滚动

时间:2017-04-03 12:22:16

标签: qt repaint qtablewidget qtablewidgetitem qstyleditemdelegate

我之前的一个Question处理自定义的QStyledItemDelegate,其中包含QWidget并排QLabelQTableWidget

我对Joseph Ireland提供的简单解决方案非常满意。不幸的是,给定的解决方案已被破解,但我没有立即意识到这一点。如果包含QStyledItemDelegate的{​​{1}}变得太小,则会激活滚动条。

现在滚动会破坏我的单元格元素的正确绘制。这似乎是某种更新问题。在我QAbstractScollArea的视口区域周围绘制一个矩形后,我意识到了这一点。

如果您要剧烈滚动,我的表格如下所示:

Violent scrolling destroys my table

细胞内容不是在正确的位置绘制的,或者看起来根本不是绘制的。每隔一行就会发生奇怪的事情。围绕我QAbstractScrollArea的视口区域绘制的矩形更加混乱。如果窗口被重绘(隐藏/显示窗口),一切都很好。

这种更新/重绘问题的解决方案可能是什么?也许我需要在滚动完成后重新绘制?

Joseph Ireland发布的适应性解决方案是:

标题文件: 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();
}

0 个答案:

没有答案