Search code examples
c++qtqtablewidgetqtstylesheetsqpalette

Selection color for QTableWidget cell is different if custom cellwidget is used


I wrote a custom table widget which is derived from QTableWidget. The last two columns in this widget use a custom cell widget (one containing a QCheckBox, the other a QLineEdit, with some optional QPushButtons).

Now, I added the option to color the table widget rows in a darker blue or orange color, depending on whether the checkbox is checked or not.

The code for this basically looks like the following:

// Color the standard tablewidget cells
for (auto j = 0; j < FIRST_FOUR_COLUMNS; j++) {
    tableWidget->item(i, j)->setBackground(isCheckedColor);
}

QPalette palette;
palette.setColor(QPalette::Base, isCheckedColor);
// For the push buttons
palette.setColor(QPalette::Button, buttonColor);

// Now color the cell widgets
tableWidget->cellWidget(i, COL_CHECKBOX)->setAutoFillBackground(true);
tableWidget->cellWidget(i, COL_LINE_EDIT)->setAutoFillBackground(true);
tableWidget->cellWidget(i, COL_CHECKBOX)->setPalette(palette);
tableWidget->cellWidget(i, COL_LINE_EDIT)->setPalette(palette);

It works fine. However, the following occurs if a row is now selected:

Orange row

Blue row

The upper image shows a selected orange row, while the lower image shows a selected blue row. As you might see, the highlighting color for the last two columns is different compared to the other, standard table widget cells.

However, I want all of it to look the same.

What I tried so far was:

  • Changing the background color via a custom stylesheet (for example):
    tableWidget->setStyleSheet("QTableWidget::item{ selection-background-color:#ff0000; }");
  • subclassing QItemDelegate and overriding the paint-method to display my own colors.

Alternatives were discussed here.

But none of that worked so far, still the same problems.

How do I solve this problem?

A minimal example to reproduce the problem:

#include <QApplication>
#include <QHBoxLayout>
#include <QMainWindow>
#include <QTableWidget>
#include <QWidget>

int
main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // Setup widgets
    auto* const tableWidget = new QTableWidget(1, 2);
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    tableWidget->setItem(0, 0, new QTableWidgetItem());
    auto *const cellWidget = new QWidget;
    tableWidget->setCellWidget(0, 1, cellWidget);

    // Apply palette color
    QPalette palette;
    palette.setColor(QPalette::Base, QColor(255, 194, 10, 60));
    tableWidget->item(0, 0)->setBackground(palette.color(QPalette::Base));
    tableWidget->cellWidget(0, 1)->setAutoFillBackground(true);
    tableWidget->cellWidget(0, 1)->setPalette(palette);

    // Layout and main window
    auto* const mainWindow = new QMainWindow;
    auto* const layout = new QHBoxLayout;
    layout->addWidget(tableWidget);
    mainWindow->setCentralWidget(tableWidget);
    mainWindow->show();

    return app.exec();
}

CMake:

cmake_minimum_required(VERSION 3.8)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

project(ExampleProject LANGUAGES CXX)

find_package(QT NAMES Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt5 COMPONENTS Widgets REQUIRED)

add_executable(ExampleProject
    ${CMAKE_CURRENT_LIST_DIR}/main.cpp
)

target_link_libraries(ExampleProject
    PRIVATE Qt::Widgets
)

Solution

  • I found a solution (or more of a workaround):
    As pointed out in the comments, the problem is caused by the cell widget's alpha values. Since this value is not the maximum alpha value, the row selection and cell widget's background color are blended, creating a different highlighting color compared to the other columns.
    A first, quick solution is to set the alpha value for the cell widgets to 0 so that the blending is prevented:

    connect(tableWidget, &QTableWidget::itemSelectionChanged, this, [tableWidget] {
        const auto selectedRows = tableWidget->selectionModel()->selectedRows();
    
        for (const auto& selectedModel : selectedRows) {
            const auto row = selectedModel.row();
    
            auto palette = tableWidget->cellWidget(row, COL_CELL_WIDGET)->palette();
            auto color = palette.color(QPalette::Base);
            color.setAlpha(0);
            palette.setColor(QPalette::Base, color);
    
            tableWidget->cellWidget(row, COL_CELL_WIDGET)->setPalette(palette);
        }
    });
    

    Keep in mind however, that once the item selection changes again or items are unselected, the color values for the rows which were selected before need to be changed to their old values.