Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. cannot get fixed sized columns in QTableView to work.
QtWS25 Last Chance

cannot get fixed sized columns in QTableView to work.

Scheduled Pinned Locked Moved Unsolved General and Desktop
qtablemodelqitemdelegateqheaderview
4 Posts 2 Posters 517 Views
  • 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
    johnco3
    wrote on 24 Feb 2024, 21:05 last edited by johnco3
    #1

    I am having trouble initializing a QTableView with fixed column header column widths.

    When I display the table for the first time, the columns seem to use the default horizontalHeaderDefaultSectionSize property from the Qt Designer's property editor.

    I also have the horizontalHeaderStretchLastSection property set to true.

    If I double-click on each of the columns, the layout snaps to the correct width, however I have to do this for each of the columns (except the last which is set to stretch as I just described). I am not sure why the initial layout does not respect the widths in my code.

    Has this something to do with sizeHints in a model for a horizontalHeader? I do not want to automatically size to the contents of the table (as the table can grow to a very large size, I just want the initial sizes to be correct).

    I set up my views using a table driven approach. The table contains a sample fixed size string or a length that I use to size the header (using font metrics):

    using TableSpec = std::vector<
        std::tuple<
            QTableView*,
            QStandardItemModel*,
            std::vector<TableColumnSpec>
        >
    >;
    
    Define the layout for tables in the main window.
    // Views with proxy sort filters need special handling
    // as the view does not directly have access to the model.
    const TableSpec gTableSpecs = { {
        // Thread colored logger.
        {
            ui->logView,
            mpLogViewModel.get(),
            {
                TableColumnSpec("Time", "Timestamp", "06-09-2023 20:01:33.334"),
                TableColumnSpec("Thread", "Thread ID", "0x00000000"),
                TableColumnSpec("Level", "Severity level", "critical"),
                TableColumnSpec("Description", "Description", "description")
            }
        },
    } };
    

    The above code shows just one of my tables (the one that shows a log table). This table uses a custom delegate that is assigned as follows (I don't think the delegate is involved with laying out the initial view of the horizontal header though), I also assign the mpLogViewModel (std::unique_ptr<QStandardItemModel>) to the view from here:

    // Assign item delegate to color the rows using the threadID (column1).
    ui->logView->setItemDelegate(mpLogItemDelegate.get());
    // Associate each model with its respective view.
    ui->logView->setModel(mpLogViewModel.get());
    

    Now that the item delegate and model have been associated with the ui->logView (QTableView), I initialize the table(s) as follows:

    // Layout the main application tables & headers.
    initTableHeaders(gTableSpecs);
    
    void
    initTableHeaders(const TableSpec& rTableSpec)
    {
        for (const auto& [pView, pModel, colSpecs] : rTableSpec) {
            const auto fm = pView->fontMetrics();
            const auto rowHeight = fm.lineSpacing();
            pView->verticalHeader()->setDefaultSectionSize(rowHeight);
            pView->verticalHeader()->setMaximumSectionSize(rowHeight);
            pView->verticalHeader()->setMinimumSectionSize(rowHeight);
            pView->verticalHeader()->setVisible(false);
            pView->horizontalHeader()->setMinimumSectionSize(25);
            pView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
            pView->horizontalHeader()->setStretchLastSection(true);
            pView->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder);
            pView->horizontalHeader()->setSortIndicatorShown(true);
            pView->setSelectionBehavior(QAbstractItemView::SelectRows);
            for (auto col = 0; col < static_cast<int>(colSpecs.size()); ++col) {
                const auto headerLabel = new QStandardItem(colSpecs[col].mColumnTitle);
                headerLabel->setTextAlignment(colSpecs[col].mAlignment);
                pModel->setHorizontalHeaderItem(col, headerLabel);
                const auto columnWidth = std::visit(Overload{
                    [&](const QString& rSampleStr)->int {
                        if (!rSampleStr.isEmpty()) {
                            return fm.horizontalAdvance(rSampleStr);
                        }
                        return fm.horizontalAdvance(colSpecs[col].mColumnTitle);
                    },
                    [&](const auto stringLength)->int {
                        if (stringLength > 0) {
                            return stringLength * fm.averageCharWidth();
                        }
                        return fm.horizontalAdvance(colSpecs[col].mColumnTitle);
                    },
                }, colSpecs[col].mSizeInfo);
                // Add 20 to make room for the sort arrow.
                pView->setColumnWidth(col, columnWidth + 20);
            }
        }
    }
    

    The problem is that when the log is displayed, it looks like this:

    enter image description here

    K 1 Reply Last reply 25 Feb 2024, 00:21
    0
    • J johnco3
      24 Feb 2024, 21:05

      I am having trouble initializing a QTableView with fixed column header column widths.

      When I display the table for the first time, the columns seem to use the default horizontalHeaderDefaultSectionSize property from the Qt Designer's property editor.

      I also have the horizontalHeaderStretchLastSection property set to true.

      If I double-click on each of the columns, the layout snaps to the correct width, however I have to do this for each of the columns (except the last which is set to stretch as I just described). I am not sure why the initial layout does not respect the widths in my code.

      Has this something to do with sizeHints in a model for a horizontalHeader? I do not want to automatically size to the contents of the table (as the table can grow to a very large size, I just want the initial sizes to be correct).

      I set up my views using a table driven approach. The table contains a sample fixed size string or a length that I use to size the header (using font metrics):

      using TableSpec = std::vector<
          std::tuple<
              QTableView*,
              QStandardItemModel*,
              std::vector<TableColumnSpec>
          >
      >;
      
      Define the layout for tables in the main window.
      // Views with proxy sort filters need special handling
      // as the view does not directly have access to the model.
      const TableSpec gTableSpecs = { {
          // Thread colored logger.
          {
              ui->logView,
              mpLogViewModel.get(),
              {
                  TableColumnSpec("Time", "Timestamp", "06-09-2023 20:01:33.334"),
                  TableColumnSpec("Thread", "Thread ID", "0x00000000"),
                  TableColumnSpec("Level", "Severity level", "critical"),
                  TableColumnSpec("Description", "Description", "description")
              }
          },
      } };
      

      The above code shows just one of my tables (the one that shows a log table). This table uses a custom delegate that is assigned as follows (I don't think the delegate is involved with laying out the initial view of the horizontal header though), I also assign the mpLogViewModel (std::unique_ptr<QStandardItemModel>) to the view from here:

      // Assign item delegate to color the rows using the threadID (column1).
      ui->logView->setItemDelegate(mpLogItemDelegate.get());
      // Associate each model with its respective view.
      ui->logView->setModel(mpLogViewModel.get());
      

      Now that the item delegate and model have been associated with the ui->logView (QTableView), I initialize the table(s) as follows:

      // Layout the main application tables & headers.
      initTableHeaders(gTableSpecs);
      
      void
      initTableHeaders(const TableSpec& rTableSpec)
      {
          for (const auto& [pView, pModel, colSpecs] : rTableSpec) {
              const auto fm = pView->fontMetrics();
              const auto rowHeight = fm.lineSpacing();
              pView->verticalHeader()->setDefaultSectionSize(rowHeight);
              pView->verticalHeader()->setMaximumSectionSize(rowHeight);
              pView->verticalHeader()->setMinimumSectionSize(rowHeight);
              pView->verticalHeader()->setVisible(false);
              pView->horizontalHeader()->setMinimumSectionSize(25);
              pView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
              pView->horizontalHeader()->setStretchLastSection(true);
              pView->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder);
              pView->horizontalHeader()->setSortIndicatorShown(true);
              pView->setSelectionBehavior(QAbstractItemView::SelectRows);
              for (auto col = 0; col < static_cast<int>(colSpecs.size()); ++col) {
                  const auto headerLabel = new QStandardItem(colSpecs[col].mColumnTitle);
                  headerLabel->setTextAlignment(colSpecs[col].mAlignment);
                  pModel->setHorizontalHeaderItem(col, headerLabel);
                  const auto columnWidth = std::visit(Overload{
                      [&](const QString& rSampleStr)->int {
                          if (!rSampleStr.isEmpty()) {
                              return fm.horizontalAdvance(rSampleStr);
                          }
                          return fm.horizontalAdvance(colSpecs[col].mColumnTitle);
                      },
                      [&](const auto stringLength)->int {
                          if (stringLength > 0) {
                              return stringLength * fm.averageCharWidth();
                          }
                          return fm.horizontalAdvance(colSpecs[col].mColumnTitle);
                      },
                  }, colSpecs[col].mSizeInfo);
                  // Add 20 to make room for the sort arrow.
                  pView->setColumnWidth(col, columnWidth + 20);
              }
          }
      }
      

      The problem is that when the log is displayed, it looks like this:

      enter image description here

      K Offline
      K Offline
      kshegunov
      Moderators
      wrote on 25 Feb 2024, 00:21 last edited by
      #2
      // [snip ...]
      // Add 20 to make room for the sort arrow.
      // pView->setColumnWidth(col, columnWidth + 20);
      auto header = pView->horizontalHeader();
      header->setSectionResizeMode(col, QHeaderView::Fixed);
      header->resizeSection(col, columnWidth + 20);
      

      Read and abide by the Qt Code of Conduct

      J 1 Reply Last reply 25 Feb 2024, 04:24
      1
      • K kshegunov
        25 Feb 2024, 00:21
        // [snip ...]
        // Add 20 to make room for the sort arrow.
        // pView->setColumnWidth(col, columnWidth + 20);
        auto header = pView->horizontalHeader();
        header->setSectionResizeMode(col, QHeaderView::Fixed);
        header->resizeSection(col, columnWidth + 20);
        
        J Offline
        J Offline
        johnco3
        wrote on 25 Feb 2024, 04:24 last edited by
        #3

        @kshegunov said in cannot get fixed sized columns in QTableView to work.:

        header->resizeSection(col, columnWidth + 20);

        I just tried this, unfortunately it does not work - but thank you, as after changing from 'Fixed' to 'ResizeToContents', the initial layout accept ed my column widths (strange that it would not accept Fixed - perhaps it has to do with settings fixed on the last column which really needs to be Stretch to use the remaining horizontal space? My issue was not resizing the section on the view's horizontalHeader. Thanks!!!

        // Add 20 to make room for the sort arrow.
        const auto header = pView->horizontalHeader();
        header->setSectionResizeMode(col, QHeaderView::ResizeToContents);
        header->resizeSection(col, columnWidth + 20);
        
        K 1 Reply Last reply 25 Feb 2024, 10:52
        1
        • J johnco3
          25 Feb 2024, 04:24

          @kshegunov said in cannot get fixed sized columns in QTableView to work.:

          header->resizeSection(col, columnWidth + 20);

          I just tried this, unfortunately it does not work - but thank you, as after changing from 'Fixed' to 'ResizeToContents', the initial layout accept ed my column widths (strange that it would not accept Fixed - perhaps it has to do with settings fixed on the last column which really needs to be Stretch to use the remaining horizontal space? My issue was not resizing the section on the view's horizontalHeader. Thanks!!!

          // Add 20 to make room for the sort arrow.
          const auto header = pView->horizontalHeader();
          header->setSectionResizeMode(col, QHeaderView::ResizeToContents);
          header->resizeSection(col, columnWidth + 20);
          
          K Offline
          K Offline
          kshegunov
          Moderators
          wrote on 25 Feb 2024, 10:52 last edited by
          #4

          @johnco3 said in cannot get fixed sized columns in QTableView to work.:

          perhaps it has to do with settings fixed on the last column which really needs to be Stretch to use the remaining horizontal space?

          Yes, it does. I think to make it really a fixed size you might need to set the minimum and maximum size to the same thing.

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          0

          4/4

          25 Feb 2024, 10:52

          • Login

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