我使用LC_VIRTUAL遇到了wx.ListCtrl的问题,无法找到解决问题的正确方法。
问题是如果OnGetItemText()花费的时间太长而无法返回结果,控件的内容会闪烁。
到目前为止我尝试过的解决方案:
到目前为止,我提出的唯一解决方案是在调用Refresh()之前缓存新数据。但是,在某些情况下我可能需要显示100,000条或更多记录,因此提前缓存它们将无法正常工作。
以下是我构建的示例,用于演示此问题,但您可能需要根据CPU速度调整计数:
from __future__ import print_function, unicode_literals
import wx
class MyListCtrl ( wx.ListCtrl ):
def OnGetItemText ( self, item, column ):
ar = []
for i in range ( 200000 ):
ar.append ( i )
return '{}'.format ( len ( ar ) )
class MyFrame ( wx.Frame ):
lc = None
timer = None
def __init__ ( self, *args, **kwargs ):
super ( MyFrame, self ).__init__ ( *args, **kwargs )
self.timer = wx.Timer ( self )
self.lc = MyListCtrl ( self, style=wx.LC_VIRTUAL|wx.LC_REPORT )
self.lc.InsertColumn ( 0, 'Count1', width=75 )
self.lc.InsertColumn ( 1, 'Count2', width=75 )
self.lc.InsertColumn ( 2, 'Count3', width=75 )
self.lc.InsertColumn ( 3, 'Count4', width=75 )
self.lc.SetItemCount ( 1 )
self.Bind ( wx.EVT_TIMER, self.on_timer, self.timer )
self.Bind ( wx.EVT_CLOSE, self.on_close )
self.timer.Start ( 1000 )
def on_timer ( self, event ):
self.lc.Refresh()
def on_close ( self, event ):
self.timer.Stop()
event.Skip()
if __name__=='__main__':
app = wx.App ( False )
frame = MyFrame ( None )
frame.Show()
app.MainLoop()
我在两种工作环境中都遇到了问题:
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> wx.version()
'3.0.2.0 msw (classic)'
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:01:18) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> wx.version()
'3.0.3.dev2680+55dda48 msw (phoenix)'
答案 0 :(得分:0)
如果您在面板上绘制所有内容并在面板上设置双重缓冲,则会消除闪烁
glBufferData
通常不需要Freeze()和Thaw(),但在这种情况下,lc的行为有点奇怪。
答案 1 :(得分:0)
我在另一个项目上遇到了同样的问题,我终于提出了一个可行的解决方案。回顾过去,我的解决方案正是Mike Driscoll上面的评论所暗示的。我会在这里提供一些更详细的信息,以防有人帮忙。
技巧是ListCtrl的GetTopItem()和GetCountPerPage()方法。使用这两个函数,您可以计算页面刷新时可见的索引范围。这些是准备刷新页面时需要缓存的唯一索引。
以下是我如何实施它的简化示例。
get_row_count()只是从表中选择“select count(*)”
如果光标位于右侧偏移处,get_row()将返回光标中的下一条记录,否则它会执行一个新查询以将光标重新定位在正确的位置。根据我的经验,ListCtrl按顺序刷新项目,因此效果非常好。
python
def on_list_update ( self, event ):
self.on_begin_update() # notify subclasses that a refresh is coming
count = self.get_row_count() # how many records will be visible?
top = self.GetTopItem()
bottom = min ( top + self.GetCountPerPage(), count )
new_item_cache = {}
for item in range ( top, bottom ):
new_item_cache[item] = self.get_row ( item )
self.item_cache = new_item_cache
if count != self.GetItemCount():
self.SetItemCount ( count )
else:
self.RefreshItems ( 0, count-1 )
上述模式通常会导致在刷新开始之前只有2个sql查询被发送到数据库服务器,并且消除了闪烁。
重要的是要注意,如果将数据用于其他事件,则要将项目缓存存储在临时变量中,直到重建为止,否则您将遇到缓存不可用的情况,因为正在进行刷新