virtual wx.ListCtrl在SetItemCount上引发wxAssertionError

时间:2017-07-23 17:33:27

标签: python wxpython virtual listctrl

我想创建一个自定义ListCtrl“MyListCtrlCrafting”,它从另一个名为“DBInterface”的类中提取数据(实际上它不是真正的数据库,而是一个复杂的python字典)。有关于如何做到这一点的教程,我遵循“Python in Action”。要点是:从ListCtrl继承并将样式参数设置为wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VIRTUAL,在 init ()期间调用SetItemCount()并覆盖某些方法。

为了测试它是如何工作的,我制作了一个小应用程序,它只包含一个(主)框架,虚拟ListCtrl和DBInterface的基本版本。在这种情况下,一切都很好。但是当我连接真实应用程序的类时,我得到一个Traceback:

Traceback (most recent call last):
  File "DesktopCrafter.py", line 198, in <module>
    controller = AppCtrl()
  File "DesktopCrafter.py", line 186, in __init__
    self.frame = GUI.MainWindow(back_end=self.back_end, crafting_controller=self.crafting_controller, parent=None, title='Desktop Crafter')
...
    self.view = MyListCtrlCrafting(name='crafting-hand', back_end=self.db, crafting_controller=self.cc, parent=self, id=wx.ID_ANY)
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 107, in __init__
    self.bindData()
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 121, in bindData
    self.SetItemCount(count)
wx._core.wxAssertionError: C++ assertion "m_count == ListView_GetItemCount(GetHwnd())" failed at ..\..\src\msw\listctrl.cpp(3120) in wxListCtrl::SetItemCount(): m_count should match ListView_GetItemCount

与简单的App相比,virtualListCtrl现在已经深度嵌套了。这个错误只能由这个嵌套中的错误连接或DBInterface和ListCtrl之间产生吗?或者我是否必须了解如何计算m_count,以解决此错误?如果是这样,我怎么能读取_core文件?我已经阅读了core.py文件中的ListCtrl,但它不包含相关部分。

我对此追溯的问题是我不明白为什么在SetItemCount()期间引发它。这个方法应该像定义一样,因为它处理列表的行,它应该接受正整数,可能是0,也可能是标准的-1。我插入5,所以这不是真正的问题(?)

非常感谢任何帮助或提示!

完整的追溯:

Traceback (most recent call last):
  File "DesktopCrafter.py", line 198, in <module>
    controller = AppCtrl()
  File "DesktopCrafter.py", line 186, in __init__
    self.frame = GUI.MainWindow(back_end=self.back_end, crafting_controller=self.crafting_controller, parent=None, title='Desktop Crafter')
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 285, in __init__
    self.InitUI()
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 299, in InitUI
    self.panel = MainPanel(back_end=self.db, crafting_controller=self.cc)
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 251, in __init__
    self.splitter = MySplitter(back_end=back_end, crafting_controller=crafting_controller)
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 229, in __init__
    self.l_frame = LPanel(back_end=back_end, crafting_controller=crafting_controller)
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 188, in __init__
    self.panel = CraftingPanel(back_end=back_end, crafting_controller=crafting_controller, *args, **kwargs)
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 154, in __init__
    self.view = MyListCtrlCrafting(name='crafting-hand', back_end=self.db, crafting_controller=self.cc, parent=self, id=wx.ID_ANY)
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 107, in __init__
    self.bindData()
  File "d:\workspace-fun\DesktopCrafter\dc\util\DCUI.py", line 121, in bindData
    self.SetItemCount(count)
wx._core.wxAssertionError: C++ assertion "m_count == ListView_GetItemCount(GetHwnd())" failed at ..\..\src\msw\listctrl.cpp(3120) in wxListCtrl::SetItemCount(): m_count should match ListView_GetItemCount

虚拟ListCtrl(两个打印都给我预期的结果):

 class MyListCtrlCrafting(wx.ListCtrl):


    def __init__(self, name, back_end, crafting_controller, *args, **kwargs):

        wx.ListCtrl.__init__(self, style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VIRTUAL, *args, **kwargs)

        self.name = name
        self.db = back_end 
        self.cc = crafting_controller
        #print(self.db.retrieveValue(['player', self.name]))
        self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems)

        self.bindData()

        self.InsertColumn(0, "Slot")
        self.InsertColumn(1, "Item")
        self.InsertColumn(2, "Amount")      

        print("initialized MyListCtrl")


    def bindData(self):

        data = self.db.retrieveValue(['player', self.name])
        count = len(data)
        #print(count)
        self.itemDataMap = {i: ('slot'+str(i+1), data[str(i)]['item'], data[str(i)]['amount']) for i in range(count)}
        self.SetItemCount(count)

    def DoCacheItems(self, e):

        self.db.updateCache(e.GetCacheFrom(), e.GetCacheTo())           

    def OnGetItemText(self, row_no, col_no):

        data = self.db.retrieveValue(['player', self.name, str(row_no)])    
        return data[col_no]

    def OnGetItemAttr(self, item): return None
    def OnGetItemImage(self, item): return -1

    def OnBackEndUpdated(self):

        self.bindData()
        self.RefreshItems(0, self.GetItemCount())

DBInterface:

 class DBInterface(dict):


    def __init__(self, path, *args, **kwargs):        

        super(DBInterface, self).__init__(*args, **kwargs)
        self.path = path


    def load(self):

        with open(self.path, 'r') as f:
            try:
                self.update(json.loads(f.read()))
            except Exception as e:
                print(e); print(self.path)


    def save(self):

        self.path.ensure()
        with open(self.path, 'w') as f:
            f.write(json.dumps(self))


    def retrieveValue(self, path):

        a = self
        for i in range(len(path)):
            a = a[path[i]]
        return a

1 个答案:

答案 0 :(得分:0)

断言基本上是一个检查,以确保操作(设置计数)成功,通过询问本机控件它有多少项(应该由先前的API调用设置。这看起来真的是真的不应该失败,虽然显然是。也许有些东西正在以某种方式重置或改变原生控制?是否涉及任何线程?

我没有给你一个可靠的答案,但作为建议我建议采取有效的小样本并逐步构建,直到它与窗口层次结构和环境以及该部分的基本特征相匹配。完整的应用程序,它被打破。最终它应该以同样的方式开始失败,然后你就会知道触发它的变化是什么,并且可以更仔细地看待它。