How to set column header label alignment for one specific column header

How to set alignment for specific col header in wxpython?
As SetColLabelAlignment() but for a specific column.

HEADER COL1 and COL2 has left alignment
HEADER COL3 has right alignment
HEADER COL4 has center alignment

HEADER |COL1  |COL2  |  COL3|  COL4   |
ROW1   |aa    |bb    |    56|    Y    |
ROW2   |cc    |hh    |    34|    N    |

For set aligment for cell I use:
self.grid.SetCellAlignment(row, 1, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)

But how do I set the alignment of a header of a particular column?

I also asked in stackoverflow

Very thanks!!

I did some experiments (on linux+gtk version) using SetColAttr() which did change the alignment of all the cells in a column, but it didn’t affect the alignment of the header.

As your example only includes text data values, is there a particular reason why you are using a wx.grid.Grid control instead of a wx.ListCtrl or a wx.lib.agw.ultimatelistctrl ?

The real case has a choice for one column.
I tred this but not has worked.

        gc_attr = wx.grid.GridCellAttr()
        gc_attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(2, gc_attr)

Header stil center alignment.

Very thanks

Yes, you got the same results with SetColAttr() that I did.

UltimateListCtrl can contain Choice controls. Here is a quick demo that I modified from the example in the documentation:

import sys
import wx
import wx.lib.agw.ultimatelistctrl as ULC

class MyFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "UltimateListCtrl Demo")
        u_list = ULC.UltimateListCtrl(self, wx.ID_ANY, agwStyle=ULC.ULC_REPORT | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_SINGLE_SEL | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)

        u_list.InsertColumn(0, "Column 1", format=ULC.ULC_FORMAT_CENTER)
        u_list.InsertColumn(1, "Column 2")
        u_list.InsertColumn(2, "Column 3", format=ULC.ULC_FORMAT_RIGHT)

        index = u_list.InsertStringItem(sys.maxsize, "Item 1")
        u_list.SetStringItem(index, 1, "bb")
        u_list.SetStringItem(index, 2, "56")

        index = u_list.InsertStringItem(sys.maxsize, "Item 2")
        u_list.SetStringItem(index, 1, "hh")
        u_list.SetStringItem(index, 2, "34")

        choice = wx.Choice(u_list, -1, choices=["one", "two"])
        index = u_list.InsertStringItem(sys.maxsize, "A widget")
        u_list.SetItemWindow(index, 1, choice, expand=True)

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


if __name__ == "__main__":
    app = wx.App(0)
    frame = MyFrame(None)
    app.SetTopWindow(frame)
    frame.Show()
    app.MainLoop()

Tested on Python 3.8.10 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.3

Screenshot at 2022-03-25 10-55-31

First, thank you for your reply

I add TextCtrl with TextCtrl in column 3

        index = u_list.InsertStringItem(sys.maxsize, "Item 2")
        u_list.SetStringItem(index, 1, "hh")
        text = wx.TextCtrl(u_list, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        u_list.SetItemWindow(index, 2, text, expand=True)

Your option works fine but but for me it looks much worse aesthetically.

ultimatelistctrl_01

My Grid
grid_control

In grid:

  • Choice widget is hide when no edition. (column Issue line 1 and 2 are choices)
  • TextCtrl widget algo is hide and only show value when no edition

For me grid is more clean.

Very thanks anyway.

Yes, you got the same results with SetColAttr() that I did.

I test this:

        gc_attr = wx.grid.GridCellAttr()
        gc_attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE)
        self.my_grd.SetColAttr(2, gc_attr) 

But not work for me.
I don’t know how to use SetColAttr()

Very thanks.
[/quote]

I test this:

        gc_attr = wx.grid.GridCellAttr()
        gc_attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE)
        self.my_grd.SetColAttr(2, gc_attr) 

But not work for me.
I don’t know how to use SetColAttr()

Very thanks.

OK, if we can’t change the alignment of the row and column labels in a Grid control, perhaps we could hide the real ones and make the first row and first column look like headers?

Here is a quick example:

import wx
import wx.grid as grid

