英文:
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 QComboBox
es 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 QComboBox
es the stylesheet should apply to by using:
如果从样式表中移除hover
关键字中的一个,那么问题就能解决,但我会失去样式。我猜测在将QComboBox
用作单元格小部件时,QTableView::item
和 QComboBox
之间存在冲突,所以我尝试更明确地指定样式表应该应用于哪些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 QComboBox
es 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:
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 QComboBox
es 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 <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.
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.
答案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->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 QComboBox
es, 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 <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);
//give the address of table to the QTableWidget pointer of the eventFilter
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) {};
//I used the below pointer to point at table
//since it won't be able to access otherwise as far as I know
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论