繁体   English   中英

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

[英]How do I synchronize data between an editable ListCtrl and a data source?

我正在尝试构建一个包含链接到图形的数据表的原型应用程序,该表将在表旁边显示并随着数据的变化而更新。

对于表,我使用的是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检索的数据是旧数据。

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

有两种同步数据的方法。

1.使用虚拟ListCtrl

使用虚拟ListCtrl时,不必手动添加数据。 它从数据源中提取数据。

要使ListCtrl虚拟,请使用wx.LC_VIRTUAL样式标志初始化ListCtrl。

为了使Virtual ListCtrl能够提取数据,您需要重写以下函数(显然,您需要首先对ListCtrl进行子类化):

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

其中第一个处理字符串数据。 我没有用过另外两个。 (如果不使用它们,则分别返回None-1 。)

您还需要调用SetItemCount(item_count)来告诉ListCtrl要检索多少条记录。

要在用户修改单元格时更新数据源,您需要实现SetVirtualData(self, row, col, text)

有关更多信息,请参见Robin Dunn的演示文稿“ Advanced wxPython Nuts and Bolts”

2.使用常规的ListCtrl

子类ListCtrl并重写功能SetStringItem(self, row, col, text) 在新的实现中,更新数据源。 但是不要忘记也调用基类SetStringItem() 否则,ListCtrl外观将不会更改。

Virtual ListCtrl的工作量还多一些,但建议您这样做,因为您将不再获得两个数据副本。

(感谢Mike Driscoll为我指出正确的方向以找到此信息!)

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

我不明白 您如何获得数据的两个副本? 一个在数据库中,一个在显示中? 情况总是如此。 当涉及到这样的事情时,我认为我看到的广告宣传的通常方法是使用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,因为我发现它更易于使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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