【发布时间】:2018-11-08 07:07:09
【问题描述】:
我更改了 QToolButton 的样式表,但它不起作用,请帮助
- 我想在鼠标悬停时移除 QToolButton 的边框。 我更改了 QToolButton 的样式表
QToolButton:悬停{ 边框:无; }
QToolButton:按下{ 边框:无; }
但它显示边框底部和按钮像图像一样向左移动
【问题讨论】:
我更改了 QToolButton 的样式表,但它不起作用,请帮助
QToolButton:悬停{ 边框:无; }
QToolButton:按下{ 边框:无; }
但它显示边框底部和按钮像图像一样向左移动
【问题讨论】:
对于“热身”,我从QPushButton 开始。这个类提供了pressed()和released()这两个信号,可以用来改变图标。
testQPushButtonDownUp.cc:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// build UI
QIcon qIconBtn("dialog-info.svg");
QIcon qIconBtnDown("dialog-error.svg");
QPushButton qBtn(qIconBtn, QString::fromUtf8("Click Me."));
qBtn.show();
// install signal handlers
QObject::connect(&qBtn, &QPushButton::pressed,
[&qBtn, &qIconBtnDown]() { qBtn.setIcon(qIconBtnDown); });
QObject::connect(&qBtn, &QPushButton::released,
[&qBtn, &qIconBtn]() { qBtn.setIcon(qIconBtn); });
// runtime loop
return app.exec();
}
testQPushButtonDownUp.pro:
SOURCES = testQPushButtonDownUp.cc
QT += widgets
在 Windows 10 上的 cygwin64 中编译和测试:
$ qmake-qt5 testQPushButtonDownUp.pro
$ make && ./testQPushButtonDownUp
Qt Version: 5.9.4
这很容易。将相同的应用于QAction 有点复杂——QAction 只提供一个信号triggered()。我没有检查它是为pressed() 还是released() 发出的——这两个需要的信号之一肯定丢失了。
为了解决这个问题,我使用了QAction::associatedWidgets()
返回已添加此操作的小部件列表。
扫描此列表以查找每次出现的QToolButton(源自QAbstractButton 和QPushButton,并且)提供相同的信号。
testQToolButtonDownUp.cc:
#include <QtWidgets>
void connectAction(QAction &qCmd, const QIcon &qIconDown, const QIcon &qIconUp)
{
QList<QWidget*> pQWidgets = qCmd.associatedWidgets();
for (QWidget *pQWidget : pQWidgets) {
QToolButton *pQBtn = dynamic_cast<QToolButton*>(pQWidget);
if (!pQBtn) continue;
QObject::connect(pQBtn, &QToolButton::pressed,
[pQBtn, qIconDown]() { pQBtn->setIcon(qIconDown); });
QObject::connect(pQBtn, &QToolButton::released,
[pQBtn, qIconUp]() { pQBtn->setIcon(qIconUp); });
}
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// build UI
QToolBar qToolbar;
QIcon qIconBtn("dialog-info.svg");
QIcon qIconBtnDown("dialog-error.svg");
QAction qCmd(qIconBtn, QString::fromUtf8("Click Me."));
qToolbar.addAction(&qCmd);
qToolbar.show();
// install signal handlers
connectAction(qCmd, qIconBtnDown, qIconBtn);
// runtime loop
return app.exec();
}
testQToolButtonDownUp.pro:
SOURCES = testQToolButtonDownUp.cc
QT += widgets
在 Windows 10 上的cygwin64 中再次编译和测试:
$ qmake-qt5 testQToolButtonDownUp.pro
$ make && ./testQToolButtonDownUp
Qt Version: 5.9.4
这可行,但有点维护不友好——connectAction() 函数必须在 QAction 添加到所有小部件后调用。 (为QAction 的同一实例重复调用它可能需要额外的努力来防止QToolButton 的同一实例的重复信号处理程序。)
只要这样一个相关的小部件自动连接新的QToolButtons 就好了。 QAction 已更改。我浏览了文档。上下寻找合适的东西——没有运气。我尝试了QAction::changed() 信号是否可以提供所需的行为(尽管文档给出的希望较小)但它没有用。
最后,我决定扭转局面——即检测何时将QAction 添加到QToolButton。但是,在我的代码中,我将QAction 添加到QToolBar 和resp。 QToolButton 自动出现。因此,我制作了一个event filter,安装到qApp。此事件过滤器将接收任何事件,因此可以很好地检测添加到任何QWidget 的任何QAction。另外,我要做的就是为需要向下图标的QActions 和QToolButtons 过滤这些事件。
testQActionDownUp.cc:
#include <set>
#include <QtWidgets>
class Action: public QAction {
public:
class FilterSingleton: public QObject {
private:
std::set<Action*> _pActions;
public:
FilterSingleton(): QObject()
{
qApp->installEventFilter(this);
}
~FilterSingleton() { qApp->removeEventFilter(this); }
FilterSingleton(const FilterSingleton&) = delete;
FilterSingleton& operator=(const FilterSingleton&) = delete;
void addAction(Action *pAction)
{
_pActions.insert(pAction);
}
bool removeAction(Action *pAction)
{
_pActions.erase(pAction);
return _pActions.empty();
}
protected:
virtual bool eventFilter(QObject *pQObj, QEvent *pQEvent) override;
};
private:
static FilterSingleton *_pFilterSingleton;
private:
QIcon _qIcon, _qIconDown;
public:
Action(
const QIcon &qIcon, const QIcon &qIconDown, const QString &text,
QObject *pQParent = nullptr);
~Action();
Action(const Action&) = delete;
Action& operator=(const Action&) = delete;
private:
void addToolButton(QToolButton *pQBtn)
{
QObject::connect(pQBtn, &QToolButton::pressed,
[pQBtn, this]() { pQBtn->setIcon(_qIconDown); });
QObject::connect(pQBtn, &QToolButton::released,
[pQBtn, this]() { pQBtn->setIcon(_qIcon); });
}
};
bool Action::FilterSingleton::eventFilter(QObject *pQObj, QEvent *pQEvent)
{
if (QToolButton *pQBtn = dynamic_cast<QToolButton*>(pQObj)) {
if (pQEvent->type() == QEvent::ActionAdded) {
qDebug() << "Action::eventFilter(QEvent::ActionAdded)";
QAction *pQAction = ((QActionEvent*)pQEvent)->action();
if (Action *pAction = dynamic_cast<Action*>(pQAction)) {
pAction->addToolButton(pQBtn);
}
}
}
return QObject::eventFilter(pQObj, pQEvent);
}
Action::FilterSingleton *Action::_pFilterSingleton;
Action::Action(
const QIcon &qIcon, const QIcon &qIconDown, const QString &text,
QObject *pQParent):
QAction(qIcon, text, pQParent),
_qIcon(qIcon), _qIconDown(qIconDown)
{
if (!_pFilterSingleton) _pFilterSingleton = new FilterSingleton();
_pFilterSingleton->addAction(this);
}
Action::~Action()
{
if (_pFilterSingleton->removeAction(this)) {
delete _pFilterSingleton;
_pFilterSingleton = nullptr;
}
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// build UI
QMainWindow qWin;
QToolBar qToolbar;
QIcon qIconBtn("dialog-info.svg");
QIcon qIconBtnDown("dialog-error.svg");
Action qCmd(qIconBtn, qIconBtnDown, QString::fromUtf8("Click Me."));
qToolbar.addAction(&qCmd);
qWin.addToolBar(&qToolbar);
QToolBar qToolbar2;
qWin.setCentralWidget(&qToolbar2);
qWin.show();
QTimer qTimer;
qTimer.setInterval(5000); // 5000 ms = 5s
qTimer.start();
// install signal handlers
int i = 0;
QObject::connect(&qTimer, &QTimer::timeout,
[&i, &qToolbar2, &qCmd]() {
if (++i & 1) qToolbar2.addAction(&qCmd);
else qToolbar2.removeAction(&qCmd);
});
// runtime loop
return app.exec();
}
有一个类Action(派生自QAction)将所有必要的东西捆绑在一起。 Action 类在内部使用一个单例(Action::FilterSingleton 类),以便在 Action 的所有实例之间共享一个事件过滤器。
QTimer 用于定期向QToolBar qToolbar2 添加/删除样本Action qCmd 以测试/演示自动管理是否正常工作。
testQActionDownUp.pro:
SOURCES = testQActionDownUp.cc
QT += widgets
在 Windows 10 上的 cygwin64 中再次编译和测试:
$ qmake-qt5 testQActionDownUp.pro
$ make && ./testQActionDownUp
Qt Version: 5.9.4
【讨论】:
要删除 QToolButton 的边框,您可以使用这样的样式表(我测试它是有效的):
QToolButton { border: 0px;}
QToolButton:pressed {background-color: red;}
它是去除被按下的工具按钮的边框和填充背景。
您不能更改按下按钮的图像,因为通常我们在 QtDesignet 中的 QToolBar 上添加 QAction,并且需要更改 QAction 图像,但 QAction 没有像 QPushButton 中那样从“按下”发出信号。
但是,如果您手动将 QToolButton 添加到 QToolBar - 您可以这样做,因为 QToolButton 有信号“按下”并且具有属性“图标”。在某些连接到“按下”信号的插槽中,您可以更改它。
【讨论】: