Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
qtws26_logo

The Qt Event of the Year: Qt World Summit 2026

Save Your Spot >
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Selection highlight is a thin blue bar at the left of the cell.
Qt 6.12 LTS is out! See what's new in the release blog

Selection highlight is a thin blue bar at the left of the cell.

Scheduled Pinned Locked Moved Unsolved Qt for Python
15 Posts 5 Posters 553 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    Jim G
    wrote last edited by
    #1

    I'm a relative beginner with Qt.

    I've set up a QTableView with a QAbstractTableModel subclass, and have it working except for the selection highlight, which is just a thin blue vertical line at the left of the cells.

    Google (possibly hallucinating) tells me I need to have the model's data() method handle SizeHintRole, but that requires the view to pass its fontMetrics to the model, and then the model must calculate the text size, I don't understand why the model needs to be responsible for worrying about pixels. I've read the page about why the model specifies some formatting that is really intrinsic to the data, so it can be rendered consistently in multiple views. But even that seems like excessive coupling and blurring of the Single Responsibility principle.

    I'm not sure why the model should have to calculate the text size just so the view can highlight it, especially when SizeToContents already did that nicely. This seems redundant.

    Question

    Is Google just hallucinating, and is there a way to make the view use the already (internally) calculated text size for selection highlighting? Or, is the only recourse to create a delegate and re-do the text size calculation there?

    Thanks

    1 Reply Last reply
    0
    • J Offline
      J Offline
      Jim G
      wrote last edited by Jim G
      #2

      I implemented Google's suggestion, but it has no effect. Here's the interesting part of the code:

      QAbstractTableModel Subclass

      class ColDef:
          ''' 
              Store column definitions for a model
              
              Still a work-in-progress 
          '''
          def __init__(self, header:str, attr:str, fmt:str, align:Qt.AlignmentFlag):
              self.header = header
              self.attr   = attr
              self.fmt    = fmt
              self.align  = align
              
          def format(self, row) -> str:
              if self.attr == '': return ''
              val = getattr(row, self.attr)
              
              if self.fmt == 'time':
                  if isinstance(val, dt.datetime):
                      return val.strftime("%H:%M")
              else: # For now...
                  return str(val)
              
              return None
      
      columnDefs = [
          #       Header              Field in rowset                 Format  Alignment
          #       ------------------  ------------------------------  ------- ---------------
          ColDef('Scheduled\nStart', 'start_ts',                      'time', Qt.AlignCenter),
          ColDef('Scheduled\nEnd',   'end_ts',                        'time', Qt.AlignCenter),
          ColDef('Leader',           '',                              '',     Qt.AlignLeft),
          ColDef('Actual\nStart',    '',                              '',     Qt.AlignCenter),
          ColDef('Actual\nEnd',      '',                              '',     Qt.AlignCenter),
          ColDef('Activity',         '',                              '',     Qt.AlignCenter),
          ColDef('Description',      'title',                         '',     Qt.AlignLeft),
          ColDef('Limit',            'registrations_limit',           'int',  Qt.AlignCenter),
          ColDef('Reg',              'confirmed_registrations_count', 'int',  Qt.AlignCenter),
          ColDef('Wait',             'waitlist_registration_count',   'int',  Qt.AlignCenter),
      ]
      
      class SAEventsModel(QAbstractTableModel):
          def __init__(self, parent=None, * , dbEngine):
              super().__init__()
              
              self.dbEngine = dbEngine
              self.rowset   = []
              self.fontMetrics = None
      
          def setFontMetrics(self, font:QFont):
              self.fontMetrics = QFontMetrics(font)
      
          def refresh(self, d:dt.date):
              self.beginResetModel()
              
              with Session(self.dbEngine) as dbSession:
                  stmt = select(DVEventSession)\
                          .where(DVEventSession.event_date==d)\
                          .order_by(DVEventSession.start_ts)
                  self.rowset = dbSession.scalars(stmt).all()
                  
              self.endResetModel()
      
          def headerData(self, section:int, orientation:Qt.Orientation, role:Qt.ItemDataRole):
              if orientation == Qt.Orientation.Horizontal \
                      and 0 <= section < len(columnDefs) \
                      and role == Qt.DisplayRole:
                  return columnDefs[section].header
              return None
      
          def rowCount(self, _) -> int:
              return len(self.rowset)
      
          def columnCount(self, _) -> int:
              return len(columnDefs)
          
          def data(self, index:QModelIndex, role:Qt.ItemDataRole):
              if index.isValid():
                  row = index.row()
                  col = index.column()
                  cd = columnDefs[col]
                  
                  if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole):
                      # Table is read-only, return same data for Display and Edit
                      return cd.format(self.rowset[row])
                  
                  elif role == Qt.ItemDataRole.SizeHintRole:
                      # Recalculate the text size 
                      text = cd.format(self.rowset[row])
                      w    = self.fontMetrics.horizontalAdvance(text)
                      h    = self.fontMetrics.height()
                      return QSize(w+20, h+10)
                  
                  elif role == Qt.ItemDataRole.TextAlignmentRole:
                      # Return the desired alignment
                      return cd.align
                  
              return None
      

      Main Window snippet

      self.ui is loaded from a QtCreator-generated .ui file. self.ui.guildEvents' is a QTableView`

              td = dt.date.today()
              self.ui.curDate.setText(f"{td:%B} {td.day} {td:%Y}")
              
              self.model = SAEventsModel(dbEngine=dbEngine)
              self.model.refresh(td)
              self.model.setFontMetrics(self.ui.guildEvents.font())
              
              self.ui.guildEvents.setModel(self.model)
              self.ui.guildEvents.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
              self.ui.guildEvents.setSelectionBehavior(qv.SelectionBehavior.SelectRows)
      

      Main Window Display

      The middle row is selected.

      2026-10-07_17-35-57.PNG

      JonBJ 1 Reply Last reply
      0
      • J Jim G

        I implemented Google's suggestion, but it has no effect. Here's the interesting part of the code:

        QAbstractTableModel Subclass

        class ColDef:
            ''' 
                Store column definitions for a model
                
                Still a work-in-progress 
            '''
            def __init__(self, header:str, attr:str, fmt:str, align:Qt.AlignmentFlag):
                self.header = header
                self.attr   = attr
                self.fmt    = fmt
                self.align  = align
                
            def format(self, row) -> str:
                if self.attr == '': return ''
                val = getattr(row, self.attr)
                
                if self.fmt == 'time':
                    if isinstance(val, dt.datetime):
                        return val.strftime("%H:%M")
                else: # For now...
                    return str(val)
                
                return None
        
        columnDefs = [
            #       Header              Field in rowset                 Format  Alignment
            #       ------------------  ------------------------------  ------- ---------------
            ColDef('Scheduled\nStart', 'start_ts',                      'time', Qt.AlignCenter),
            ColDef('Scheduled\nEnd',   'end_ts',                        'time', Qt.AlignCenter),
            ColDef('Leader',           '',                              '',     Qt.AlignLeft),
            ColDef('Actual\nStart',    '',                              '',     Qt.AlignCenter),
            ColDef('Actual\nEnd',      '',                              '',     Qt.AlignCenter),
            ColDef('Activity',         '',                              '',     Qt.AlignCenter),
            ColDef('Description',      'title',                         '',     Qt.AlignLeft),
            ColDef('Limit',            'registrations_limit',           'int',  Qt.AlignCenter),
            ColDef('Reg',              'confirmed_registrations_count', 'int',  Qt.AlignCenter),
            ColDef('Wait',             'waitlist_registration_count',   'int',  Qt.AlignCenter),
        ]
        
        class SAEventsModel(QAbstractTableModel):
            def __init__(self, parent=None, * , dbEngine):
                super().__init__()
                
                self.dbEngine = dbEngine
                self.rowset   = []
                self.fontMetrics = None
        
            def setFontMetrics(self, font:QFont):
                self.fontMetrics = QFontMetrics(font)
        
            def refresh(self, d:dt.date):
                self.beginResetModel()
                
                with Session(self.dbEngine) as dbSession:
                    stmt = select(DVEventSession)\
                            .where(DVEventSession.event_date==d)\
                            .order_by(DVEventSession.start_ts)
                    self.rowset = dbSession.scalars(stmt).all()
                    
                self.endResetModel()
        
            def headerData(self, section:int, orientation:Qt.Orientation, role:Qt.ItemDataRole):
                if orientation == Qt.Orientation.Horizontal \
                        and 0 <= section < len(columnDefs) \
                        and role == Qt.DisplayRole:
                    return columnDefs[section].header
                return None
        
            def rowCount(self, _) -> int:
                return len(self.rowset)
        
            def columnCount(self, _) -> int:
                return len(columnDefs)
            
            def data(self, index:QModelIndex, role:Qt.ItemDataRole):
                if index.isValid():
                    row = index.row()
                    col = index.column()
                    cd = columnDefs[col]
                    
                    if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole):
                        # Table is read-only, return same data for Display and Edit
                        return cd.format(self.rowset[row])
                    
                    elif role == Qt.ItemDataRole.SizeHintRole:
                        # Recalculate the text size 
                        text = cd.format(self.rowset[row])
                        w    = self.fontMetrics.horizontalAdvance(text)
                        h    = self.fontMetrics.height()
                        return QSize(w+20, h+10)
                    
                    elif role == Qt.ItemDataRole.TextAlignmentRole:
                        # Return the desired alignment
                        return cd.align
                    
                return None
        

        Main Window snippet

        self.ui is loaded from a QtCreator-generated .ui file. self.ui.guildEvents' is a QTableView`

                td = dt.date.today()
                self.ui.curDate.setText(f"{td:%B} {td.day} {td:%Y}")
                
                self.model = SAEventsModel(dbEngine=dbEngine)
                self.model.refresh(td)
                self.model.setFontMetrics(self.ui.guildEvents.font())
                
                self.ui.guildEvents.setModel(self.model)
                self.ui.guildEvents.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
                self.ui.guildEvents.setSelectionBehavior(qv.SelectionBehavior.SelectRows)
        

        Main Window Display

        The middle row is selected.

        2026-10-07_17-35-57.PNG

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote last edited by JonB
        #3

        @Jim-G
        Hi. I am travelling abroad so cannot try anything.

        As ever with this sort of thing, try to reduce to minimal and then build up.

        I don't recall ever having a problem with selection highlighting nor doing anything at all about font, font metrics or sizes. If I were you I would:

        • Temporarily try a QTableWidget. Put in a couple of fixed rows and a couple of columns. Try a couple of SelectionBehaviours. Works or looks odd?

        • Move to a QTreeView but try a QStandardItemModel for the model. Again put in a couple of rows and columns. How does selection look?

        If problems there that is one thing. If they work but yours does not then start looking at your implementation.

        P.S.
        Is your issue because you did not implement the flags() override? You may need to do that for a QAbstractTableModel. You need to return at least ItemIsSelectable: because you have not I wonder of your items are just not selectable so it won't show properly? Check what your current SAEventsModel.flags(index) is returning. It actually ought be correct without override, but just verify.

        1 Reply Last reply
        0
        • J Offline
          J Offline
          Jim G
          wrote last edited by
          #4

          The flags() question was interesting, but the default is ItemIsSelectable|ItemIsEnabled, and implementing flags() returning those values had no effect.

          I tried some sample code using QTableWidget, and that works correctly. I then made sure my code sets all the same attributes on the view and the model, with no effect. I'm stumped. I guess I'm going to have to reimplement my code with QTableWidget and see what happens.

          More later...

          1 Reply Last reply
          0
          • S Offline
            S Offline
            SimonSchroeder
            wrote last edited by
            #5

            You data method only returns something for the few roles you have specified. Otherwise you are returning None. Try instead to return QAbstractItemModel.data(...) (I don't know Python and can't tell you how to exactly write that). This might solve your problem, but I'm not sure.

            SGaistS 1 Reply Last reply
            0
            • S SimonSchroeder

              You data method only returns something for the few roles you have specified. Otherwise you are returning None. Try instead to return QAbstractItemModel.data(...) (I don't know Python and can't tell you how to exactly write that). This might solve your problem, but I'm not sure.

              SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote last edited by
              #6

              @SimonSchroeder said in Selection highlight is a thin blue bar at the left of the cell.:

              You data method only returns something for the few roles you have specified. Otherwise you are returning None. Try instead to return QAbstractItemModel.data(...) (I don't know Python and can't tell you how to exactly write that). This might solve your problem, but I'm not sure.

                  return super().data(index, role)
              

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • J Offline
                J Offline
                Jim G
                wrote last edited by
                #7

                In C++ you return a default QVariant() for default behavior. In PySide6 this maps to None, and QVariant is not even defined or available for use. Also, in PySide6 QAbstractItemModel.data() is virtual with no default implementation.

                Using return super().data(index,role) raises NotImplementedError as expected

                1 Reply Last reply
                1
                • J Offline
                  J Offline
                  Jim G
                  wrote last edited by Jim G
                  #8

                  OK, I think I found a bug. I closely examined some sample code I found that uses a QStandardItemModel, and displays selection highlights correctly. Here's a screenshot:

                  2026-10-09_12-50-31.PNG

                  Other than the change of model class, the only other difference I could find was that in the sample code there is this:

                          # Alternating row colors for data density scannability
                          self.table_view.setAlternatingRowColors(True)
                  

                  So I tried adding that to my code, and it fixed the issue:

                  2026-10-09_12-53-11.PNG

                  Bug?

                  Also note that in my earlier screenshot showing the problem, there is already alternate row highlighting which is unexpected as the default for alternatingRowColors is False. Something's amiss here.

                  Christian EhrlicherC 1 Reply Last reply
                  0
                  • J Jim G

                    OK, I think I found a bug. I closely examined some sample code I found that uses a QStandardItemModel, and displays selection highlights correctly. Here's a screenshot:

                    2026-10-09_12-50-31.PNG

                    Other than the change of model class, the only other difference I could find was that in the sample code there is this:

                            # Alternating row colors for data density scannability
                            self.table_view.setAlternatingRowColors(True)
                    

                    So I tried adding that to my code, and it fixed the issue:

                    2026-10-09_12-53-11.PNG

                    Bug?

                    Also note that in my earlier screenshot showing the problem, there is already alternate row highlighting which is unexpected as the default for alternatingRowColors is False. Something's amiss here.

                    Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote last edited by Christian Ehrlicher
                    #9

                    @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                    Bug?

                    No, it's the default WinUI 3 style.

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    J 1 Reply Last reply
                    0
                    • Christian EhrlicherC Christian Ehrlicher

                      @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                      Bug?

                      No, it's the default WinUI 3 style.

                      J Offline
                      J Offline
                      Jim G
                      wrote last edited by
                      #10

                      @Christian-Ehrlicher said in Selection highlight is a thin blue bar at the left of the cell.:

                      @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                      Bug?

                      No, it's the default WinUI 3 style. Look into your explorer to see that the highlight is gray.

                      I'm not following. I think we're talking about two different things. I can reproduce the issue using the sample code only.

                      Here's the UI including self.table_view.setAlternatingRowColors(True) and line 4 selected:

                      2026-10-09_12-50-31.PNG

                      And now with that single line commented out and line 3 selected:

                      2026-10-09_13-06-02.PNG

                      Notice the "selection" highlight in the second screenshot is just a thin blue line at the left of each cell.

                      It is unexpected that displaying the correct highlighting would involve the setting of alternatingRowColors.

                      Christian EhrlicherC 1 Reply Last reply
                      0
                      • J Jim G

                        @Christian-Ehrlicher said in Selection highlight is a thin blue bar at the left of the cell.:

                        @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                        Bug?

                        No, it's the default WinUI 3 style. Look into your explorer to see that the highlight is gray.

                        I'm not following. I think we're talking about two different things. I can reproduce the issue using the sample code only.

                        Here's the UI including self.table_view.setAlternatingRowColors(True) and line 4 selected:

                        2026-10-09_12-50-31.PNG

                        And now with that single line commented out and line 3 selected:

                        2026-10-09_13-06-02.PNG

                        Notice the "selection" highlight in the second screenshot is just a thin blue line at the left of each cell.

                        It is unexpected that displaying the correct highlighting would involve the setting of alternatingRowColors.

                        Christian EhrlicherC Offline
                        Christian EhrlicherC Offline
                        Christian Ehrlicher
                        Lifetime Qt Champion
                        wrote last edited by
                        #11

                        @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                        Notice the "selection" highlight in the second screenshot is just a thin blue line at the left of each cell.

                        And that's the correct winui3 style.
                        3d371abe-a5a4-4328-ae54-9f9e0395d0d7-grafik.png

                        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                        Visit the Qt Academy at https://academy.qt.io/catalog

                        1 Reply Last reply
                        0
                        • J Offline
                          J Offline
                          Jim G
                          wrote last edited by Jim G
                          #12

                          So why does setting alternatingRowColors cause the change in highlight? Is that a bug?

                          I'm not trying to be difficult. I'm still learning Qt/PySide6 (excellent tools IMO) and am puzzled by the need to set alternatingRowColors just to get the expected highlight behavior.

                          Christian EhrlicherC S 2 Replies Last reply
                          0
                          • J Offline
                            J Offline
                            Jim G
                            wrote last edited by
                            #13

                            Also, what I see differs markedly from the example of winui 3 selection you cite. My selection indicators are only 2 pixels wide and jammed up against the left side of the text with no intervening space... actually they overlap (under) the leftmost pixel column of the text.

                            1 Reply Last reply
                            0
                            • J Jim G

                              So why does setting alternatingRowColors cause the change in highlight? Is that a bug?

                              I'm not trying to be difficult. I'm still learning Qt/PySide6 (excellent tools IMO) and am puzzled by the need to set alternatingRowColors just to get the expected highlight behavior.

                              Christian EhrlicherC Offline
                              Christian EhrlicherC Offline
                              Christian Ehrlicher
                              Lifetime Qt Champion
                              wrote last edited by
                              #14

                              @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                              So why does setting alternatingRowColors cause the change in highlight? Is that a bug?

                              The WinUI3 style has no information about alternating row colors so this is the solution for this.

                              med up against the left side of the text with no intervening space

                              This will be fixed

                              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                              Visit the Qt Academy at https://academy.qt.io/catalog

                              1 Reply Last reply
                              0
                              • J Jim G

                                So why does setting alternatingRowColors cause the change in highlight? Is that a bug?

                                I'm not trying to be difficult. I'm still learning Qt/PySide6 (excellent tools IMO) and am puzzled by the need to set alternatingRowColors just to get the expected highlight behavior.

                                S Offline
                                S Offline
                                SimonSchroeder
                                wrote last edited by
                                #15

                                @Jim-G said in Selection highlight is a thin blue bar at the left of the cell.:

                                So why does setting alternatingRowColors cause the change in highlight?

                                Qt tries to use the OS default widgets first. Alternating row colors is not supported by the OS directly. So, Qt will draw it from scratch and usually tries to mimic the OS look. Seems like it did not get updated, yet.

                                1 Reply Last reply
                                0

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt
                                • Unsolved