Erweitern von QAction durch zusätzliche Signale

From Qt Wiki
Jump to: navigation, search


Einführung

QAction kann so konfiguriert werden, dass es checkable ist. Dies bedeutet, es kann einen binären Zustand, nämlich angewählt (checked) und nicht angewählt annehmen. Dies wird bspw. bei einem Pushbutton angezeigt, der runtergedrückt bleibt, nachdem man ihn einmal geklickt hat und erst wieder in den Ausgangszustand zurückkehrt, nachdem man ihn noch ein weiteres mal anklickt.

Das Problem mit QAction ist, dass es nur ein Signal sendet, wenn sich sein checked-Zustand geändert hat und in diesem Signal mit einem boolschen Attribut mitteilt, ob der Zustand nun checked ist oder nicht. Das bedeutet, wenn man eine Slot-Methode schreibt, die auf dieses Signal reagiert, muss man in diesem Slot erst gucken, wie der Zustand der QAction jetzt ist und dann kann man erst, basierend auf dieser Fallentscheidung, die gewünschte Funktion ausführen.

Es oft praktischer, wenn man 2 getrennte Signale hätte: Eins für "der Zustand ist jetzt checked" und eins für "er ist jetzt nicht checked". Weil QAction solche Signale nicht hat, bauen wir uns hier eine von QAction abgeleitete Klasse, die QAction um eben diese Signale erweitert.

Quelltext

Der Quelltext ist wirklich einfach. Dies ist die Header-Datei:

#ifndef CHECKABLEACTION_H
#define CHECKABLEACTION_H

#include <QAction>
#include <QDebug>

/*!
 * This class represents an action that will emit
 * distinct signals depending on the check of the
 * action itself.
 */
class CheckableAction : public QAction
{
 Q_OBJECT
 public:
  explicit CheckableAction(QObject *parent = 0);

 signals:
  /*!
   * This signal is emitted each time the action is
   * checked.
   */
  void actionChecked();

  /*!
   * This signal is emitted each time the action is
   * unchecked.
   */
  void actionUnchecked();

 public slots:

 private slots:
  /*!
   * This slot is used to forward (i.e., emit) a triggered
   * event depending on the status of the action (i.e., if it
   * has been checked or not).
   * checked true if the action has been checked, false
   * otherwise
   */
  void slotForwardCheckSignal( bool checked );
};

#endif // CHECKABLEACTION_H

Implementierung:

#include "checkableaction.h"

CheckableAction::CheckableAction(QObject *parent) :
 QAction(parent)
 {

  // auto connect the triggered event to the slot for
  // forwarding the check status
  connect( this, SIGNAL(triggered(bool)),
           this, SLOT(slotForwardCheckSignal(bool))
  );
}

void CheckableAction::slotForwardCheckSignal(bool checked)
{
 qDebug() << "Action checked status " << checked;

 // check the status of the action
 if( ! isCheckable() ) {
  // the action cannot be checked, simply emit
  // a triggered event
  triggered();
 } else
 if( isChecked() ) {
  // the action is checked
  emit actionChecked();
 }
 else {
  // the action is unchecked
  emit actionUnchecked();
 }
}

Beispiel zur Verwendung

Die neue Klasse wird genauso benutzt, wie eine QAction, bloß dass uns jetzt die 2 neuen Signale actionChecked() und actionUnchecked() zur Verfügung stehen.

CheckableAction *myAction = new CheckableAction( this );
myAction->setText( tr("Action TEXT") );
myAction->setIcon( QIcon(":/actions/img/myaction.png") );
myAction->setStatusTip( tr("Check/Uncheck the action") );
myAction->setCheckable( true );

connect( myAction, SIGNAL(actionChecked()),
             this, SLOT(slotActionUncheked())
       );

connect( myAction, SIGNAL(actionUnchecked()),
             this, SLOT(slotActionCheked())
       );