Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

As pointed out in other answered 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.

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()));
}

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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top