Python 如何正确更改DataViewModel的内容
wxPython最近让我很头疼,所以我不得不再次问你们:) 我的设置Python 如何正确更改DataViewModel的内容,python,wxpython,wxwidgets,Python,Wxpython,Wxwidgets,wxPython最近让我很头疼,所以我不得不再次问你们:) 我的设置 视窗7 可移植Python v 2.7.6.1() wxPython 3.0.2.0() 给出的代码是我实际应用程序的一个非常精简的版本。实际上,我有一个大模型,它以不同的方式显示在不同的控件中。 因此,我有一个模型,即代码示例中的modelRoot,从中我为不同的DataViewCtrl构建了不同的DataViewModels(MyDvcModel)。在代码示例中,我只有一个DataViewModel和一个DataVie
- 视窗7
- 可移植Python v 2.7.6.1()
- wxPython 3.0.2.0()
modelRoot
,从中我为不同的DataViewCtrl构建了不同的DataViewModels(MyDvcModel
)。在代码示例中,我只有一个DataViewModel和一个DataViewCtrl,因为它足以显示我的问题。
我试图紧跟中的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都通过它进行更新。不幸的是,我必须在每个模型上调用itemsadded
,这是一个相当大的痛苦(因为我必须在删除、编辑和移动项目时执行相同的操作)。
另外,我不知道新添加对象的项目ID,因为每个DataViewModel中的项目ID都不同。因此,我使用pub向所有DataViewModels发送一条消息,然后这些DataViewModels搜索新对象,并分别调用itemsadded
。
由于这不能正常工作,我试图直接调用itemsadded
,这也不起作用。
通过更改变量
变量的值,可以在两种实现之间切换。最终目标是让变体'viaMessage'
工作
问题
以下是如何重现这种奇怪行为的描述:
- 编辑:好吧,事情变得更奇怪了:
我编辑了代码并实现了一个附加的删除按钮。当我重复所有步骤直到第二步。然后删除所有添加的子项,子项1和2突然神奇地再次出现!(在添加2个子项后向左,然后展开根| |在删除两个添加的子项并再次展开根后向右)
- 我试图在谷歌上搜索“wxwidgets dataviewmodel itemadded collapsed”,但结果不是我想要的
- 我有一个想法,到目前为止我还没有尝试过,因为这只是一个解决办法:在程序启动时,我可以以编程方式展开和折叠所有子树。但是,我希望避免这种变通方法
- 我试图调试它,但看不到任何可疑的东西
- 我检查了原始的wxWidgets代码,但没有完全掌握它
- 怎么了?为什么它不能按预期工作?这是wxPython错误还是我的代码中的错误?
- 我如何修复它?
- 我有没有比我如何实现目标更好的方法
- 您是否看到我的代码中有任何其他缺陷或缺点?(除了这是一个精简版,我尽量避免使用样板文件,如
和MVC设计(至少缺少C)等。)if uuuuu name\uuuuuu=='uuu main\uuuuu':main()
- 为什么我不能直接使用
作为消息处理程序,但我必须通过MyDvcModel.Update
使用间接方式?如果我使用onimadded()
,我会在应用程序实际启动之前得到一个异常MyDvcModel.Update
(TypeError:在方法“DataViewItem\uuuuuuuu cmp\uuuuuuuuu”中,应为“wxDataViewItem*”类型的参数2)
非常感谢您的帮助。您的
PyDataViewModel
代码比应用程序所需的复杂。不必更新DVC模型,只需将其清除即可(使模型本身了解数据是如何变化的,并根据数据向DVC发送消息)。这对数百个项目没有明显的延迟(我没有用几千个项目进行测试)
按以下步骤进行:
# remove subscription, no longer needed
# pub.subscribe(self.OnItemAdded, 'ITEM_ADDED')
# remove OnItemAdded and Update
#-------------------- CUSTOM FUNCTIONS -----------------------------
简化为:
def DeleteLastItemFromRoot(*ignoreEvent):
global childNum
if modelRoot.children != []:
obj = modelRoot.children[-1] #select last item
modelRoot.RemoveChild(obj)
# no longer required, handled my model.Cleared()
# model.ItemDeleted(model.ObjectToItem(modelRoot), model.ObjectToItem(obj))
# Forcing a synchronisation python model/PyDataViewModel/DVC
model.Cleared()
def AddItemToRoot(*ignoreEvent):
global childNum
newObject = DvcTreeItem('child' + str(childNum))
modelRoot.AddChild(newObject)
childNum += 1
# syncing
model.Cleared()
您的
PyDataViewModel
代码比应用程序所需的复杂。而不是更新