dede
dede

Reputation: 726

is it possible, to have two sortable ListCtrls in one window?

I have this little piece of code and everything is fine for the left ListCtrl:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import wx
import wx.lib.mixins.listctrl as listmix

class FillBD2Frame(wx.Frame):
  def __init__(self):
    wx.Frame.__init__(self, None, wx.ID_ANY, "FillBD2", size=(400, 300))
    self.Centre()
    FillBD2(self)

class MyListCtrl(wx.ListCtrl):
  def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
    wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
    self.parent=parent
    self.DataMap={}

class FillBD2(wx.Panel, listmix.ColumnSorterMixin):
  def __init__(self, parent):
    wx.Panel.__init__(self, parent, wx.ID_ANY, style=wx.WANTS_CHARS)

    self.parent=parent
    self.list_ctrl1=MyListCtrl(self, style=wx.LC_REPORT|wx.BORDER_SUNKEN|wx.LC_SORT_ASCENDING)
    self.list_ctrl2=MyListCtrl(self, style=wx.LC_REPORT|wx.BORDER_SUNKEN|wx.LC_SORT_ASCENDING)
    self.testen=  wx.Button(self, 2, "&test",  (-1, -1), wx.DefaultSize)

    gr=2
    self.list_ctrl1.InsertColumn(0, 'path',                              width=30*gr)
    self.list_ctrl1.InsertColumn(1, 'name',                              width=30*gr)
    self.list_ctrl1.InsertColumn(2, 'size(real)',  wx.LIST_FORMAT_RIGHT, width=15*gr)
    self.list_ctrl1.InsertColumn(3, 'size(dest)',  wx.LIST_FORMAT_RIGHT, width=15*gr)
    listmix.ColumnSorterMixin.__init__(self, 4)

    self.list_ctrl1.DataMap={
      0:("pth1", "nam1", 62, 70),
      1:("pth2", "nam2", 22, 30),
      2:("pth3", "nam3", 57, 60),
      4:("pth4", "nam4",  9, 10)
    }
    self.fillListCtrl(self.list_ctrl1, 1)


    self.list_ctrl2.InsertColumn(0, 'path',                              width=30*gr)
    self.list_ctrl2.InsertColumn(1, 'name',                              width=30*gr)
    self.list_ctrl2.InsertColumn(2, 'size(dest)',  wx.LIST_FORMAT_RIGHT, width=15*gr)
#    listmix.ColumnSorterMixin.__init__(self, 3)

    self.list_ctrl2.DataMap={
      0:("pth5", "nam5", 45, 50),
      1:("pth6", "nam6", 81, 90),
      2:("pth7", "nam7", 33, 40),
      4:("pth8", "nam8", 13, 20)
    }
    self.fillListCtrl(self.list_ctrl2, 2)


    self.list_ctrl1.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick1)
    self.list_ctrl2.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick2)

    vsizer=wx.BoxSizer(wx.VERTICAL)
    bsizer=wx.BoxSizer(wx.HORIZONTAL)
    hsizer=wx.BoxSizer(wx.HORIZONTAL)

    bsizer.Add(self.testen,   0, wx.ALL, 5)
    hsizer.Add(self.list_ctrl1, 1, wx.ALL|wx.EXPAND, 1)
    hsizer.Add(self.list_ctrl2, 1, wx.ALL|wx.EXPAND, 1)

    vsizer.Add(bsizer, 0, wx.ALL, 5)
    vsizer.Add(hsizer, 1, wx.ALL|wx.EXPAND, 5)

    self.SetSizer(vsizer)
    vsizer.Fit(self)
    self.list_ctrl1.SetFocus()
    self.list_ctrl1.Select(0, 1)

  def fillListCtrl(self, ctrl, ctrl_nr=1):
    ctrl.DeleteAllItems()
    ctrl.Refresh()
    index=0
    for key, data in ctrl.DataMap.items():
      ctrl.InsertStringItem(index, data[0])
      ctrl.SetStringItem(index, 1, data[1])
      ctrl.SetStringItem(index, 2, str(data[2]))
      if ctrl_nr==1:
        ctrl.SetStringItem(index, 3, str(data[3]))

      ctrl.SetItemData(index, key)
      index+=1
    ctrl.SetItemState(0, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)


  def GetListCtrl(self):
    return(self.list_ctrl1)

  def OnColClick1(self, event):
    self.itemDataMap=self.list_ctrl1.DataMap
    event.Skip()
  def OnColClick2(self, event):
    self.itemDataMap=self.list_ctrl2.DataMap
    event.Skip()


if __name__=='__main__':
  app=wx.App()
  frame=FillBD2Frame().Show()
  app.MainLoop()

But what do I have to do, if I want the right ListCtrl also be sortable?

If I uncomment the second listmix.ColumnSorterMixin.init(), the sorting for the left ListCtrl gets confused and the right one is still not sortable...

