1、问题原因解析
最近在做一个项目的时候需要用到在列表框的前面加上复选框,然后点击提交按钮的时候再根据复选框的勾选情况来判定是否需要选用该行的数据,简单的预期效果如下图所示:
但是我在做这个功能的时候发现一个问题,就是我用如下导入的模块CheckListCtrlMixin,复选框完全无法点击,就是最后做出来复选框点击不了,,,当时郁闷的不行???
from wx.lib.mixins.listctrl import CheckListCtrlMixin
因为网上很多方法都是使用CheckListCtrlMixin模块来重构ListCtrl类,以实现上面图片的效果。
原因及解决办法
后面我还是在Google搜索在github上面找到原因,是wxpython版本问题,根据资料显示,在wxpython4.1.0以前的版本,都是通过CheckListCtrlMixin来重构ListCtrl类,来实现复选框的功能,而在4.1.0及以后版本,开发者已经在原始的ListCtrl类里面添加了复选框的功能,只是默认没有激活,需要调用函数EnableCheckBoxes来进行激活,页面才会显示复选框。但是我当时不知道这个事情,我查看了我当时的wxpython版本,正好是4.1.0,然后我还用CheckListCtrlMixin来重构,所以导致最后重构里面的复选框功能冲突,以至于界面可以显示,但是怎么点击都点击不动的情况。
以上就是复选框点击不了的原因,接下来我记录一下在wxpython4.1.0以前的版本和4.1.0以后的版本怎么使用ListCtrl复选框做了个简单的例子,并附上源码,希望对没遇到这种情况的朋友有帮助,提供一定的参考。
2、wxpython版本小于4.1.0的ListCtrl使用复选框
如前文所说,这种情况就需要重构ListCtrl组件,然后才能使用复选框功能,源码如下所示:
"""
针对wxpython4.0.7及以下版本,4.1.0以上版本在wx.ListCtrl里面已经集成了check复选框
"""
import wx
from wx.lib.mixins.listctrl import CheckListCtrlMixin
listdata = [("成都","天府国际机场"),("重庆","江北机场"),("广州","白云机场"),("杭州","萧山机场"),("上海","虹桥机场")]
#重构ListCtrl组件,得到新的组件CheckListCtrl,该组件既有ListCtrl的所有功能,又有复选框check的功能
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin):
def __init__(self, parent):
wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style=wx.LC_REPORT |
wx.SUNKEN_BORDER)
CheckListCtrlMixin.__init__(self)
#例子Frame界面
class Example(wx.Frame):
def __init__(self, parent=None, id=-1):
wx.Frame.__init__(self, parent, id, pos=wx.DefaultPosition)
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
leftPanel = wx.Panel(panel)
rightPanel = wx.Panel(panel)
self.log = wx.TextCtrl(rightPanel, style=wx.TE_MULTILINE|wx.TE_READONLY)
self.list = CheckListCtrl(rightPanel)
self.list.InsertColumn(0, '城市', width=190)
self.list.InsertColumn(1, '机场', width=200)
num = 0
for i in listdata:
index = self.list.InsertItem(num, i[0])
self.list.SetItem(index, 1, i[1])
num += 1
vbox2 = wx.BoxSizer(wx.VERTICAL)
selBtn = wx.Button(leftPanel, label='选择所有')
desBtn = wx.Button(leftPanel, label='取消所有')
appBtn = wx.Button(leftPanel, label='打印选择')
self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=selBtn.GetId())
self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, id=desBtn.GetId())
self.Bind(wx.EVT_BUTTON, self.OnApply, id=appBtn.GetId())
vbox2.Add(selBtn, 0, wx.TOP|wx.BOTTOM, 5)
vbox2.Add(desBtn, 0, wx.BOTTOM, 5)
vbox2.Add(appBtn)
leftPanel.SetSizer(vbox2)
vbox.Add(self.list, 4, wx.EXPAND | wx.TOP, 3)
vbox.Add((-1, 10))
vbox.Add(self.log, 2, wx.EXPAND)
vbox.Add((-1, 10))
rightPanel.SetSizer(vbox)
hbox.Add(leftPanel, 0, wx.EXPAND | wx.RIGHT, 5)
hbox.Add(rightPanel, 1, wx.EXPAND)
hbox.Add((3, -1))
panel.SetSizer(hbox)
self.SetTitle('ListCtrlCheckDemo')
self.SetSize(500,400)
self.Centre()
def OnSelectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i)
def OnDeselectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i, False)
def OnApply(self, event):
num = self.list.GetItemCount()
for i in range(num):
if i == 0: self.log.Clear()
if self.list.IsChecked(i):
self.log.AppendText(self.list.GetItemText(i) + '-' + self.list.GetItemText(i,1) + "\n")
def main():
app = wx.App()
ex = Example(None)
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
运行界面如下所示,选择复选框,在下面的框中弹出选择的行数据
3、wxpython版本大于等于4.1.0的ListCtrl使用复选框
针对大于等于4.1.0版本的wx,就没有那么麻烦了,不需要重构,只需要调用一个EnableCheckBoxes函数就可以实现复选框的功能,源代码如下所示:
"""
针对wxpython4.0.7及以下版本,4.1.0以上版本在wx.ListCtrl里面已经集成了check复选框
"""
import wx
listdata = [("成都","天府国际机场"),("重庆","江北机场"),("广州","白云机场"),("杭州","萧山机场"),("上海","虹桥机场")]
class Example(wx.Frame):
def __init__(self, parent=None, id=-1):
wx.Frame.__init__(self, parent, id, pos=wx.DefaultPosition)
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
leftPanel = wx.Panel(panel)
rightPanel = wx.Panel(panel)
self.log = wx.TextCtrl(rightPanel, style=wx.TE_MULTILINE|wx.TE_READONLY)
self.list = wx.ListCtrl(rightPanel,style=wx.LC_REPORT)
self.list.EnableCheckBoxes() #使用ListCtrl的复选框功能,需要调用此函数来激活,默认是没有此功能的
self.list.InsertColumn(0, '城市', width=190)
self.list.InsertColumn(1, '机场', width=200)
for i in listdata:
index = self.list.InsertStringItem(0, i[0])
self.list.SetStringItem(index, 1, i[1])
vbox2 = wx.BoxSizer(wx.VERTICAL)
selBtn = wx.Button(leftPanel, label='选择所有')
desBtn = wx.Button(leftPanel, label='取消所有')
appBtn = wx.Button(leftPanel, label='打印选择')
self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=selBtn.GetId())
self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, id=desBtn.GetId())
self.Bind(wx.EVT_BUTTON, self.OnApply, id=appBtn.GetId())
vbox2.Add(selBtn, 0, wx.TOP|wx.BOTTOM, 5)
vbox2.Add(desBtn, 0, wx.BOTTOM, 5)
vbox2.Add(appBtn)
leftPanel.SetSizer(vbox2)
vbox.Add(self.list, 4, wx.EXPAND | wx.TOP, 3)
vbox.Add((-1, 10))
vbox.Add(self.log, 2, wx.EXPAND)
vbox.Add((-1, 10))
rightPanel.SetSizer(vbox)
hbox.Add(leftPanel, 0, wx.EXPAND | wx.RIGHT, 5)
hbox.Add(rightPanel, 1, wx.EXPAND)
hbox.Add((3, -1))
panel.SetSizer(hbox)
self.SetTitle('ListCtrlCheckDemo')
self.SetSize(500,400)
self.Centre()
def OnSelectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i,True)
def OnDeselectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i, False)
def OnApply(self, event):
num = self.list.GetItemCount()
for i in range(num):
if i == 0: self.log.Clear()
if self.list.IsItemChecked(i):
self.log.AppendText(self.list.GetItemText(i) + '-' + self.list.GetItemText(i,1) + "\n")
def main():
app = wx.App()
ex = Example(None)
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
运行的界面和上面低于4.1.0版本的界面一样,只是代码里面部分函数有些修改。
备注:下面的链接是在github上面找到的问题说明,里面的大概意思就是前面说的,4.1.0之前的版本的复选框功能需要用CheckListCtrlMixin来重构ListCtrl,而4.1.0以及之后的版本,功能被移到ListCtrl组件里面去了,不需要重构了,只是说目前新版本的ListCtrl在增加复选框的背景图上面还没有实现,如果想做复选框的背景图,目前还是只能使用旧版本的ListCtrl,或者自己重写ListCtrl。