0

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

为了测试它是如何工作的,我制作了一个小应用程序,它只包含一个(主)框架、虚拟 ListCtrl 和一个基本版本的 DBInterface。在此设置中一切正常。但是当我连接真实App的类时,我得到了一个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())

数据库接口:

 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
4

1 回答 1

0

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

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

于 2017-07-24T01:56:32.253 回答