class MyForm(wx.Frame):

    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="Fake Grid Labels", size=(500, 200))
        panel = wx.Panel(self)

        self.grid = grid.Grid(panel)
        self.grid.CreateGrid(3, 5)

        self.grid.HideColLabels()
        self.grid.HideRowLabels()

        self.grid.SetColSize(0, 100)
        self.grid.SetColSize(1, 100)
        self.grid.SetColSize(2, 100)
        self.grid.SetColSize(3, 100)

        font = self.grid.GetLabelFont()
        bg = "#e0e0e0"

        self.grid.SetCellValue(0, 0, "HEADER")
        self.grid.SetCellValue(0, 1, "COL1")
        self.grid.SetCellValue(0, 2, "COL2")
        self.grid.SetCellValue(0, 3, "COL3")
        self.grid.SetCellValue(0, 4, "COL4")

        for c in range(5):
            self.grid.SetCellFont(0, c, font)
            self.grid.SetCellBackgroundColour(0, c, bg)

        self.grid.SetCellValue(1, 0, "ROW1")
        self.grid.SetCellFont(1, 0, font)
        self.grid.SetCellValue(1, 1, "aa")
        self.grid.SetCellValue(1, 2, "bb")
        self.grid.SetCellValue(1, 3, "56")
        self.grid.SetCellValue(1, 4, "Y")
        self.grid.SetCellValue(2, 0, "ROW2")
        self.grid.SetCellFont(2, 0, font)
        self.grid.SetCellValue(2, 1, "cc")
        self.grid.SetCellValue(2, 2, "hh")
        self.grid.SetCellValue(2, 3, "34")
        self.grid.SetCellValue(2, 4, "N")

        for r in range(1, 3):
            self.grid.SetCellFont(r, 0, font)
            self.grid.SetCellBackgroundColour(r, 0, bg)


        attr = wx.grid.GridCellAttr()
        attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(0, attr)
        attr = wx.grid.GridCellAttr()
        attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(1, attr)
        attr = wx.grid.GridCellAttr()
        attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(2, attr)
        attr = wx.grid.GridCellAttr()
        attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(3, attr)
        attr = wx.grid.GridCellAttr()
        attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
        self.grid.SetColAttr(4, attr)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid)
        panel.SetSizer(sizer)



if __name__ == "__main__":
    app = wx.App()
    frame = MyForm()
    frame.Show()
    app.MainLoop()

Screenshot at 2022-03-25 13-44-41

I have a copy of this book:
https://www.packtpub.com/product/wxpython-application-development-cookbook/9781785287732

In chapter 8 of that book there is an example of how to customise grid labels by sub-classing wx.lib.mixins.gridlabelrenderer.GridLabelRenderer.

However, when I tested it, the custom column label renderer always receives wx.ALIGN_CENTRE as the hAlign argument in its Draw() method, irrespective of whatever alignment has been set for the column.

Based on the example from Cody Precord’s book, the following code uses a dictionary lookup to set the horizontal alignment for each column:

import wx
import wx.grid as grid
import wx.lib.mixins.gridlabelrenderer as glr

COL_H_ALIGNMENTS = {
    0 : wx.ALIGN_LEFT,
    1 : wx.ALIGN_LEFT,
    2 : wx.ALIGN_RIGHT,
    3 : wx.ALIGN_CENTRE
}

class CustomGrid(grid.Grid, glr.GridWithLabelRenderersMixin):
    def __init__(self, parent):
        grid.Grid.__init__(self, parent)
        glr.GridWithLabelRenderersMixin.__init__(self)


class CustomColLabelRenderer(glr.GridLabelRenderer):
    def __init__(self, color):
        super(CustomColLabelRenderer, self).__init__()
        self.color = color

    def Draw(self, grid, dc, rect, col):
        dc.SetPen(wx.Pen(wx.WHITE))
        dc.SetBrush(wx.Brush(self.color))
        dc.DrawRectangle(rect)
        text = grid.GetColLabelValue(col)
        # hAlign, vAlign = grid.GetColLabelAlignment()
        hAlign = COL_H_ALIGNMENTS[col]
        vAlign = wx.ALIGN_CENTRE
        self.DrawText(grid, dc, rect, text, hAlign, vAlign)


