PyQt: Can a QPushButton be assigned a QAction?
Asked Answered
E

4

5

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?

Exserviceman answered 22/5, 2013 at 23:10 Comment(0)
M
11

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.

Monastic answered 22/5, 2013 at 23:40 Comment(3)
OK - I didn't ask about QToolButton but QPushButton, which has no setDefaultAction method, as the interpreter just told me. So sounds like you're saying that what I'm doing just won't work. It's not really an important issue, I prefer toolbars/buttons anyhow. I was just hacking around trying to write some simple GUI code without the aid of QtDesigner.Exserviceman
@Mikey That's what I'm saying. But you could do it manually anyway by subclassing QPushButton and adding a setDefaultAction method that changes everything in the button according to the action and connects the relevant button's signals to the action's slots.Monastic
Understood. I edited your answer to reflect your comments and accepted it.Exserviceman
L
4

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.

Leges answered 14/11, 2016 at 22:5 Comment(1)
Good idea, though judging from the OPs code I guess the first parameter should be self.__buttonFile and not self.__menuFile. Anyway, in PyQt5 this can be further simplified to self.__buttonFile.clicked.connect(self.__actionOpen.trigger)Stets
B
1

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()
Bakken answered 14/3, 2021 at 6:8 Comment(0)
Y
0

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()));
}
Yean answered 15/5, 2014 at 22:32 Comment(4)
I think, that class should rather be called ActionPushButton because, it derives from a button, so it's a button, not an action.Bassorilievo
I'm downvoting this answer: The question is about Python and PyQt, not C++.Exserviceman
@Vector: even if you do not understand C++, it is easy to understand the concept.Marylou
@Marylou - I understand C++. but if a question is about Python, you don't give the answer using C++. That's just wrong. You translate it to Python. The question is titled PyQt.Exserviceman

© 2022 - 2024 — McMap. All rights reserved.