Как синхронизировать данные между редактируемым ListCtrl и источником данных? - PullRequest
1 голос
/ 05 февраля 2012

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

Для таблицы я использую объект, производный от ListCtrl и, потому что я хочу чтобы иметь возможность редактировать данные на месте, я также наследую Класс TextEditMixin:

class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin):
    def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition,
             size=wx.DefaultSize, style=0):
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
    listmix.TextEditMixin.__init__(self)

Я хочу, чтобы мои внутренние данные были отделены от их отображения, поэтому мой wx.Frame -приобретенный объект имеет объект источника данных, из которого он читает данные для заполнения ListCtrl.

    self.list = EditableListCtrl(panel, style=wx.LC_REPORT)
    self.list.InsertColumn(0, 'A', width=140)
    self.list.InsertColumn(1, 'B', width=130)

    for i in range(0, self.db.getNumRecords()):
        item = self.db.getRecord(i)
        index = self.list.InsertStringItem(sys.maxint, str(item[0]))
        self.list.SetStringItem(index, 1, str(item[1]))

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

Есть ли стандартный способ сделать это?

Я попытался привязаться к событию EVT_LIST_ITEM_DESELECTED, но оно срабатывает до того, как функция TextEditMixin изменит данные в ListCtrl - данные, полученные из ListCtrl с помощью обратного вызова функция старых данных.

Ответы [ 4 ]

3 голосов
/ 12 апреля 2015

Существует способ обойти эту очевидную аномалию, когда вы редактируете данные, и все же кажется, что вы не можете получить к ним доступ, например, для обновления базы данных.Вам необходимо привязать событие к listctrl и затем получить доступ к event.GetLabel, а не listCtrl.GetText
, например:

self.listCtrl.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnMixUpdate)

, а затем:

def OnMixUpdate(self, event):
    # Set the changed data via the event.GetLabel not listCtrl.GetText which remains unchanged until we change it
    rowid = self.listCtrl.GetFocusedItem ()
    new_data = event.GetLabel ()
    colid = event.GetColumn ()
    self.listCtrl.SetStringItem(rowid,colid,new_data,)
    #Update a textctrl on screen
    self.SetData()
    #Update database
    self.OnUpdate(None)
    event.Skip()

. Выше используетсянормальный listctrl () Эта конкретная проблема сводила меня с ума больше, чем за день до того, как я придумал это решение.Я подозреваю, что есть и другие, но я не смог их найти.На самом деле, исходя из моих поисков в Интернете, похоже, что с этой проблемой сталкивалось не несколько человек.

Вы можете заменить строку
rowid = self.listCtrl.GetFocusedItem ()
с
rowid = event.GetIndex () и получить тот же результат, который, возможно, читается лучше

3 голосов
/ 08 февраля 2012

Существует два способа синхронизации данных.

1. Использовать Virtual ListCtrl

При использовании Virtual ListCtrl вам не нужно добавлять данные вручную. Это извлекает данные из вашего источника данных.

Чтобы сделать ListCtrl виртуальным, инициализируйте ListCtrl с помощью wx.LC_VIRTUAL флаг стиля.

Для того, чтобы Virtual ListCtrl извлекал данные, вам необходимо переопределить следующие функции (очевидно, вам нужно сначала создать подкласс ListCtrl):

OnGetItemText(self, item, column)
OnGetItemAttr(self, item)
OnGetItemImage(self, item)

Первый из них обрабатывает строковые данные. Я не использовал другой два. (Если вы их не используете, просто верните None и -1 соответственно.)

Вам также нужно позвонить SetItemCount(item_count), чтобы сообщить ListCtrl сколько записей для извлечения.

Чтобы обновить источник данных, когда пользователь изменяет ячейку, необходимо агрегат SetVirtualData(self, row, col, text).

См. Презентацию "Усовершенствованные гайки и болты wxPython" Робина Данна для получения дополнительной информации.

2. Используйте обычный ListCtrl

Подкласс ListCtrl и переопределить функцию SetStringItem(self, row, col, text). В вашей новой реализации обновите ваш источник данных. не не забудьте также назвать базовый класс SetStringItem()! Иначе, внешний вид ListCtrl не изменится.

Virtual ListCtrl - немного больше работы, но рекомендуется, потому что у вас больше нет двух копий данных.

(Спасибо Майку Дрисколлу за то, что он указал мне правильное направление, чтобы найти эту информацию!)

1 голос
/ 19 февраля 2013

Событие, которое вы ищете, wx.EVT_LIST_END_LABEL_EDIT, я думаю.

1 голос
/ 06 февраля 2012

Я не понимаю. Как у вас есть две копии данных? Один в базе данных и один на дисплее? Это всегда будет так. Когда дело доходит до чего-то подобного, я думаю, что обычный метод, который я видел рекламируемым, заключается в использовании Virtual ListCtrl (см. Демонстрацию wxPython).

Вы также можете посмотреть, как я это сделал с MediaLocker:

http://www.blog.pythonlibrary.org/2011/12/09/ann-medialocker-%E2%80%93-a-wxpython-app-to-track-your-media/

Или в моем оригинальном приложении, которое послужило основой для MediaLocker:

http://www.blog.pythonlibrary.org/2011/11/10/wxpython-and-sqlalchemy-an-intro-to-mvc-and-crud/

Я использую ObjectListView вместо ListCtrl, так как мне легче его использовать.

...