如何在可编辑的ListCtrl和数据源之间同步数据?

时间:2012-02-05 11:49:46

标签: wxpython wxwidgets

我正在尝试构建一个由表组成的原型应用程序 链接到图表的数据,将与表格一起显示 并随着数据的变化而更新。

对于表我正在使用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 个答案:

答案 0 :(得分:3)

有两种方法可以同步数据。

<强> 1。使用虚拟列表控制

使用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)

有关详细信息,请参阅演示文稿"Advanced wxPython Nuts and Bolts" by Robin Dunn

<强> 2。使用常规ListCtrl

Subclass ListCtrl并覆盖函数SetStringItem(self, row, col, text)。在新的实施中,更新数据源。别 忘了也叫基类SetStringItem()!除此以外, ListCtrl外观不会改变。

Virtual ListCtrl有点多功,但推荐使用,因为你不再有两份数据副本。

(感谢Mike Driscoll指出我正确的方向找到这些信息!)

答案 1 :(得分:3)

有一种方法可以解决这种明显的异常现象,您可以在其中编辑数据但看起来您无法访问它,例如执行数据库更新。 您需要将事件绑定到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() 得到相同的结果,也许读得更好

答案 2 :(得分:1)

我不明白。你如何拥有两份数据?一个在数据库中,一个在显示?情况总是如此。当谈到这样的事情时,我认为我看到的通常方法是使用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,因为我发现它更容易使用。

答案 3 :(得分:1)

我认为您正在寻找的事件是wx.EVT_LIST_END_LABEL_EDIT