Один из моих предыдущих Вопросов касается настраиваемого QStyledItemDelegate, содержащего QWidget
с двумя QLabel
рядом.
Я был очень доволен простым решением, предложенным Джозефом Айрлендом. К сожалению, данное решение сломано, но я не сразу это понял. Если QTableWidget
, содержащий мой QStyledItemDelegate
, становится слишком маленьким, активируются полосы прокрутки.
Теперь прокрутка уничтожает правильный рисунок элементов моей ячейки. Похоже, это какая-то проблема с обновлением. Я понял это после того, как нарисовал прямоугольник вокруг области просмотра моего QAbstractScollArea
.
Моя таблица выглядит следующим образом, если вы будете сильно прокручивать:
Содержимое ячеек прорисовывается не там, где надо, или вообще не прорисовывается. Странно происходит для каждой второй строки. Еще больше испортился прямоугольник, нарисованный вокруг области просмотра моего QAbstractScrollArea
. Если окно перерисовывается (скрыть/показать окно), все в порядке.
Какое может быть решение такой проблемы обновления/перекраски? Может быть, мне нужно перерисовать после завершения прокрутки?
Мое адаптированное решение, опубликованное Джозефом Айрлендом, было:
Заголовочный файл: TwoNumbersDelegate.h
#pragma once
#include <QStyledItemDelegate>
class QLabel;
class TwoNumbersDelegate : public QStyledItemDelegate {
public:
TwoNumbersDelegate(QObject* parent = nullptr);
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
private:
QLabel* mLeft;
QLabel* mRight;
QFrame* mFrame;
};
Исходный файл: TwoNumbersDelegate.cpp
#include "TwoNumbersDelegate.h"
#include <QLabel>
#include <QPainter>
#include <QDebug>
#include <QHBoxLayout>
#include <QTableWidget>
TwoNumbersDelegate::TwoNumbersDelegate(QObject* parent /*= nullptr*/) : QStyledItemDelegate(parent)
{
mLeft = new QLabel("%1");
mRight = new QLabel("%2");
mFrame = new QFrame;
mFrame->setLayout(new QHBoxLayout);
mFrame->layout()->addWidget(mLeft);
// you could add a spacer here maybe
mFrame->layout()->addWidget(mRight);
mFrame->setAttribute(Qt::WA_DontShowOnScreen, true);
mFrame->show();
}
void TwoNumbersDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
auto data = index.data(Qt::EditRole);
auto list = data.toList();
if (list.size() != 2) {
QStyledItemDelegate::paint(painter, option, index);
}
mLeft->setText(list.at(0).toString());
mRight->setText(list.at(1).toString());
mFrame->resize(option.rect.size());
qDebug() << option.rect.size();
// mFrame->layout()->invalidate();
// mFrame->layout()->activate();
if (auto tableWidget = qobject_cast<QTableWidget*>(parent())) {
auto cellRegion = QRegion(option.rect);
auto viewportRegion = QRegion(tableWidget->viewport()->rect());
auto intersectedRegion = cellRegion.intersected(viewportRegion);
intersectedRegion.translate(-option.rect.topLeft());
painter->drawRect(tableWidget->viewport()->rect().adjusted(0,0,-1,-1));
painter->save();
painter->translate(option.rect.topLeft());
mFrame->render(painter, QPoint(), intersectedRegion, QWidget::DrawChildren);
qDebug() << cellRegion << viewportRegion << intersectedRegion;
painter->restore();
}
}
QSize TwoNumbersDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return mFrame->minimumSizeHint();
}
Следующая программа послужила мне тестовым бегуном:
#include <QApplication>
#include <QTableWidget>
#include <QVBoxLayout>
#include "TwoNumbersDelegate.h"
int main(int argc, char** args) {
QApplication q(argc, args);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
//frame->setStyleSheet("QFrame { background: green}"); // Activate this to see overdrawing
auto table = new QTableWidget;
table->setAlternatingRowColors(true);
table->setItemDelegate(new TwoNumbersDelegate);
table->setRowCount(20);
table->setColumnCount(10);
for (auto iter = 0; iter < 20; iter++) {
for (auto colIter = 0; colIter < 10; colIter++) {
auto item = new QTableWidgetItem;
QVariantList map;
map << iter << iter*colIter;
item->setData(Qt::EditRole, map);
table->setItem(iter, colIter, item);
}
}
frame->layout()->addWidget(table);
frame->show();
q.exec();
}
paintEvent
tableWidget. Это (должно) решить проблему с прямоугольником. Или кpaintEvent
ViewPort, я не совсем уверен. Если это так, вам следует использовать новый класс окна просмотра и использовать метод tableviewsetViewport
. - person LoPiTaL   schedule 05.04.2017QTableWidget
все равно может быть решением. Каким-то образомpaintEvent
обрабатывается неправильно. - person Aleph0   schedule 05.04.2017