简体   繁体   中英

Python traitsui save file dialogue - overwriting

what is the right way to implement file-saving dialogue with the traitsui package from Enthought? At the moment, I have the actual saving function watching for changes in the trait filename_out (ie File trait). Unsurprisingly, this does nothing when the user wants to save to the same file repeatedly, overwriting it each time. How do I make it save the file each time the user confirms overwriting in the FileEditor dialogue?

A small piece of not-working code:

from traits.api import File, HasTraits
from traitsui.api import FileEditor, View, Item
import numpy

class ArrayToBeSaved(HasTraits):
    filename_out = File

    traits_view = View(Item('filename_out', editor = FileEditor(dialog_style='save')))

    def __init__(self):
        self.my_array = numpy.ones(3)

    #This is NOT the right way
    def _filename_out_changed(self):
        numpy.save(self.filename_out, self.my_array)
        self.my_array = numpy.zeros(3)

atbs = ArrayToBeSaved()

atbs.configure_traits()

After selecting the file location, the array of ones is saved. After calling the file dialogue one more time, selecting the same file, the user is asked to confirm overwriting. However, nothing happens, as the filename_out was not changed.

EDIT: I would like to make clear, that the FileEditor does ask to confirm overwriting, but does not save the file.

Note that you can use pyface.file_dialog which automatically has the "do you want to overwrite this file" behavior. If you don't actually need your filename to be a trait, do this instead, it is much simpler.

If there is a good reason for the filename to be a trait, you need a continuation to be resumed after checking the user's response.

There are many possible ways to do it, but here is the way I like to do it. Note that I did not test this code.

import os
from traits.api import File, HasTraits, Function, Bool, Event
from traitsui.api import FileEditor, View, Item, Handler, OKCancelButtons, Label
import numpy

class CheckOverwriteWindow(Handler):

  finished = Bool
  notify = Event

  def init_info(self, info):
    self.finished = False

  def closed(self, info, is_ok):
    self.finished = is_ok
    self.notify = True

  view = View(
    Label('Really overwrite?'),
    buttons = OKCancelButtons
  )

class ArrayToBeSaved(HasTraits):
    filename_out = File
    _save_continuation = Function
    _check_overwrite_window = Instance(CheckOverwriteWindow,())

    traits_view = View(Item('filename_out', editor = FileEditor(dialog_style='save')))

    def __init__(self):
        self.my_array = numpy.ones(3)

    def _filename_out_changed(self):
        def save_continuation():
            numpy.save(self.filename_out, self.my_array)
            self.my_array = numpy.zeros(3)
        if not os.path.exists(self.filename_out):
            save_continuation()
        else:
            self._save_continuation = save_continuation
            self._check_overwrite_window.edit_traits()

    @on_trait_change('_check_overwrite_window:notify')
    def handle_overwrite(self):
        if self._check_overwrite_window.finished:
            self._save_continuation()

atbs = ArrayToBeSaved()

atbs.configure_traits()

Thanks to aestrivex I can present a complete answer. The pyface.file_dilaog really does the job. Since it took me some time to figure out how to use it, I decided to post a full working example.

This works also for re-opening the same file, only chage the attribute of FileDialog to action = 'open' (eg if you accidentally edit the values of something and wish to return to the sate that is saved on your disk - a situation that also fails if you rely on watching for change of a File trait.)

from traits.api import HasTraits, Button
from traitsui.api import View, Item
import numpy

##you may need to uncoment these 2 lines to prevent 
##ImportErrors due to missing backends
#from traits.etsconfig.api import ETSConfig
#ETSConfig.toolkit = 'qt4' # or 'wx'    

from pyface.api import FileDialog, OK


class ArrayToBeSaved(HasTraits):
    save_as = Button('save as')

    traits_view = View(Item('save_as'))

    def __init__(self):
        self.my_array = numpy.ones(3)

    def _save_as_changed(self):
        dlg = FileDialog(action='save as')
        if dlg.open() == OK:
            numpy.save(dlg.path, self.my_array)
            self.my_array = numpy.zeros(3)

atbs = ArrayToBeSaved()

atbs.configure_traits()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM