Qt样式表中QTableView::item和cellWidget之间的冲突

huangapple go评论65阅读模式
英文:

Qt stylesheet conflict between QTableView::item and cellWidget

问题

I'm using Qt 5.15.2 on Windows. I have a QTableWidget which has a bunch of QComboBoxes as cell widgets. The application uses the following stylesheet:

QComboBox:hover{background: yellow;}
QTableView::item:hover{color: red;}

Now when showing the table and hovering over a QComboBox on the last visible row, the table starts auto-scrolling down, like so:

这个问题发生在显示表格并在最后一行上的 QComboBox 上悬停时,表格会自动向下滚动,如下所示:

If I remove either of the hover keyword from the stylesheet, then things work fine but I lose my style. My guess is that there is a conflict between QTableView::item and QComboBox when it's used as a cell widget so I've tried being more explicit about which QComboBoxes the stylesheet should apply to by using:

如果从样式表中移除hover关键字中的一个,那么问题就能解决,但我会失去样式。我猜测在将QComboBox用作单元格小部件时,QTableView::itemQComboBox 之间存在冲突,所以我尝试更明确地指定样式表应该应用于哪些QComboBox,如下所示:

QTableView QComboBox:hover{background: yellow;}
QTableView::item:hover{color: red;}

but that didn't help either. Any suggestions on how to solve this please?

但是这也没有帮助。请问有关如何解决这个问题的建议吗?

Here is the code I've used for this example:

以下是我用于这个示例的代码:

#include <QTableWidget>
#include <QBoxLayout>
#include <QComboBox>
#include <QApplication>

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

    qApp->setStyleSheet(
                "QComboBox{background: yellow;}"
                "QTableView::item:hover{color: red;}"
                        );

    auto rows = 100;
    auto cols = 5;
    auto table = new QTableWidget(rows, cols);

    for(auto i = 0; i != rows; ++i)
    {
        for(auto j = 0; j != cols; ++j)
        {
            if(j == 0)
            {
                auto item = new QTableWidgetItem("hello");
                table->setItem(i, j, item);
            }
            else
            {
                auto cb = new QComboBox();
                cb->addItems(QStringList() << "Item1" << "Item2");
                table->setCellWidget(i, j, cb);
            }
        }
    }

    table->setMinimumSize(800,600);
    table->show();
    return a.exec();
}

UPDATE

As suggested by this answer, using setAutoScroll(false) works around the issue of the autoscrolling.

根据这个 答案 的建议,使用 setAutoScroll(false) 可以解决自动滚动的问题。

Unfortunately, the table loses the ability to autoscroll when the current item changes with the directional arrows as shown below.

不幸的是,如下所示,当使用方向箭头更改当前项目时,表格失去了自动滚动的能力。

I've also just confirmed that the whole issue described in my post is not reproducible with Qt versions prior to Qt 5.15, so I'm guessing this is a Qt regression bug.

我刚刚确认,我的帖子中描述的整个问题在 Qt 5.15 之前的版本中是无法重现的,所以我猜这是 Qt 的一个回归 bug。

英文:

I'm using Qt 5.15.2 on Windows. I have a QTableWidget which has a bunch of QComboBoxes as cell widgets. The application uses the following stylesheet:

QComboBox:hover{background: yellow;}
QTableView::item:hover{color: red;}

Now when showing the table and hovering over a QComboBox on the last visible row, the table starts auto-scrolling down, like so:

Qt样式表中QTableView::item和cellWidget之间的冲突

This doesn't happen if I hover over a normal QTableWidgetItem on the last visible row as shown on the image.

If I remove either of the hover keyword from the stylesheet, then things work fine but I lose my style. My guess is that there is a conflict between QTableView::item and QComboBox when it's used as a cell widget so I've tried being more explicit about which QComboBoxes the stylesheet should apply to by using

QTableView QComboBox:hover{background: yellow;}
QTableView::item:hover{color: red;}

but that didn't help either. Any suggestions on how to solve this please?

Here is the code I've used for this example:

#include &lt;QTableWidget&gt;
#include &lt;QBoxLayout&gt;
#include &lt;QComboBox&gt;
#include &lt;QApplication&gt;

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

    qApp-&gt;setStyleSheet(
                &quot;QComboBox{background: yellow;}&quot;
                &quot;QTableView::item:hover{color: red;}&quot;
                        );

    auto rows = 100;
    auto cols = 5;
    auto table = new QTableWidget(rows, cols);

    for(auto i = 0; i != rows; ++i)
    {
        for(auto j = 0; j != cols; ++j)
        {
            if(j == 0)
            {
                auto item = new QTableWidgetItem(&quot;hello&quot;);
                table-&gt;setItem(i, j, item);
            }
            else
            {
                auto cb = new QComboBox();
                cb-&gt;addItems(QStringList() &lt;&lt; &quot;Item1&quot; &lt;&lt; &quot;Item2&quot;);
                table-&gt;setCellWidget(i, j, cb);
            }
        }
    }

    table-&gt;setMinimumSize(800,600);
    table-&gt;show();
    return a.exec();
}

UPDATE

As suggested by this answer, using setAutoScroll(false) works around the issue of the autoscrolling.

Unfortunately, the table loses the ability to autoscroll when the current item changes with the directional arrows as shown below.

I've also just confirmed that the whole issue described in my post is not reproducible with Qt versions prior to Qt 5.15, so I'm guessing this is a Qt regression bug.

Qt样式表中QTableView::item和cellWidget之间的冲突

答案1

得分: 1

Your QTableWidget 似乎在将鼠标悬停在部分可见项时会自动滚动,我的猜测是当悬停时,它将其视为选定单元格,从而导致自动滚动。

要解决此问题,您可以简单地执行以下操作:

table->setAutoScroll(false);

我将其应用于您的 MRE,并且它有效。

此解决方案背后的原因如下:

我通过使用事件过滤器得出了表格自动滚动的结论,这帮助我注意到了 QComboBoxes 的 QEvent::Move,如果它们在我不移动它们的情况下移动,那就意味着它是 "auto",因此我搜索了以下内容:

qtablewidget disable ensure visible

这随后导致了这个 答案

要绕过 "按键" 禁用的 "自动滚动",您可以使用事件过滤器来实际上切换它,以下是如何实现的:

main.cpp 中:

#include <QApplication>
#include <QTableWidget>
#include <QComboBox>
#include <QObject>
#include <QEvent>
#include "myEventFilter.h"

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

    qApp->setStyleSheet(
        "QComboBox{background: yellow;}"
        "QTableView::item:hover{color: red;}"
    );
    QString s = "della3";
    fprintf(stderr, "%s", s.toLatin1().data());

    auto rows = 100;
    auto cols = 5;
    auto table = new QTableWidget(rows, cols);

    for(auto i = 0; i != rows; ++i)
    {
        for(auto j = 0; j != cols; ++j)
        {
            if(j == 0)
            {
                auto item = new QTableWidgetItem("hello");
                table->setItem(i, j, item);
            }
            else
            {
                auto cb = new QComboBox();
                cb->addItems(QStringList() << "Item1" << "Item2");
                table->setCellWidget(i, j, cb);
            }
        }
    }

    table->setMinimumSize(800,600);
    table->setAutoScroll(false);

    myEventFilter *filter = new myEventFilter();
    table->installEventFilter(filter);
    // 将表格的地址传递给事件过滤器的 QTableWidget 指针
    filter->t = table;

    table->show();
    
    return a.exec();
}

myEventFilter.h 中:

#ifndef MYEVENTFILTER_H
#define MYEVENTFILTER_H

#include <QObject>
#include <QEvent>
#include <QTableWidget>

class myEventFilter : public QObject
{
    Q_OBJECT

public:
    myEventFilter (QObject *parent = nullptr) {};
    // 我使用下面的指针指向表格
    // 因为据我所知,否则它将无法访问
    QTableWidget *t;

protected:
    bool eventFilter(QObject *obj, QEvent *event) override
    {
        if(event->type() == QEvent::KeyPress)
        {
            t->setAutoScroll(true);
        }
        if(event->type() == QEvent::KeyRelease)
        {
            t->setAutoScroll(false);
        }

        return QObject::eventFilter(obj,event);
    };
};

#endif // MYEVENTFILTER_H
英文:

Your QTableWidget seems to be auto-scrolling when you hover a partially visible item, my guess is that it treats it as a selected cell when hovered, which causes the auto-scroll.

To fix your issue you can simply do this:

table-&gt;setAutoScroll(false);

I applied it to your MRE and it worked.

Reasoning behind this solution:

I came up with the conclusion of your table auto-scrolling by using an eventFilter, which helped me notice QEvent::Move of the QComboBoxes, and if they are moving without me moving them, that means it's auto, so I googled this:
>qtablewidget disable ensure visible

Which then led me to this answer.

Update:

to get around the auto scroll disabled for key press, you can use an event filter to basically switch in on and off, here's how:

main.cpp

#include &lt;QApplication&gt;
#include &lt;QTableWidget&gt;
#include &lt;QComboBox&gt;
#include &lt;QObject&gt;
#include &lt;QEvent&gt;
#include &quot;myEventFilter.h&quot;


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

    qApp-&gt;setStyleSheet(
        &quot;QComboBox{background: yellow;}&quot;
        &quot;QTableView::item:hover{color: red;}&quot;
        );
    QString s = &quot;della3&quot;;
    fprintf(stderr,&quot;%s&quot;, s.toLatin1().data());

    auto rows = 100;
    auto cols = 5;
    auto table = new QTableWidget(rows, cols);

    for(auto i = 0; i != rows; ++i)
    {
        for(auto j = 0; j != cols; ++j)
        {
            if(j == 0)
            {
                auto item = new QTableWidgetItem(&quot;hello&quot;);
                table-&gt;setItem(i, j, item);
            }
            else
            {
                auto cb = new QComboBox();
                cb-&gt;addItems(QStringList() &lt;&lt; &quot;Item1&quot; &lt;&lt; &quot;Item2&quot;);
                table-&gt;setCellWidget(i, j, cb);
            }
        }
    }

    table-&gt;setMinimumSize(800,600);
    table-&gt;setAutoScroll(false);

    myEventFilter *filter = new myEventFilter();
    table-&gt;installEventFilter(filter);
    //give the address of table to the QTableWidget pointer of the eventFilter
    filter-&gt;t=table;

    table-&gt;show();
    
    return a.exec();
}

myEventFilter.h

#ifndef MYEVENTFILTER_H
#define MYEVENTFILTER_H

#include &lt;QObject&gt;
#include &lt;QEvent&gt;
#include &lt;QTableWidget&gt;

class myEventFilter : public QObject
{
    Q_OBJECT

public:
    myEventFilter (QObject *parent = nullptr) {};
    //I used the below pointer to point at table
    //since it won&#39;t be able to access otherwise as far as I know
    QTableWidget *t;

protected:
    bool eventFilter(QObject *obj, QEvent *event) override
    {
        if(event-&gt;type() == QEvent::KeyPress)
        {
            t-&gt;setAutoScroll(true);
        }
        if(event-&gt;type() == QEvent::KeyRelease)
        {
            t-&gt;setAutoScroll(false);
        }

        return QObject::eventFilter(obj,event);
    };
};

#endif // MYEVENTFILTER_H

huangapple
  • 本文由 发表于 2023年4月4日 16:18:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75927032.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定