Icons for various states of QPushbutton etc.
How do set the icon for a QPushButton or QToolbutton for when it is off and for when it is toggled.
btn1 = QPushButton("Test")
icon1 = QIcon("normal.png")
icon2 = QIcon("toggled.png")
# set the icon for when btn1.toggled returns True
# and when btn1.toggled returns False
Creating a QPushbutton with three states
I want to create a qpushbutton that can have three states. I am using the button in a media player I am creating. These are the states I want the button to have:
normal (repeat off)
toggled state 1 (repeat all)
toggled state 2 (repeat one)
Upon research I've realised I may have to override QAbstractButton.nextCheckState. The trouble is that the is no signature for the method in the documentation. I therefore have no idea on how to override it or even if the is a state property to set or modify.
Any help will be appreciated.
You can use a simple way of checking the checked flag of a pushbutton on the clicked() signal.
connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(buttonClicked(bool)));
And in your code, define a slot as buttonClicked(bool checked) and implement it as:
void MainWindow::buttonClicked(bool checked)
{
if ( checked )
ui->pushButton->setIcon(QIcon(":/on.png"));
else
ui->pushButton->setIcon(QIcon(":/off.png"));
}
This can be implemented for a QToolbutton as well accordingly.
And please note the icons in here are used from the resources. So, it's better to add your icons to the resources file.
I don't know about QAbstractButton.nextCheckState, but I suggest making use of Qt's signal/slot mechanism.
Whenever the state of repeat mode changes in the model, emit a signal like notifyModeChanged. Connect a slot to that signal in which the state (e.g. the icon) of the button is set as required.
I put together a quick example with everything contained in the MainWindow class. In a real application one would divide the code at least into model and view. The example is based on the auto-generated project of QtCreator's new project wizard. In Design view, I added a QPushButton.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "ui_mainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) :
QMainWindow(parent),
ui(new Ui::MainWindow),
icon1("icon1.png"),
icon2("icon2.png"),
icon3("icon3.png")
{
ui->setupUi(this);
ui->pushButton->setIcon(icon2);
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::changeMode);
connect(this, &MainWindow::notifyModeChanged, this, &MainWindow::modeChanged);
}
~MainWindow() {
delete ui;
}
signals:
void notifyModeChanged();
public slots:
void changeMode() {
mode = (mode + 1) % 3;
emit notifyModeChanged();
}
void modeChanged() {
switch (mode) {
case 0: ui->pushButton->setIcon(icon1); break;
case 1: ui->pushButton->setIcon(icon2); break;
case 2: ui->pushButton->setIcon(icon3); break;
}
}
private:
Ui::MainWindow *ui;
QIcon icon1;
QIcon icon2;
QIcon icon3;
int mode{0};
};
#endif // MAINWINDOW_H
Related
I would like to have the OK button of all the QMessageBox of my GUI (which is quite complex and so there are a lot of them) set a different color with respect to the other buttons (Cancel, No etc.).
I don't want to set its color every time I create a new QMessageBox but I would like to set it through the stylesheet of my application once and for all.
I tried different options but none of them worked:
- QMessageBox#okButton {background-color:blue}
- QMessageBox::okButton {...}
- QMessageBox:okButton {...}
- QMessageBox#ok-button {...}
- QMessageBox QPushButton#okButton {...}
and others...
Is there a way or do I have to give up?
A possible solution is to set the objectName() to be a selector for each button and for this you can use the notify() method of the QApplication:
from PySide2.QtCore import QEvent
from PySide2.QtWidgets import *
class Application(QApplication):
def notify(self, receiver, event):
if isinstance(receiver, QMessageBox) and event.type() == QEvent.Show:
for button in receiver.buttons():
sb = receiver.standardButton(button)
if not button.objectName():
button.setObjectName(sb.name.decode())
button.style().unpolish(button)
button.style().polish(button)
return super().notify(receiver, event)
def main():
app = Application()
app.setStyle("fusion")
app.setStyleSheet(
"""
QPushButton#Ok { background-color: green }
QPushButton#Cancel { background-color: red }
"""
)
QMessageBox.critical(
None, "Title", "text", buttons=QMessageBox.Ok | QMessageBox.Cancel
)
msgBox = QMessageBox()
msgBox.setText("The document has been modified.")
msgBox.setInformativeText("Do you want to save your changes?")
msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msgBox.exec_()
if __name__ == "__main__":
main()
Unfortunately, there's no direct solution, since QDialogButtonBox (which is what QMessageBox uses for its buttons) doesn't provide selectors for button roles.
For staticly created messagebox, the only way is to use the [text="button text"] selector, but that would just be a guess, which could change depending on the localization and the style (which could set a mnemonic, and you cannot even know what that would be for sure). Also, this requires setting the stylesheet for the QApplication.
A possible application wide stylesheet for these situations would look like this:
app.setStyleSheet('''
QDialogButtonBox > QPushButton[text="&OK"] {
background-color: orange;
}
QDialogButtonBox > QPushButton[text="&Cancel"] {
background-color: green;
}
''')
Note that I used the Parent > Class selector in order to ensure that only buttons of QDialogButtonBox are styled with those rules, otherwise any "Ok" button would be orange, etc.
Nonetheless, in the case above on my computer it only works for the Ok button, since my localization (Italian) uses "&Annulla" for the other.
On the other hand, if you're creating QMessageBox instances, there's more freedom and flexibility using selectors based on object names.
The only issue is that since the object name is set after the creation, the stylesheet is not applied, so the buttons must be "unpolished" after instantiation.
A simple subclass could provide a standard interface without complicating things too much:
class ColoredMessageBox(QtWidgets.QMessageBox):
StandardNames = {
QtWidgets.QMessageBox.Ok: 'Ok',
QtWidgets.QMessageBox.Cancel: 'Cancel',
QtWidgets.QMessageBox.Save: 'Save',
# ...
}
def exec_(self):
for button in self.buttons():
objName = self.StandardNames.get(self.standardButton(button))
if objName:
button.setObjectName(objName)
self.style().unpolish(button)
return super().exec_()
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet('''
QMessageBox > QDialogButtonBox > QPushButton#Ok {
background-color: orange;
}
QMessageBox > QDialogButtonBox > QPushButton#Cancel {
background-color: blue;
}
''')
w = ColoredMessageBox(QtWidgets.QMessageBox.Information, 'Hello', 'How are you?',
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
w.exec_()
Consider the following PyQt program,
import sys
from PyQt5 import QtCore, QtWidgets
class dockdemo(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(dockdemo, self).__init__(parent)
self.items = QtWidgets.QDockWidget("Dockable", self)
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItem("item1")
self.listWidget.addItem("item2")
self.listWidget.addItem("item3")
self.items.setWidget(self.listWidget)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
self.setWindowTitle("Dock demo")
def main():
app = QtWidgets.QApplication(sys.argv)
ex = dockdemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This works fine and produces a simple, docked window:
However, this isn't obeying my GTK2 dark platform theme. If I force Qt to do so by setting QT_QPA_PLATFORMTHEME=gtk2, I instead get this:
The docked window's controls are almost the same colour as the background so they're very difficult to see.
GNU Octave in C++ shows its own docked widgets controls correctly in the platform theme:
Octave's docked widgets also show the right controls when not using the system theme.
I suspect it's probably due to some of the CSS it's setting here, but I don't know exactly what: http://hg.savannah.gnu.org/hgweb/octave/file/6d0585c8ee11/libgui/src/octave-dock-widget.cc#l123
Am I doing something wrong? It feels like a bug that Qt isn't properly setting the colours for the docked window's controls unless you do something extra (and what that extra might be, I don't know yet).
Thanks to another answer here, I have a complete solution for my original problem as stated.
It appears that Qt simply hardcodes those icons without regard to the theme, but this is simple to fix.
First, we use the relative luminance to decide if a colour is bright or not,
def is_dark(qt_colour):
r, g, b = qt_colour.red(), qt_colour.green(), qt_colour.blue()
luminance = (0.2126*r + 0.7152*g + 0.0722*b)/256
return luminance < 0.5
and then we grab some icons that are identical but coloured dark and light. I just grabbed Octave's own set of icons:
widget-close-light.svg
widget-undock-light.svg
widget-close.svg
widget-undock.svg
found in its source tree. We place these icons in an img/ subdirectory/subfolder.
Then, we grab the widget's background colour,
bg_colour = self.items.palette().color(QtGui.QPalette.Background)
and depending on that colour, we set the CSS to use the light or the dark set of icons:
if is_dark(bg_colour):
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close-light.svg);
titlebar-normal-icon: url(img/widget-undock-light.svg);
}
"""
)
else:
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close.svg);
titlebar-normal-icon: url(img/widget-undock.svg);
}
"""
)
This results in proper icons in both light and dark themes!
The complete code now looks like this:
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
def is_dark(qt_colour):
r, g, b = qt_colour.red(), qt_colour.green(), qt_colour.blue()
luminance = (0.2126*r + 0.7152*g + 0.0722*b)/256
return luminance < 0.5
class dockdemo(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(dockdemo, self).__init__(parent)
self.items = QtWidgets.QDockWidget("Dockable", self)
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItem("item1")
self.listWidget.addItem("item2")
self.listWidget.addItem("item3")
self.items.setWidget(self.listWidget)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
bg_colour = self.items.palette().color(QtGui.QPalette.Background)
if is_dark(bg_colour):
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close-light.svg);
titlebar-normal-icon: url(img/widget-undock-light.svg);
}
"""
)
else:
self.items.setStyleSheet(
"""
QDockWidget
{
titlebar-close-icon: url(img/widget-close.svg);
titlebar-normal-icon: url(img/widget-undock.svg);
}
"""
)
self.setWindowTitle("Dock demo")
def main():
app = QtWidgets.QApplication(sys.argv)
ex = dockdemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Unfortunately the Linux-default Qt Fusion style dock icons are hard-coded as XPM format images in the QFusionStyle (and also in QCommonStyle which is the fallback). And they are never colored to match the theme. A lot of the "standard" icons are like that but many are colored/opaque so the background doesn't make a big difference.
To override them you will need to either use CSS or a custom QProxyStyle.
You can see how it is done in CSS from that example you linked to.
QDockWidget
{
titlebar-close-icon: url(close.svg);
titlebar-normal-icon: url(restore.svg);
}
A custom QStyle is a little more involved...
class AppStyle : public QProxyStyle
{
public:
using QProxyStyle::QProxyStyle;
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override
{
switch (standardIcon) {
case SP_TitleBarNormalButton:
return QIcon("restore.svg");
case SP_TitleBarCloseButton:
case SP_DockWidgetCloseButton:
return QIcon("close.svg");
default:
return baseStyle()->standardIcon(standardIcon, option, widget);
}
}
QPixmap standardPixmap(StandardPixmap stdPixmap, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override
{
switch (stdPixmap) {
case SP_TitleBarNormalButton:
case SP_TitleBarCloseButton:
case SP_DockWidgetCloseButton:
return standardIcon(stdPixmap, option, widget).pixmap(option->rect.size());
default:
return baseStyle()->standardPixmap(stdPixmap, option, widget);
}
}
};
In both cases you'd need to know the theme being used somehow (eg. that it is dark). You'd use different (or dynamic) CSS for each theme, or your custom QProxyStyle would return the correct icon for the base color. In C++ for example you could even determine if the current palette background is dark (low color value) and then return different icons based on that.
P.S. Yes it could probably be considered a "bug" or deficiency that Qt doesn't handle this "automagically" already for dark system themes -- it is also quite annoying when trying to skin an app to be dark regardless of the desktop theme. But c'est la vie.
P.P.S. Whoops, just realized I gave a C++ example for a Python question... I don't use Python with Qt so I'm afraid that's the best I can do.
I want to click on the builtin (enabling) checkbox of a QGroupBox programmatically during testing with pytest-qt.
But i can't find out how to access the underlying checkbox widget of the groupbox via an attribute or similar methods.
Basically i could just use the .setChecked(True) method in my test but this would not be a "real" mouse click.
Is there a to access the checkbox widget of the groupbox directly?
Click action involves pressButton and releaseButton mouse events. So we can emulate click action by sending two sequential events to the destination widget.
Widget::Widget(QWidget* parent)
: QWidget(parent)
, m_groupBox(new QGroupBox)
{
m_groupBox->setCheckable(true);
QPushButton* generateClickButton = new QPushButton("generate click");
connect(generateClickButton, &QPushButton::clicked, [this]
{
clickAt(m_groupBox, Qt::LeftButton);
});
setLayout(new QVBoxLayout);
layout()->addWidget(m_groupBox);
layout()->addWidget(generateClickButton);
resize(100, 100);
}
Widget::~Widget()
{}
void Widget::clickAt(QWidget* receiver, Qt::MouseButton button)
{
if (receiver)
{
QMouseEvent pressEvent(QEvent::MouseButtonPress, receiver->pos(), button, 0, 0);
QMouseEvent releaseEvent(QEvent::MouseButtonRelease, receiver->pos(), button, 0, 0);
QApplication::sendEvent(receiver, &pressEvent);
QApplication::sendEvent(receiver, &releaseEvent);
}
}
Better alternative: QTest::mouseClick does the same
I have been trying to work with Qt Virtual Keyboard and it has been going pretty good, until...
The problem is:
Environment variables being set. (kinda check)
QT_VIRTUALKEYBOARD_STYLE(not found). I've already created my own style, from another stackoverflow post, seems pretty good, but it's not being found.
WARNING: Cannot find style
".../INTERACT/interact-ii/tools/en_GB/customkb.qml" -
fallback: "default"
Some attempts:
Have put the customkeyboard.qml alone file inside my own project and set the variable to its path.
Have put the whole folder "en_GB" from the default Qt folder inside my project with my modification.
Have also set the variable with the original path from the Qt folder with my style.
Downloaded Qt 5.8/5.7/5.6 and did the same for all the qtvirtualkeyboard.
After seen the above error (fallback: "default") I tried to add my qml items to the default.qml from the qt folder. [.../Qt/5.8/Src/qtvirtualkeyboard/src/virtualkeyboard/content/styles/default]
Have opened the qtvirtualkeyboard.so file with QTCreator and build all after changing my qml files also to see if it would change something and nothing changed.
None of them seems to modify my keyboard size and location.
Here are the files that matter with a small example.
1 - Small example using the keyboard.
import os
import sys
from PyQt5.QtCore import QProcessEnvironment
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
os.environ["QT5DIR"] = "/home/epson/Qt/5.8/gcc_64"
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = "/home/epson/Qt/5.8/gcc_64/plugins/platforms"
os.environ["QT_PLUGIN_PATH"] = "/home/epson/Qt/5.8/gcc_64/plugins"
os.environ["QML_IMPORT_PATH"] = "/home/epson/Qt/5.8/gcc_64/qml"
os.environ["QML2_IMPORT_PATH"] = "/home/epson/Qt/5.8/gcc_64/qml"
os.environ["QT_VIRTUALKEYBOARD_LAYOUT_PATH"] = "/home/epson/INTERACT/interact-ii/tools/en_GB/customkb.qml"
os.environ["QT_VIRTUALKEYBOARD_STYLE"] = "/home/epson/Qt/5.8/Src/qtvirtualkeyboard/src/virtualkeyboard/content/styles"
os.environ["QT_IM_MODULE"] = "qtvirtualkeyboard"
for i in QProcessEnvironment.systemEnvironment().keys():
print(i)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.line_edit = None
self.init_ui()
def init_ui(self):
self.line_edit = QLineEdit()
self.line_edit2 = QLineEdit()
self.layout = QVBoxLayout()
self.main_widget = QWidget()
self.main_widget.setLayout(self.layout)
self.layout.addWidget(self.line_edit)
self.layout.addWidget(self.line_edit2)
self.setCentralWidget(self.main_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
2 - My customkeyboard.qml
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.0
import QtQuick.Window 2.2
import QtQuick.VirtualKeyboard 2.1
import "content"
Item {
width: 1280
height: 720
Item {
id: appContainer
width: Screen.width < Screen.height ? parent.height : parent.width
height: Screen.width < Screen.height ? parent.width : parent.height
anchors.centerIn: parent
rotation: Screen.width < Screen.height ? 90 : 0
Basic {
id: virtualKeyboard
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: inputPanel.top
}
/* Handwriting input panel for full screen handwriting input.
This component is an optional add-on for the InputPanel component, that
is, its use does not affect the operation of the InputPanel component,
but it also can not be used as a standalone component.
The handwriting input panel is positioned to cover the entire area of
application. The panel itself is transparent, but once it is active the
user can draw handwriting on it.
*/
HandwritingInputPanel {
z: 79
id: handwritingInputPanel
anchors.fill: parent
inputPanel: inputPanel
Rectangle {
z: -1
anchors.fill: parent
color: "black"
opacity: 0.10
}
}
/* Container area for the handwriting mode button.
Handwriting mode button can be moved freely within the container area.
In this example, a single click changes the handwriting mode and a
double-click changes the availability of the full screen handwriting input.
*/
Item {
z: 89
visible: handwritingInputPanel.enabled && Qt.inputMethod.visible
anchors { left: parent.left; top: parent.top; right: parent.right; bottom: inputPanel.top; }
HandwritingModeButton {
id: handwritingModeButton
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 10
floating: true
flipable: true
width: 76
height: width
state: handwritingInputPanel.state
onClicked: handwritingInputPanel.active = !handwritingInputPanel.active
onDoubleClicked: handwritingInputPanel.available = !handwritingInputPanel.available
}
}
/* Keyboard input panel.
The keyboard is anchored to the bottom of the application.
*/
InputPanel {
id: keyboard;
y: screenHeight; // position the top of the keyboard to the bottom of the screen/display
anchors.left: parent.left;
anchors.right: parent.right;
states: State {
name: "visible";
when: keyboard.active;
PropertyChanges {
target: keyboard;
// position the top of the keyboard to the bottom of the text input field
y: textInput.height;
}
}
transitions: Transition {
from: ""; // default initial state
to: "visible";
reversible: true; // toggle visibility with reversible: true;
ParallelAnimation {
NumberAnimation {
properties: "y";
duration: 250;
easing.type: Easing.InOutQuad;
}
}
}
}
}
}
QUESTION:
Am I doing things wrongly about setting STYLE and LAYOUT variables? Which one of them both should I really been setting up, is it the STYLE or the LAYOUT variable that would change the size and location of my keyboard? Where should I really put the qml file? What am I doing wrong? Can't see what is the problem!!
Obs: Even following this post couldn't make it work. Did everything exactly the same but seems something is missing or I'm misunderstanding something.
I believe you are confusing layouts for styles which is creating several problems for you.
Layouts
The .qml files in the en_GB directory are what Qt uses for the keyboard layout.
To include your custom layouts, you must point the QT_VIRTUALKEYBOARD_LAYOUT_PATH var to the directory you created for your custom layouts (e.g. QT_VIRTUALKEYBOARD_LAYOUT_PATH=/path/to/custom/keyboard-layout/mycustomlayout). Then, to add a custom layout for British English, you would create a en_GB directory in /path/to/custom/keyboard-layout/mycustomlayout. In your en_GB directory, you should have, at the very least, main.qml.
You have named your file customkeyboard.qml. In order for Qt to correctly locate, load, and process your custom layout, you must follow the file naming convention of the default layouts (i.e. main.qml, handwriting.qml, symbols.qml), as referenced here.
Styles
For custom styles, you must put your custom style directory in $$[QT_INSTALL_QML]/QtQuick/VirtualKeyboard/Styles, as referenced here. Obviously, your custom style.qml file goes in your custom style directory.
Hopefully that helps clarify some things for you.
Using Python 3.2x and PyQT 4.8x:
I initialized an action and assigned to a menu item:
self.__actionOpen = QtGui.QAction(self.__mw)
self.__actionOpen.setObjectName("actionOpen")
self.__actionOpen.setText("OpenFile")
QtCore.QObject.connect(self.__actionOpen, QtCore.SIGNAL("triggered()"), self.__accessFile)
self.__menuFile.addAction(self.__actionOpen)
Works fine - menu item is there with caption "OpenFile" and the action signal/slot is invoked.
I tried it with a QPushButton - same QAction object:
self.__buttonFile.addAction(self.__actionOpen)
Nothing: No caption on the button, nothing happens when it's clicked.
Do actions not work with QButton (the addAction call did not complain...)? Or is there something wrong with my code? Perhaps the "triggered()" signal is not appropriate for an action that interacts with QPushButton?
You can't assign a QAction to a QPushButton the way you want. QPushButton doesn't redefine addAction so the behavior comes from QWidget.addAction which adds the action to the context menu of the button.
You can however assign the action to a QToolButton with setDefaultAction which will change the button caption and trigger the action when clicked.
Or you could do it manually anyway by subclassing QPushButton and adding a setDefaultAction method that would change everything in the button according to the action (caption, tooltip...) and connects the relevant button's signals to the action's slots.
Adding an action won't "run" the action when the button is clicked, and that is by design.
If what you are after is to reuse or refer the QAction's behaviour you can just connect the clicked() signal of the QPushButton to the trigger() of the QAction:
QtCore.QObject.connect(self.__menuFile,
QtCore.SIGNAL("clicked()"),
self.__actionOpen.trigger)
That way the self.__actionOpen action will be triggered whenever the self.menuFile button is clicked.
My solution for this issue:
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QPushButton
class QActingPushButton(QPushButton):
"""QPushButtons don't interact with their QActions. This class triggers
every `QAction` in `self.actions()` when the `clicked` signal is emitted.
https://stackoverflow.com/a/16703358
"""
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.clicked.connect(self.trigger_actions)
#pyqtSlot()
def trigger_actions(self) -> None:
for act in self.actions():
act.trigger()
You could create a PushButtonAction:
h file:
#ifndef PUSHBUTTONACTION_H
#define PUSHBUTTONACTION_H
#include <QAction>
#include <QPushButton>
class PushButtonAction: public QPushButton
{
Q_OBJECT
public:
PushButtonAction(QAction *action, QWidget *parent = 0);
};
#endif // PUSHBUTTONACTION_H
cpp file:
#include "pushbuttonaction.h"
PushButtonAction::PushButtonAction(QAction *action, QWidget *parent):
QPushButton(parent)
{
setIcon(action->icon());
setText(action->text());
connect(this, SIGNAL(clicked()), action, SLOT(trigger()));
}