wxpython dataview_如何正确更改DataViewMod的内容

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'工作。在

问题

以下是如何重现这种奇怪行为的描述:启动应用程序。您应该只看到折叠的根项(旁边有“+”)。不用触摸树状视图,只需单击“添加子项”按钮几次。在

现在展开根项。您将看到其中有几个子级(与您单击的频率相同)。然而,在程序开始时,添加了两个子级,现在,缺少。这是不可取的,我认为这是错误的行为。

编辑:好吧,事情变得更奇怪了:

我编辑了代码并实现了一个额外的删除按钮。当我重复到第二步。然后删除所有添加的孩子,孩子1和2突然神奇地再次出现!(添加2个子项后向左,然后展开根| |右删除添加的两个子项并再次展开根)

无论如何,现在请重新启动应用程序(关闭窗口并再次运行脚本)。现在展开根项并单击“添加子项”。哇,突然间它起作用了。

好的,让我们尝试另一个:重新启动应用程序。再次展开和折叠根项。现在点击“添加孩子”几次。现在再次展开根项。在

又一次,它似乎奏效了。所有的子元素,开始时添加的以及通过按钮添加的都在那里。在

所以显然只有在展开父项之前添加子项时才会出现错误。

这是什么魔法?在

我的印象是,我想实现的并不是什么特别的事情,我想知道错误在哪里,我无法通过谷歌找到这个问题,所以我不得不假设错误在我这边,但我找不到。在

只是为了证明这个问题的标题:我在删除一个项目时也有类似的问题。因此,问题更一般地说是如何正确地更改DataViewModel的内容(例如,删除、添加和更改项的值),而不仅仅是添加项。在

我的尝试我试图在google上搜索"wxwidgets dataviewmodel itemadded collapsed",但结果不是我想要的。在

我有个主意,whi到目前为止,我还没有尝试过,因为这只是一种解决方法:在程序启动时,我可以编程方式展开和折叠所有子树。不过,我想避免这种变通办法。在

我试着调试它,但看不到任何可疑的东西。在

我检查了wxWidgets的原始代码,但是没有完全理解。在

我的问题怎么了?为什么它不能如愿工作?这是wxPython错误还是代码中的错误?

我怎样才能修好它?

侧面任务我有更好的方法来实现我的目标,而不是我如何实现它?在

你看到我的代码中还有其他的缺陷吗?(除了它是一个精简版,我尽量避免使用样板文件if __name__ == '__main__': main()和MVC设计(至少缺少C)等。)

为什么我不能直接使用MyDvcModel.Update作为消息处理程序,而必须通过OnItemAdded()使用间接寻址?如果我使用MyDvcModel.Update,那么在应用程序实际启动(TypeError: in method 'DataViewItem___cmp__', expected argument 2 of type 'wxDataViewItem *')之前,我会得到一个异常。在

如果这些问题也能得到回答,那就太好了,但我接受你的答案作为解决方案既不必要也不充分;)

感谢任何帮助。在

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值