class MyFrame(wx.Frame):

    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="Custom Grid Column Headers", size=(650,320))
        panel = wx.Panel(self)

        self.grid = CustomGrid(panel)
        self.grid.CreateGrid(2, 4)

        bg = self.grid.GetLabelBackgroundColour()

        col_render = CustomColLabelRenderer(bg)
        self.grid.SetDefaultColLabelRenderer(col_render)

        for col in range(4):
            attr = wx.grid.GridCellAttr()
            attr.SetAlignment(COL_H_ALIGNMENTS[col], wx.ALIGN_CENTRE)
            self.grid.SetColAttr(col, attr)

        self.grid.SetColLabelValue(0, "COL1")
        self.grid.SetColSize(0, 100)
        self.grid.SetColLabelValue(1, "COL2")
        self.grid.SetColSize(1, 100)
        self.grid.SetColLabelValue(2, "COL3")
        self.grid.SetColSize(2, 100)
        self.grid.SetColLabelValue(3, "COL4")
        self.grid.SetColSize(3, 100)

        self.grid.SetRowLabelValue(0, "ROW1")
        self.grid.SetRowLabelValue(1, "ROW2")

        self.grid.SetCellValue(0, 0, "aa")
        self.grid.SetCellValue(0, 1, "bb")
        self.grid.SetCellValue(0, 2, "56")
        self.grid.SetCellValue(0, 3, "Y")
        self.grid.SetCellValue(1, 0, "cc")
        self.grid.SetCellValue(1, 1, "hh")
        self.grid.SetCellValue(1, 2, "34")
        self.grid.SetCellValue(1, 3, "N")

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid)
        panel.SetSizer(sizer)


if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()


Hello:

Your reply SOLVE the question for me. :slightly_smiling_face: Very thanks!!

import wx
import wx.grid as grid
import wx.lib.mixins.gridlabelrenderer as glr

COL_H_ALIGNMENTS = {
    0 : wx.ALIGN_LEFT,
    1 : wx.ALIGN_LEFT,
    2 : wx.ALIGN_RIGHT,
    3 : wx.ALIGN_CENTRE
}

class CustomGrid(grid.Grid, glr.GridWithLabelRenderersMixin):
    def __init__(self, parent):
        grid.Grid.__init__(self, parent)
        glr.GridWithLabelRenderersMixin.__init__(self)


class CustomColLabelRenderer(glr.GridLabelRenderer):
    def __init__(self, color):
        super(CustomColLabelRenderer, self).__init__()
        self.color = color

    def Draw(self, grid, dc, rect, col):
        dc.SetPen(wx.Pen(wx.WHITE))
        dc.SetBrush(wx.Brush(self.color))
        dc.DrawRectangle(rect)
        text = grid.GetColLabelValue(col)
        # hAlign, vAlign = grid.GetColLabelAlignment()
        hAlign = COL_H_ALIGNMENTS[col]
        vAlign = wx.ALIGN_CENTRE
        self.DrawText(grid, dc, rect, text, hAlign, vAlign)


class MyFrame(wx.Frame):

    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="Custom Grid Column Headers", size=(650,320))
        panel = wx.Panel(self)

        self.grid = CustomGrid(panel)
        self.grid.CreateGrid(2, 4)

        bg = self.grid.GetLabelBackgroundColour()

        col_render = CustomColLabelRenderer(bg)
        self.grid.SetDefaultColLabelRenderer(col_render)

        for col in range(4):
            attr = wx.grid.GridCellAttr()
            attr.SetAlignment(COL_H_ALIGNMENTS[col], wx.ALIGN_CENTRE)
            self.grid.SetColAttr(col, attr)

        self.grid.SetColLabelValue(0, "COL1")
        self.grid.SetColSize(0, 100)
        self.grid.SetColLabelValue(1, "COL2")
        self.grid.SetColSize(1, 100)
        self.grid.SetColLabelValue(2, "COL3")
        self.grid.SetColSize(2, 100)
        self.grid.SetColLabelValue(3, "COL4")
        self.grid.SetColSize(3, 100)

        self.grid.SetRowLabelValue(0, "ROW1")
        self.grid.SetRowLabelValue(1, "ROW2")

        self.grid.SetCellValue(0, 0, "aa")
        self.grid.SetCellValue(0, 1, "bb")
        self.grid.SetCellValue(0, 2, "56")
        self.grid.SetCellValue(0, 3, "Y")
        self.grid.SetCellValue(1, 0, "cc")
        self.grid.SetCellValue(1, 1, "hh")
        self.grid.SetCellValue(1, 2, "34")
        self.grid.SetCellValue(1, 3, "N")

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid)
        panel.SetSizer(sizer)


if __name__ == "__main__":
    app = wx.App(0)
    frame = MyFrame()
    app.SetTopWindow(frame)
    frame.Show()
    app.MainLoop()
1 Like