4

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?

Vector
  • 10,879
  • 12
  • 61
  • 101

4 Answers4

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.

alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • 1
    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. – Vector May 22 '13 at 23:52
  • @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. – alexisdm May 23 '13 at 00:30
  • Understood. I edited your answer to reflect your comments and accepted it. – Vector May 23 '13 at 00:44
3

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.

RubenLaguna
  • 21,435
  • 13
  • 113
  • 151
  • 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)` – f0xdx Oct 31 '17 at 02:02
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()
Daniel Diniz
  • 175
  • 8
-1

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()));
}
mabg
  • 1,894
  • 21
  • 28
  • I think, that class should rather be called `ActionPushButton` because, it derives from a button, so it's a button, not an action. – Tilman Vogel May 15 '14 at 22:40
  • 3
    I'm downvoting this answer: The question is about Python and PyQt, not C++. – Vector May 16 '14 at 06:26
  • 1
    @Vector: even if you do not understand C++, it is easy to understand the concept. – antoyo Jul 18 '15 at 19:23
  • 4
    @antoyo - 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. – Vector Jul 18 '15 at 23:38