In one of my projects I use wx.dataview.DataViewCtrl. I want to use different colours for alternating rows, but the documentation states for the .SetAlternateRowColour() method:
True if customizing this colour is supported (currently only in the generic version).
Also sorting by multiple columns is only supported by the generic versions. My system uses wxGTK, so I miss these features.
Is there a way to force wxPython to use the generic version of DataViewCtrl?
If not, is there a trick known to get alternating colours for rows? And sorting by multiple columns?
I found a comment in an issue raised in the wxWidgets GitHub repository which said that in order to use the generic wxDataViewListCtrl on GTK, you would have to build wxWidgets using the configure option --disable-nativedvc. If you succeeded in doing that, you would then need to produce a custom build of wxPython in order to interface with it.
Below is a very simplified example that changes the background colour of alternate rows, which does work in the native version (I am using wxPython 4.2.1 gtk3 (phoenix) wxWidgets 3.2.4 + Python 3.12.3 + Linux Mint 22). I don’t know how to implement sorting by multiple columns.
import wx
import wx.dataview as dv
def getData(num_rows, num_cols):
data = []
for r in range(num_rows):
values = []
for c in range(num_cols):
value = f"Item {r + 1},{c + 1}"
values.append(value)
data.append(values)
return data
class ColourModel(dv.DataViewIndexListModel):
def __init__(self, data):
dv.DataViewIndexListModel.__init__(self, len(data))
self.data = data
# This method is called to provide the data object for a
# particular row,col
def GetValueByRow(self, row, col):
return self.data[row][col]
# This method is called when the user edits a data item in the view.
def SetValueByRow(self, value, row, col):
self.data[row][col] = value
return True
# Report how many columns this model provides data for.
def GetColumnCount(self):
return len(self.data[0])
# Report the number of rows in the model
def GetCount(self):
return len(self.data)
# Called to check if non-standard attributes
# should be used in the cell at (row, col)
# Note: These settings are not used for cells with None values
def GetAttrByRow(self, row, col, attr):
if row % 2 == 0:
attr.SetBackgroundColour('#D0F0A0')
else:
attr.SetBackgroundColour('#A0D0E0')
return True
class TestFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="Coloured Rows")
self.SetSize((340, 260))
style = dv.DV_HORIZ_RULES | dv.DV_VERT_RULES
self.dvc = dv.DataViewCtrl(self, style=style)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.dvc, 1, wx.EXPAND, 0)
self.SetSizer(main_sizer)
self.Layout()
self.num_rows = 8
self.num_cols = 4
data = getData(self.num_rows, self.num_cols)
self.displayData(data)
def displayData(self, data):
self.model = ColourModel(data)
self.dvc.AssociateModel(self.model)
for c in range(self.num_cols):
label = f"Col-{c+1}"
renderer = dv.DataViewTextRenderer()
col = dv.DataViewColumn(label, renderer, c)
self.dvc.AppendColumn(col)
app = wx.App()
frame = TestFrame(None)
frame.Show()
app.MainLoop()
I might stay clear of compiling that stuff myself. Only, because it would then only work on my computer. But thanks!
Regarding using GetAttrByRow(): I noticed that method, but thought, it would only work for pure texts (as it states in the documentation: ‘This only affects the DataViewTextRendererText() (sic) renderer’). I now tried it with different renderers and some others also work, such as the DataViewDateRenderer and the inert DataViewSpinRenderer (I haven’t tried any other). Some others do not change the background: The DataViewToggleRenderer, the DataViewChoiceRenderer and the DataViewProgressRenderer (I haven’t tried any other).