We have created combo popup using ulimatelistcontrol and we have added first item is textbox
but that textbox not editable also we have to add events to that textbox. here is
the code. for more clarification I have attached Image.
import wx
from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
from wx.lib.agw import ultimatelistctrl as ULC
class FDListCtrl(ULC.UltimateListCtrl, ListCtrlAutoWidthMixin):
def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
ULC.UltimateListCtrl.__init__(self, parent, agwStyle= ULC.ULC_REPORT
| ULC.ULC_VRULES
| ULC.ULC_HRULES
| ULC.ULC_SINGLE_SEL
| ULC.ULC_NO_HEADER
| ULC.ULC_HAS_VARIABLE_ROW_HEIGHT
| ULC.ULC_HOT_TRACKING, size=(200,40)
)
ListCtrlAutoWidthMixin.__init__(self)
class ListCtrlComboPopup(wx.ComboPopup, ListCtrlAutoWidthMixin):
def __init__(self):
wx.ComboPopup.__init__(self)
self.lc = None
self.count = 0
self.value = -1
self.current_item = -1
def GetItemData(self, index):
if index < 0:
return 0
return self.lc.GetItemData(index)
def AddItem(self, txt, item_data=None, colour=wx.Colour(255, 255, 255)):
if self.lc and self.lc.GetColumnCount() == 0:
self.lc.InsertColumn(0, "")
print(self.lc.GetColumnCount())
print(self.lc.GetItemCount())
if txt == '':
textctrl = wx.TextCtrl(self.lc, -1, value='Data', size=wx.DefaultSize)
index = self.lc.InsertStringItem(self.lc.GetItemCount(), txt, 0)
self.lc.SetItemWindow(index, 0, textctrl, expand=True)
else:
index = self.lc.InsertStringItem(self.lc.GetItemCount(), txt, ULC.ULC_MASK_TEXT)
if index > -1:
self.count = self.count + 1
if item_data:
self.lc.SetItemData(index, item_data)
_entry = self.lc.GetItem(self.lc.GetItemCount() - 1)
self.lc.SetItemTextColour(index, colour)
def DeleteItem(self, index):
self.lc.DeleteItem(index)
def ItemData(self, index):
return self.lc.GetItemText(index)
def OnMotion(self, event):
item, flags = self.lc.HitTest(event.GetPosition())
if self.GetItemData(item):
self.lc.Select(item)
self.current_item = item
event.Skip()
def OnLeftDown(self, event):
if self.GetItemData(self.current_item):
self.value = self.current_item
self.Dismiss()
# This is called immediately after construction finishes. You can
# use self.GetCombo if needed to get to the ComboCtrl instance.
def Init(self):
self.value = -1
self.current_item = -1
self.count = 0
if self.lc and self.lc.GetColumnCount() == 0:
self.lc.InsertColumn(0, "")
# Create the popup child control. Return true for success.
def Create(self, parent):
self.lc = FDListCtrl(parent, ID=wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.SIMPLE_BORDER | wx.LC_NO_HEADER)
self.lc.Bind(wx.EVT_MOTION, self.OnMotion)
self.lc.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
return True
# Return the widget that is to be used for the popup
def GetControl(self):
return self.lc
# Called just prior to displaying the popup, you can use it to
# 'select' the current item.
def SetStringValue(self, val):
idx = self.lc.FindItem(-1, val)
if idx != wx.NOT_FOUND:
self.lc.Select(idx)
# Return a string representation of the current item.
def GetStringValue(self):
if self.value >= 0:
return self.lc.GetItemText(self.value)
return ""
# Called immediately after the popup is shown
def OnPopup(self):
wx.ComboPopup.OnPopup(self)
# Called when popup is dismissed
def OnDismiss(self):
wx.ComboPopup.OnDismiss(self)
# This is called to custom paint in the combo control itself
# (ie. not the popup). Default implementation draws value as
# string.
def PaintComboControl(self, dc, rect):
wx.ComboPopup.PaintComboControl(self, dc, rect)
# Receives key events from the parent ComboCtrl. Events not
# handled should be skipped, as usual.
def OnComboKeyEvent(self, event):
wx.ComboPopup.OnComboKeyEvent(self, event)
# Implement if you need to support special action when user
# double-clicks on the parent wxComboCtrl.
def OnComboDoubleClick(self):
wx.ComboPopup.OnComboDoubleClick(self)
# Return final size of popup. Called on every popup, just prior to OnPopup.
# minWidth = preferred minimum width for window
# prefHeight = preferred height. Only applies if > 0,
# maxHeight = max height for window, as limited by screen size
# and should only be rounded down, if necessary.
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
items_displayed = self.lc.GetItemCount() if self.lc.GetItemCount() <= 15 else 15
return wx.ComboPopup.GetAdjustedSize(self, minWidth, items_displayed * 20, maxHeight)
# Return true if you want delay the call to Create until the popup
# is shown for the first time. It is more efficient, but note that
# it is often more convenient to have the control created
# immediately.
# Default returns false.
def LazyCreate(self):
return wx.ComboPopup.LazyCreate(self)
def Select(self, item_index):
if self.count != 0:
self.current_item = item_index
self.lc.Select(item_index)
return True
return False
def Items(self):
items = []
item_count = self.lc.GetItemCount()
for row in range(item_count):
items.append(self.lc.GetItem(row))
return items
def Clear(self):
self.lc.ClearAll()
self.Init()
class ComboMenuMeta(type(wx.ComboCtrl)):
pass
class ComboMenu(wx.ComboCtrl, metaclass=ComboMenuMeta):
def __init__(self, parent, style=0):
wx.ComboCtrl.__init__(self, parent, style=style, size=(200,40))
self.popup_ctrl = ListCtrlComboPopup()
self.SetPopupControl(self.popup_ctrl)
self.Count = self.popup_ctrl.count
def Items(self):
return self.popup_ctrl.Items()
def Append(self, item_string, item_data=None, colour = wx.Colour(255, 255, 255)):
self.popup_ctrl.AddItem(item_string, item_data, colour)
def Count(self):
return self.popup_ctrl.count
def GetCount(self):
return self.popup_ctrl.count
def Clear(self):
self.popup_ctrl.Clear()
def Delete(self, item_index):
self.popup_ctrl.DeleteItem(item_index)
def GetString(self, item_index):
return self.popup_ctrl.ItemData(item_index)
def Select(self, item_index):
if self.popup_ctrl.Select(item_index):
self.SetValue(self.GetString(item_index))
def GetClientData(self, item_index):
return self.popup_ctrl.GetItemData(item_index)
def GetSelection(self):
return self.popup_ctrl.current_item
class TestPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
pscb = ComboMenu(self,style=wx.CB_READONLY)
pscb.Append('', None, wx.Colour(255, 255, 255))
pscb.Append('Item 1', 'Item 1', wx.Colour(255, 255, 255))
self.pscb = pscb
if __name__ == '__main__':
app = wx.App()
frame = wx.Frame (None, -1, 'Filter DropDown', size=(600, 500))
TestPanel(frame)
frame.Show()
app.MainLoop()