And how should the GetListCtrl method decide, which ListCtrl it shall return...!?

Upvotes: 0

Views: 89

Answers (1)

Mike Driscoll
Mike Driscoll

Reputation: 33111

You need to refactor the code a bit to get this to work. Since the ColumnSorterMixin requires that the ListCtrl exists (according to the source), it sounds like you need to have the mixin sub-classed with the wx.Panel, creating a class that has inherits from both. Because of this, you need to create a panel that has all the required methods and just a list control as its only widget. Then each time you instantiate this new class, you can add that to your top-level panel. Here's one approach that worked for me:

import wx
import wx.lib.mixins.listctrl as listmix

class FillBD2Frame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "FillBD2", size=(400, 300))
        self.Centre()
        FillBD2(self)

class MyListCtrl(wx.ListCtrl):
    def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
        self.parent=parent
        self.DataMap={}

class FillPanel(wx.Panel, listmix.ColumnSorterMixin):

    def __init__(self, parent, DataMap, ctrl_type=1):
        wx.Panel.__init__(self, parent, wx.ID_ANY, style=wx.WANTS_CHARS)
        self.parent = parent

        self.list_ctrl = MyListCtrl(self, 
                                    style=wx.LC_REPORT|wx.BORDER_SUNKEN|wx.LC_SORT_ASCENDING)

        gr=2
        self.list_ctrl.InsertColumn(0, 'path',                              width=30*gr)
        self.list_ctrl.InsertColumn(1, 'name',                              width=30*gr)

        if ctrl_type == 1:
            self.list_ctrl.InsertColumn(2, 'size(real)',  wx.LIST_FORMAT_RIGHT, width=15*gr)
            self.list_ctrl.InsertColumn(3, 'size(dest)',  wx.LIST_FORMAT_RIGHT, width=15*gr)
        elif ctrl_type == 2:
            self.list_ctrl.InsertColumn(2, 'size(dest)',  wx.LIST_FORMAT_RIGHT, width=15*gr)

        listmix.ColumnSorterMixin.__init__(self, 4)

        self.list_ctrl.DataMap = DataMap
        self.fillListCtrl(ctrl_type)
        self.list_ctrl.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.list_ctrl, 1, wx.EXPAND)
        self.SetSizer(sizer)


    def fillListCtrl(self, ctrl_nr=1):
        self.list_ctrl.DeleteAllItems()
        self.list_ctrl.Refresh()
        index=0
        for key, data in self.list_ctrl.DataMap.items():
            self.list_ctrl.InsertStringItem(index, data[0])
            self.list_ctrl.SetStringItem(index, 1, data[1])
            self.list_ctrl.SetStringItem(index, 2, str(data[2]))
            if ctrl_nr==1:
                self.list_ctrl.SetStringItem(index, 3, str(data[3]))

            self.list_ctrl.SetItemData(index, key)
            index+=1
        self.list_ctrl.SetItemState(0, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)

    def GetListCtrl(self):
        return(self.list_ctrl)

    def OnColClick(self, event):
        self.itemDataMap = self.list_ctrl.DataMap
        event.Skip()


class FillBD2(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY, style=wx.WANTS_CHARS)
        self.parent=parent

        DataMap_1={
            0:("pth1", "nam1", 62, 70),
            1:("pth2", "nam2", 22, 30),
            2:("pth3", "nam3", 57, 60),
            4:("pth4", "nam4",  9, 10)
        }

        DataMap_2={
            0:("pth5", "nam5", 45, 50),
            1:("pth6", "nam6", 81, 90),
            2:("pth7", "nam7", 33, 40),
            4:("pth8", "nam8", 13, 20)
        }

        self.testen=  wx.Button(self, -1, "&test",  (-1, -1), wx.DefaultSize)

        list_panel = FillPanel(self, DataMap_1)
        list_panel_2 = FillPanel(self, DataMap_2, ctrl_type=2)

        # create sizers
        vsizer = wx.BoxSizer(wx.VERTICAL)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)

        vsizer.Add(self.testen, 0, wx.ALL, 5)
        hsizer.Add(list_panel, 1, wx.ALL|wx.EXPAND, 5)
        hsizer.Add(list_panel_2, 1, wx.ALL|wx.EXPAND, 5)
        vsizer.Add(hsizer, 1, wx.EXPAND)
        self.SetSizer(vsizer)

if __name__=='__main__':
    app = wx.App()
    frame = FillBD2Frame().Show()
    app.MainLoop()

One other thing I need to point out. You had set the button's id to 2, which is a very bad thing. You need to let wxPython manage IDs, especially ones that are below 100 as those tend to be special IDs that wxPython uses internally. To make wxPython dynamically assign an ID, use wx.ID_ANY or -1, as you did in other parts of the code.

Upvotes: 1

Related Questions