バーチャルリストでリスト表示を低負荷に行う(2)
2011-09-28 - 理想のユーザ・インターフェイスを求めての続き。wxPythonの話。
VListBoxのサンプルを改良して、他で使える形にもっていく。
改良のポイントを列記すると、
- リストはVListBoxで作成
- リストの前後に他のコントロールを配置
- ボタンを押したときに、リストの中の何が選ばれているかを表示
となる。
ソースコードは以下の通り。VListBoxでは、リスト(の見た目)を自分好みに作れるという点で魅力的だが、何からなにまで自分でやらないといけないので、凝ったものを作る場合には面倒。
import wx class UserListBox(wx.VListBox): def __init__(self, parent, users): super(UserListBox, self).__init__(parent) self.bmp = wx.Bitmap("system-users.png", wx.BITMAP_TYPE_PNG) self.bh = self.bmp.GetHeight() self.users = users self.SetItemCount(len(self.users)) def OnMeasureItem(self, index): return self.bh + 4 def OnDrawSeparator(self, dc, rect, index): oldpen = dc.GetPen() dc.SetPen(wx.Pen(wx.BLACK)) dc.DrawLine(rect.x, rect.y, rect.x + rect.width, rect.y) rect.Deflate(0, 2) dc.SetPen(oldpen) def OnDrawItem(self, dc, rect, index): dc.DrawBitmap(self.bmp, rect.x + 2, ((rect.height - self.bh) / 2) + rect.y) textx = rect.x + 2 + self.bh + 2 lblrect = wx.Rect(textx, rect.y, rect.width - textx, rect.height) dc.DrawLabel(self.users[index], lblrect, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL) class MyApp(wx.App): def OnInit(self): self.frame = MyFrame(None, title="Virtual List Box", size=(300,200)) self.SetTopWindow(self.frame) self.frame.Show() return True class MyFrame(wx.Frame): def __init__(self, *args, **kwargs): super(MyFrame, self).__init__(*args, **kwargs) self.panel = MyPanel(self) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.panel, 1, wx.EXPAND) self.SetSizer(sizer) class MyPanel(wx.Panel): def __init__(self, parent): super(MyPanel, self).__init__(parent) self.parent = parent users = ["Steve", "James", "Mary", "Yuya", "Yukiyo", "Ankur", "Saiyam", "Vadim", "Andrea", "Ana" ] self.lst = UserListBox(self, users) line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) btnsizer = wx.StdDialogButtonSizer() btn1 = wx.Button(self, wx.ID_OK) btn1.SetDefault() btnsizer.AddButton(btn1) btn2 = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn2) btnsizer.Realize() btn1.Bind(wx.EVT_BUTTON, self.press_ok) btn2.Bind(wx.EVT_BUTTON, self.press_cancel) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(wx.StaticText(self, -1, "Select one user from the below list."), 0, wx.ALIGN_LEFT|wx.ALL, 5) sizer.Add(self.lst, 1, wx.EXPAND) sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) self.SetSizer(sizer) sizer.Fit(self) def press_ok(self, evt): print self.lst.GetSelection() def press_cancel(self, evt): self.parent.Destroy() if __name__ == "__main__": app = MyApp(False) app.MainLoop()
実行画面は以下の通り。