Диалог сохранения файла Python traitsui — перезапись

как правильно реализовать диалог сохранения файлов с пакетом traitsui от Enthought? На данный момент у меня есть фактическая функция сохранения, отслеживающая изменения черты filename_out (т.е. черты File). Неудивительно, что это ничего не дает, когда пользователь хочет неоднократно сохранять в один и тот же файл, перезаписывая его каждый раз. Как заставить его сохранять файл каждый раз, когда пользователь подтверждает перезапись в диалоговом окне FileEditor?

Небольшой кусок нерабочего кода:

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()

После выбора местоположения файла массив единиц сохраняется. После повторного вызова файлового диалога, выбора того же файла пользователю предлагается подтвердить перезапись. Однако ничего не происходит, так как filename_out не был изменен.

РЕДАКТИРОВАТЬ: Я хотел бы пояснить, что FileEditor запрашивает подтверждение перезаписи, но не сохраняет файл.


person Jan Vorac    schedule 24.08.2015    source источник


Ответы (2)


Обратите внимание, что вы можете использовать pyface.file_dialog, который автоматически имеет поведение «вы хотите перезаписать этот файл». Если вам на самом деле не нужно, чтобы ваше имя файла было трейтом, сделайте это вместо этого, это намного проще.

Если есть веская причина для того, чтобы имя файла было трейтом, вам нужно возобновить продолжение после проверки ответа пользователя.

Есть много возможных способов сделать это, но вот способ, которым я люблю это делать. Обратите внимание, что я не тестировал этот код.

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()
person aestrivex    schedule 27.08.2015
comment
Спасибо за ответ! Я все еще что-то пропустил, хотя. После добавления импорта Instance и on_trait_change я столкнулся с такой же проблемой: двойной выбор одного и того же имени не приводит к каким-либо действиям, хотя диалоговое окно файла запрашивает подтверждение. Ваш код работает, когда вы выбираете name1.npy, затем name2.npy и снова name1.npy, но мой тоже. Это только добавляет еще один этап подтверждения. - person Jan Vorac; 28.08.2015
comment
Извините, я не правильно понял ваш вопрос, но я также не думаю, что вы очень четко изложили свою конкретную проблему. Если вы используете редактор по умолчанию для выбора файла, он не будет обновлять трейт, если файл на самом деле не изменился. Точнее, он обновит трейт, но, поскольку значение не изменится, это не приведет к срабатыванию уведомления. Вам было бы легче делать то, что вы хотите, написав оболочку вокруг pyface.FileDialog (я упоминал в начале своего ответа). Эта оболочка всегда может вернуть значение, тогда как FileEditor ничего не вызовет, если трейт не изменится. - person aestrivex; 28.08.2015

Благодаря aestrivex я могу дать полный ответ. pyface.file_dilaog действительно делает свою работу. Поскольку мне потребовалось некоторое время, чтобы понять, как его использовать, я решил опубликовать полный рабочий пример.

Это также работает для повторного открытия того же файла, только измените атрибут FileDialog на action = 'open' (например, если вы случайно редактируете значения чего-либо и хотите вернуться к состоянию, сохраненному на вашем диске - ситуация, которая также не работает, если вы полагаться на наблюдение за изменением File признака.)

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()
person Jan Vorac    schedule 31.08.2015