Reputation: 165
i changed stylesheet for QToolButton but it is not working, please help
QToolButton:hover{ border: none; }
QToolButton:pressed{ border: none; }
but it display border bottom and button move to left like image
Upvotes: 3
Views: 2198
Reputation: 20151
For a “Warm-up”, I started with a QPushButton
. This class provides the signals pressed()
and released()
which can be used to change the icon resp.
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
Compiled and tested in cygwin64 on Windows 10:
$ qmake-qt5 testQPushButtonDownUp.pro
$ make && ./testQPushButtonDownUp
Qt Version: 5.9.4
This was easy. Applying the same to QAction
is a bit more complicated – QAction
provides only one signal triggered()
. I didn't check whether it's emitted for pressed()
or released()
– one of the both needed signals is surely missing.
To solve this, I used QAction::associatedWidgets()
which
Returns a list of widgets this action has been added to.
This list is scanned for every occurrence of QToolButton
which (is derived from QAbstractButton
as well as QPushButton
and) provides the same signals.
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
Compiled and tested again in cygwin64 on Windows 10:
$ qmake-qt5 testQToolButtonDownUp.pro
$ make && ./testQToolButtonDownUp
Qt Version: 5.9.4
This works but is a bit maintenance-unfriendly – the connectAction()
function has to be called after the QAction
has been added to all widgets. (Double-calling it for the same instance of QAction
might need additional effort to prevent duplicated signal handlers for the same instance of QToolButton
.)
It would be nice to connect new QToolButton
s automatically as soon as the associated widgets of such a resp. QAction
have been changed. I scrolled through the doc. up and down to find something appropriate – without luck. I tried whether the QAction::changed()
signal might provide the required behavior (although the doc. gave less hope) but it didn't work.
Finally, I decided to turn it around – i.e. detecting when a QAction
is added to a QToolButton
. However, in my code I add the QAction
to a QToolBar
and the resp. QToolButton
appears automatically. Thus, I made an event filter, installed to qApp
. This event filter will receive any event and, hence, is good to detect any QAction
added to any QWidget
. All I've to do additionally, is to filter these events for QAction
s and QToolButton
s where the down-up icons are required for.
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();
}
There is a class Action
(derived from QAction
) to bundle everything necessary together. The class Action
uses internally a singleton (of class Action::FilterSingleton
), so that one event filter is shared between all instances of Action
.
A QTimer
is used to add/remove the sample Action qCmd
periodically to QToolBar qToolbar2
to test/demostrate whether the auto-management works properly.
testQActionDownUp.pro
:
SOURCES = testQActionDownUp.cc
QT += widgets
Compiled and tested again in cygwin64 on Windows 10:
$ qmake-qt5 testQActionDownUp.pro
$ make && ./testQActionDownUp
Qt Version: 5.9.4
Upvotes: 3
Reputation: 133
For remove border of QToolButton you can use style sheet like this ( i tested it is work ):
QToolButton { border: 0px;}
QToolButton:pressed {background-color: red;}
It is remove border and fill background of pressed tool button.
You can not change image of pressed button because usally we add QAction on QToolBar in QtDesignet, and need to change QAction image, but QAction have not signal from "pressed" like in QPushButton.
But if you adding QToolButton to QToolBar manually - you can do that, because QToolButton have signal "pressed" and have property "icon". In some slot connected to "pressed" signal you can change it.
Upvotes: 1