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. Adding QButtons to a QTableWidget Header
QtWS25 Last Chance

Adding QButtons to a QTableWidget Header

Scheduled Pinned Locked Moved Unsolved General and Desktop
1 Posts 1 Posters 856 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.
  • S Offline
    S Offline
    SlyPig
    wrote on last edited by
    #1

    I am trying to add QButtons to the header of a QTableWidget and trying to follow the guidelines here:
    qt-support-weekly-27-widgets-on-a-header
    qtablewidget-personal-widget-as-header

    The code I have works and the buttons appear in the header. The problem is that the buttons don't automatically align to the columns:
    TableHeader.png

    If I minimize the window and then display it again, the buttons are aligned, so it seems like some sort of paint/repaint problem. However, I've tried putting 'repaint' just about everywhere and can't find a fix for this. If the window is widened fairly quickly, the same alignment issue happens, but again, a minimize and redisplay fixes it.

    Here's the code I'm using. Sorry for putting so much here - this is the smallest I could get it and still show the issue. This forum doesn't allow attachments apparently. Any ideas on how to fix the button / column alignment issue is very much appreciated!

    main.cpp:

    #include "mainWindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    mainWindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QTableWidgetItem>
    #include <QPushButton>
    #include <QMessageBox>
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    const int COL_COUNT = 8;
    const int ROW_COUNT = 500;
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    protected:
        void timerEvent(QTimerEvent* event);
    
    private:
        Ui::MainWindow *ui;
    
        int _timerID; // ID of our timer event
        bool _firstTime;
        
        // List containing pointers to the buttons in the table header
        QList<QPushButton *> _hdrButton;
    
    private slots:
        void popup();
    };
    #endif // MAINWINDOW_H
    
    

    mainWindow.cpp:

    #include "mainWindow.h"
    #include "ui_mainWindow.h"
    
    // Interval on which our timer event fires (in MS)
    static const int kMonitorTimerInverval = 1000;
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
        , _timerID(0)
        , _firstTime(true)
    {
        ui->setupUi(this);
    
        ui->tableWidget->setRowCount(ROW_COUNT);
        ui->tableWidget->setColumnCount(COL_COUNT);
        ui->tableWidget->verticalHeader()->setVisible(false);
        ui->tableWidget->horizontalHeader()->setMinimumHeight(40);
    
        _hdrButton.clear();
        for (int col = 2; col < COL_COUNT; col++) // Columns 3 - 8 only
        {
            _hdrButton.append(new QPushButton);
    
            connect(_hdrButton[col - 2], SIGNAL(clicked()), this, SLOT(popup()));
    
            ui->tableWidget->SetHorizontalHeaderItemWidget(col, _hdrButton[col - 2]);
        }
    
        _timerID = startTimer(kMonitorTimerInverval); // Start the timer
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::popup()
    {
        // See which header button was clicked
        int column;
        for (column = 2; column < COL_COUNT; column++)
        {
            if (QObject::sender() == _hdrButton[column - 2])
            {
                break;
            }
        }
    
        QString msg = QString("Column\n%1").arg(column + 1);
        QMessageBox msgBox;
    
        msgBox.setWindowTitle("Status");
        msgBox.setText(msg);
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
    }
    
    void MainWindow::timerEvent(QTimerEvent* event)
    {
        if ((event->timerId() == _timerID) && _firstTime)
        {
            // No text for columns 3 - 8 since the text will be
            // in the button that's located in the header
            QStringList headerText;
            headerText << "COL 1" << "COL 2" << "" << "" << "" << "" << "" << "";
            ui->tableWidget->setHorizontalHeaderLabels(headerText);
    
            // Added text to the buttons and configure column sizing
            QString buttonText;
            for (int col = 0; col < COL_COUNT; col++)
            {
                if ((col == 0) || (col == 1)) // First two columns
                {
                    ui->tableWidget->resizeColumnToContents(col);
                }
                else // Columns 3 - 8
                {
                    buttonText = QString("Button %1").arg(col - 1);
                    ui->tableWidget->SetHorizontalHeaderItemText(col, buttonText);
                    myHeaderView::Margins buttonMargins = { 4, 4, 4, 4 };
                    ui->tableWidget->SetHorizontalHeaderItemMargins(col, buttonMargins);
                    ui->tableWidget->SetHorizontalHeaderItemResizeMode(col, QHeaderView::Stretch);
                }
            }
            ui->tableWidget->scrollToBottom();
    
            _firstTime = false;
        }
    }
    

    myTableWidget.h:

    #ifndef EU_TABLE_WIDGET_H
    #define EU_TABLE_WIDGET_H
    
    #include <QtCore/qglobal.h>
    #include <QTableWidget>
    
    #include "myHeaderView.h"
    
    class myTableWidget : public QTableWidget
    {
        public:
            myTableWidget(QWidget * parent = Q_NULLPTR);
    
            void scrollContentsBy(int dx, int dy);
            void SetHorizontalHeaderItemWidget(int column, QWidget * widget);
            void SetHorizontalHeaderItemMargins(int column, myHeaderView::Margins margins);
            void SetHorizontalHeaderItemStylesheet(int column, QString &style);
            void SetHorizontalHeaderItemText(int column, QString &text);
            void SetHorizontalHeaderItemResizeMode(int column, QHeaderView::ResizeMode mode);
    
        private:
            myHeaderView * mHorizontalHeader;
    };
    #endif // EU_TABLE_WIDGET_H
    

    myTableWidget.cpp:

    #include "myTableWidget.h"
    
    myTableWidget::myTableWidget(QWidget * parent) :
        QTableWidget(parent)
    {
        mHorizontalHeader = new myHeaderView(Qt::Orientation::Horizontal, this);
        setHorizontalHeader(mHorizontalHeader);
    }
    
    void myTableWidget::scrollContentsBy(int dx, int dy)
    {
        QTableWidget::scrollContentsBy(dx, dy);
    
        if (dx != 0)
            mHorizontalHeader->FixWidgetPositions();
    }
    
    void myTableWidget::SetHorizontalHeaderItemWidget(int column, QWidget * widget)
    {
        mHorizontalHeader->SetItemWidget(column, widget);
    }
    
    void myTableWidget::SetHorizontalHeaderItemMargins(int column, myHeaderView::Margins margins)
    {
        mHorizontalHeader->SetItemMargins(column, margins);
    }
    
    void myTableWidget::SetHorizontalHeaderItemStylesheet(int column, QString &style)
    {
        mHorizontalHeader->SetItemStylesheet(column, style);
    }
    
    void myTableWidget::SetHorizontalHeaderItemText(int column, QString &text)
    {
        mHorizontalHeader->SetItemText(column, text);
    }
    
    void myTableWidget::SetHorizontalHeaderItemResizeMode(int column, QHeaderView::ResizeMode mode)
    {
        mHorizontalHeader->setSectionResizeMode(column, mode);
    }
    

    myHeaderView.h:

    #ifndef MY_HEADER_VIEW_H
    #define MY_HEADER_VIEW_H
    
    #include <QWidget>
    #include <QHeaderView>
    #include <QPushButton>
    
    class myHeaderView : public QHeaderView
    {
        public:
            struct Margins
            {
                int left;
                int right;
                int top;
                int buttom;
    
                Margins(int left = 2, int right = 2, int top = 2, int buttom = 2);
            };
    
            myHeaderView(Qt::Orientation orientation,
                         QWidget         *parent = nullptr);
    
            void FixWidgetPositions();
            void SetItemWidget(int index, QWidget * widget);
            void SetItemMargins(int index, Margins margins);
            void SetItemStylesheet(int index, QString &style);
            void SetItemText(int index, QString &text);
            void SetItemResizeMode(int index, QHeaderView::ResizeMode mode);
    
        private:
            struct Item
            {
                QWidget * item;
                Margins margins;
    
                Item();
            };
    
            QMap<int, Item> mItems;
    
            void showEvent(QShowEvent * e);
            void HandleSectionResized(int i);
            void HandleSectionMoved(int logical, int oldVisualIndex, int newVisualIndex);
    };
    #endif // MY_HEADER_VIEW_H
    

    myHeaderView.cpp:

    #include "myHeaderView.h"
    
    myHeaderView::myHeaderView(Qt::Orientation orientation, QWidget * parent) :
        QHeaderView(orientation, parent)
    {
        connect(this, &myHeaderView::sectionResized, this, &myHeaderView::HandleSectionResized);
        connect(this, &myHeaderView::sectionMoved,   this, &myHeaderView::HandleSectionMoved);
    }
    
    
    void myHeaderView::showEvent(QShowEvent *e)
    {
        for (int i = 0; i < count(); i++)
        {
            if (!mItems[i].item)
            {
                mItems[i].item = new QWidget(this);
            }
            else
            {
                mItems[i].item->setParent(this);
            }
    
            mItems[i].item->setGeometry(sectionViewportPosition(i) + mItems[i].margins.left,
                                        mItems[i].margins.top,
                                        sectionSize(i) - mItems[i].margins.left - mItems[i].margins.right - 1,
                                        height() - mItems[i].margins.top - mItems[i].margins.buttom - 1);
            mItems[i].item->show();
        }
    
        QHeaderView::showEvent(e);
    }
    
    
    void myHeaderView::HandleSectionResized(int i)
    {
        for (int j = visualIndex(i); j < count(); j++)
        {
            int logical = logicalIndex(j);
            mItems[logical].item->setGeometry(sectionViewportPosition(logical) + mItems[i].margins.left,
                                              mItems[i].margins.top,
                                              sectionSize(logical) - mItems[i].margins.left - mItems[i].margins.right - 1,
                                              height() - mItems[i].margins.top - mItems[i].margins.buttom - 1);
        }
    }
    
    
    void myHeaderView::HandleSectionMoved(int logical, int oldVisualIndex, int newVisualIndex)
    {
        for (int i = qMin(oldVisualIndex, newVisualIndex); i < count(); i++)
        {
            logical = logicalIndex(i);
            mItems[logical].item->setGeometry(sectionViewportPosition(logical) + mItems[i].margins.left,
                                              mItems[i].margins.top,
                                              sectionSize(logical) - mItems[i].margins.left - mItems[i].margins.right - 1,
                                              height() - mItems[i].margins.top - mItems[i].margins.buttom - 1);
        }
    }
    
    
    void myHeaderView::FixWidgetPositions()
    {
        for (int i = 0; i < count(); i++)
        {
            mItems[i].item->setGeometry(sectionViewportPosition(i) + mItems[i].margins.left,
                                        mItems[i].margins.top,
                                        sectionSize(i) - mItems[i].margins.left - mItems[i].margins.right - 1,
                                        height() - mItems[i].margins.top - mItems[i].margins.buttom - 1);
        }
    }
    
    
    void myHeaderView::SetItemWidget(int index, QWidget * widget)
    {
        widget->setParent(this);
        mItems[index].item = widget;
    }
    
    
    void myHeaderView::SetItemMargins(int index, myHeaderView::Margins margins)
    {
        mItems[index].margins = margins;
    
        HandleSectionResized(index);
    }
    
    void myHeaderView::SetItemStylesheet(int index, QString &style)
    {
        mItems[index].item->setStyleSheet(style);
    }
    
    void myHeaderView::SetItemText(int index, QString &text)
    {
        reinterpret_cast<QPushButton *>(mItems[index].item)->setText(text);
    }
    
    void myHeaderView::SetItemResizeMode(int index, QHeaderView::ResizeMode mode)
    {
        reinterpret_cast<QHeaderView *>(mItems[index].item)->setSectionResizeMode(mode);
    }
    
    myHeaderView::Margins::Margins(int left, int right, int top, int buttom) :
        left(left),
        right(right),
        top(top),
        buttom(buttom)
    {
    }
    
    myHeaderView::Item::Item() :
        item(nullptr)
    {
    }
    
    1 Reply Last reply
    0
    • JonBJ JonB referenced this topic on

    • Login

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