wxPython最近让我头疼,所以我不得不再次问你们:)
给定的代码是我实际应用程序的一个非常简化的版本。实际上,我有一个大模型,在不同的控件中以不同的方式显示。
因此,我有一个模型,它是代码示例中的modelRoot
,我从中为不同的dataviewctrl构建不同的DataViewModels(MyDvcModel
)。在代码示例中,我只有一个DataViewModel和一个DataViewCtrl,因为它足以显示我的问题。
我试图靠近https://github.com/svn2github/wxPython/blob/master/trunk/demo/DVC_DataViewModel.py中的DataViewModel示例
这是我最简单的工作示例:
import wx
import wx.dataview
from wx.lib.pubsub import pub
#class for a single item
class DvcTreeItem(object):
def __init__(self, value='item'):
self.parent = None
self.children = []
self.value = value
def AddChild(self, dvcTreeItem):
self.children.append(dvcTreeItem)
dvcTreeItem.parent = self
def RemoveChild(self, dvcTreeItem):
self.children.remove(dvcTreeItem)
dvcTreeItem.parent = None
#class for the model
class MyDvcModel(wx.dataview.PyDataViewModel):
def __init__(self, root):
wx.dataview.PyDataViewModel.__init__(self)
self.root = root
pub.subscribe(self.OnItemAdded, 'ITEM_ADDED')
#-------------------- REQUIRED FUNCTIONS -----------------------------
def GetColumnCount(self):
return 1
def GetChildren(self, item, children):
if not item:
children.append(self.ObjectToItem(self.root))
return 1
else:
objct = self.ItemToObject(item)
for child in objct.children:
#print "GetChildren called. Items returned = " + str([child.value for child in objct.children])
children.append(self.ObjectToItem(child))
return len(objct.children)
def IsContainer(self, item):
if not item:
return True
else:
return (len(self.ItemToObject(item).children) != 0)
return False
def GetParent(self, item):
if not item:
return wx.dataview.NullDataViewItem
parentObj = self.ItemToObject(item).parent
if parentObj is None:
return wx.dataview.NullDataViewItem
else:
return self.ObjectToItem(parentObj)
def GetValue(self, item, col):
if not item:
return None
else:
return self.ItemToObject(item).value
#-------------------- CUSTOM FUNCTIONS -----------------------------
def OnItemAdded(self, obj):
self.Update(obj) #for some weird reason, the update function cannot be used directly as event handler for pub (?).
def Update(self, obj, currentItem=wx.dataview.DataViewItem()):
children = []
self.GetChildren(currentItem, children)
for child in children:
self.Update(obj, child) #recursively step through the tree to find the item that belongs to the added object
if self.ItemToObject(child) == obj:
self.ItemAdded(self.GetParent(child), child)
print "item " + obj.value + " was added!"
break
#class for the frame
class wxTreeAddMini(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DLIGHT))
self.myDVC = wx.dataview.DataViewCtrl(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0)
self.myButton = wx.Button(self, wx.ID_ANY, u"Add Child", wx.DefaultPosition, wx.DefaultSize, 0)
self.myDelButton = wx.Button(self, wx.ID_ANY, u"Del Child", wx.DefaultPosition, wx.DefaultSize, 0)
mySizer = wx.BoxSizer(wx.VERTICAL)
mySizer.Add(self.myDVC, 1, wx.ALL|wx.EXPAND, 5)
mySizer.Add(self.myButton, 0, wx.ALL, 5)
mySizer.Add(self.myDelButton, 0, wx.ALL, 5)
self.SetSizer(mySizer)
app = wx.App(False)
modelRoot = DvcTreeItem('root')
child1 = DvcTreeItem('child1 - the forgotten one')
child1.AddChild(DvcTreeItem('even complete subtrees'))
child1.AddChild(DvcTreeItem('disappear'))
modelRoot.AddChild(child1)
modelRoot.AddChild(DvcTreeItem('child2 - the forgotten brother'))
childNum = 3
model = MyDvcModel(modelRoot)
frame = wxTreeAddMini(None)
frame.myDVC.AssociateModel(model)
frame.myDVC.AppendTextColumn("stuff", 0, width=250, mode=wx.dataview.DATAVIEW_CELL_INERT)
frame.Show()
def DeleteLastItemFromRoot(*ignoreEvent):
global childNum
if modelRoot.children != []:
obj = modelRoot.children[-1] #select last item
modelRoot.RemoveChild(obj)
model.ItemDeleted(model.ObjectToItem(modelRoot), model.ObjectToItem(obj))
def AddItemToRoot(*ignoreEvent):
global childNum
newObject = DvcTreeItem('child' + str(childNum))
modelRoot.AddChild(newObject)
childNum += 1
VARIANT = 'callItemAdded'
if VARIANT == 'viaMessage':
wx.CallAfter(pub.sendMessage, 'ITEM_ADDED', obj=newObject)
elif VARIANT == 'callItemAdded':
model.ItemAdded(model.ObjectToItem(modelRoot), model.ObjectToItem(newObject))
frame.myButton.Bind(wx.EVT_BUTTON, AddItemToRoot)
frame.myDelButton.Bind(wx.EVT_BUTTON, DeleteLastItemFromRoot)
app.MainLoop()
我的最终目标是只更新低级模型(modelRoot
及其子代/子级),并使所有的DataViewModels都被更新。不幸的是,我必须在每个模型上调用ItemAdded
,这是一个相当大的痛苦(因为我必须对删除、编辑和移动项目执行相同的操作)。
另外,我不知道新添加对象的item ID,因为item ID在每个DataViewModel中是不同的。因此,我使用pub向所有DataViewModels发送一条消息,然后这些模型搜索新对象并分别对其自身调用ItemAdded
。
由于这没有正常工作,我试图直接调用ItemAdded
,但也不起作用。
您可以通过更改VARIANT
变量的值在两种实现之间切换。最终目标是让变体'viaMessage'
工作。在
以下是如何重现这种奇怪行为的描述:
又一次,它似乎奏效了。所有的子元素,开始时添加的以及通过按钮添加的都在那里。在
所以显然只有在展开父项之前添加子项时才会出现错误。
这是什么魔法?在
我的印象是,我想实现的并不是什么特别的事情,我想知道错误在哪里,我无法通过谷歌找到这个问题,所以我不得不假设错误在我这边,但我找不到。在
只是为了证明这个问题的标题:我在删除一个项目时也有类似的问题。因此,问题更一般地说是如何正确地更改DataViewModel的内容(例如,删除、添加和更改项的值),而不仅仅是添加项。在
"wxwidgets dataviewmodel itemadded collapsed"
,但结果不是我想要的。在if __name__ == '__main__': main()
和MVC设计(至少缺少C)等。)MyDvcModel.Update
作为消息处理程序,而必须通过OnItemAdded()
使用间接寻址?如果我使用MyDvcModel.Update
,那么在应用程序实际启动(TypeError: in method 'DataViewItem___cmp__', expected argument 2 of type 'wxDataViewItem *')
之前,我会得到一个异常。在如果这些问题也能得到回答,那就太好了,但我接受你的答案作为解决方案既不必要也不充分;)
感谢任何帮助。在
您的
PyDataViewModel
代码比应用程序所需的复杂。与Update
不同的是,它完全可以清除它(让模型自己知道数据是如何变化的,并根据它向DVC发送消息)。这项工作没有明显的延误,数百项(我没有测试数千项)。在执行以下操作:
简化为:
^{pr2}$相关问题 更多 >
编程相关推荐