Messageboxen

Oft benötigt man kleine Dialoge für Abfragen, die in Relation zu ihrem Nutzen sehr aufwändig zu erstellen sind. Diese Arbeit nimmt uns zu einem großen Teil die Klasse QMessageBox ab. Wir müssen nur noch den Titel, Text und die Buttons festlegen und den Rückgabewert prüfen. Natürlich können wir das ganze aber auch noch besser an unsere Wünsche anpassen.
Messageboxen können bereits vor der Event-Schleife der QApplication-Instanz angezeigt werden, da sie über die Methode QMessageBox::exec() ihre eigene Event-Schleife starten. Das ändert aber nichts daran, dass das QApplication-Objekt zuerst angelegt werden muss!

Messageboxen über statische Methoden

Durch statische Methoden können wir sehr schnell Messageboxen anzeigen. Gemeinsam haben sie alle einen Fenstertitel (title) und ein Parent-Widget (parent). Abhängig von der Art der Messagebox haben sie verschiedene Icons. In den meisten Fällen kann auch der Text (text) und die Buttons (buttons) selbst festgelegt werden. Hat eine Messagebox ein Parent-Widget, wird es zentral über diesem angezeigt und teilt sich mit ihm auch den Eintrag in der Taskleiste des Betriebssystems.
Folgende Methoden geben eine Meldung aus. Diese Meldung wird je nach Art der Messagebox, mit einem anderen Icon versehen. Wir können auch die in der Messagebox enthaltenen Buttons festlegen (über ein binäres Oder kombinierbar), sowie den Standard-Button der automatisch ausgewählt wird wenn die Messagebox angezeigt wird. Rückgabewert ist der gedrückte Button.

StandardButton critical( QWidget *parent, const QString& title, const QString& text, 
                         StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )
StandardButton information( QWidget *parent, const QString& title, const QString& text, 
                            StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )
StandardButton question( QWidget *parent, const QString& title, const QString& text, 
                         StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )
StandardButton warning( QWidget *parent, const QString& title, const QString& text, 
                        StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )

parent: Eltern-Widget der Messagebox, über dem sie angezeigt wird.
title: Text in der Titelleiste.
text: Text in der Messagebox.
buttons: Angezeigte Buttons, binäre Oder-Verknüpfung der folgenden Liste.
defaultButton: Standardmäßig ausgewählter Button.
Return Value: Betätigter Button.

Folgende Buttons stehen zur Auswahl:

  • QMessageBox::Ok
  • QMessageBox::Open
  • QMessageBox::Save
  • QMessageBox::Cancel
  • QMessageBox::Close
  • QMessageBox::Discard
  • QMessageBox::Apply
  • QMessageBox::Reset
  • QMessageBox::RestoreDefaults
  • QMessageBox::Help
  • QMessageBox::SaveAll
  • QMessageBox::Yes
  • QMessageBox::YesToAll
  • QMessageBox::No
  • QMessageBox::NoToAll
  • QMessageBox::Abort
  • QMessageBox::Retry
  • QMessageBox::Ignore

Über QMessageBox::NoButton wird kein Button angezeigt.
Da Messageboxen - wie bereits in der Einleitung erwähnt - ihre eigene Event-Schleife haben, können wir sie z.B. verwenden um zu fragen, ob das Programm auch wirklich gestartet werden soll:

// main.cpp
#include <QMessageBox>
#include <QPushButton>
#include <QApplication>
 
int main ( int argc, char *argv[] )
{
  QApplication app( argc, argv );
 
  QMessageBox::StandardButton ret = QMessageBox::warning( NULL,  // Kein Parent-Objekt
                             "Warnung",                          // Text in der Titelleiste
                             // Text in der Messagebox
                             "Dieses Programm befindet sich noch in der Testphase. "\
                             "Willst du es wirklich ausfuehren?",
                             // Angezeigte Buttons
                             QMessageBox::Yes | QMessageBox::No );
  // Programm beenden, falls der Benutzer den "Nein"-Button geklickt hat.
  if ( ret == QMessageBox::No )
    return 1;
 
  // Unsere "Anwendung" starten.
  QPushButton button( "Beenden" );
  QObject::connect ( &button, SIGNAL( clicked () ), &app, SLOT( quit () ) );
  button.resize( 200, 60 );
  button.show();
 
  return app.exec();
}


Messagebox-Objekte

Messagebox-Objekte zu erstellen ist zwar aufwendiger, jedoch haben wir dadurch einige zusätzliche Möglichkeiten. Unter anderem können eigene Buttons gesetzt und ein Abschnitt für Details hinzugefügt werden.

// main.cpp
#include <QMessageBox>
#include <QApplication>
 
int main ( int argc, char *argv[] )
{
  QApplication app( argc, argv );
 
  QMessageBox mBox;
  mBox.setWindowTitle( "proggen.org" );
  mBox.addButton( QMessageBox::Ok );
  mBox.setEscapeButton( QMessageBox::Ok );
  mBox.setText( "Willkommen auf proggen.org!" );
  mBox.setDetailedText( "proggen.org ist eine bisher kleine Community "\
                        "allgemein zum Thema Programmierung. Wir bereiten "\
                        "ein ausfuehrliches Tutorial zur Programmiersprache C "
                        "vor, wie auch ein Tutorial zur Websprache PHP. Im "\
                        "Forum koennen Fragen gestellt und Projekte vorgestellt "\
                        "werden." );
 
  return mBox.exec();
}

Zugeklappte Details:

Offene Details:

Anwendungsbeispiel: Qt-Quiz

Obwohl QMessageBox eine sehr einfache Klasse ist, nimmt sie uns einiges an Arbeit ab. Man kann mit ihr auch bereits einige kleine Programme erstellen, wie zum Beispiel ein Quiz.
Für die Fragen unseres Spiels legen wir uns eine einfache Hilfsklasse an:

// Question.h
#ifndef QUESTION_H
#define QUESTION_H
 
#include <QString>
 
class Question
{
 
  public:
    Question( const QString& question, const QString& answer1,
              const QString& answer2, const bool correct )
      : m_question( question ), m_answer1( answer1 ),
        m_answer2( answer2 ), m_correct( correct )
    { }
    bool isCorrect( bool answer ) { return m_correct == answer; }
    const QString& question() const { return m_question; }
    const QString& answer1() const { return m_answer1; }
    const QString& answer2() const { return m_answer2; }
 
  private:
    QString m_question;
    QString m_answer1;
    QString m_answer2;
    bool m_correct;
 
};
 
#endif // QUESTION_H

Die Funktionalität wird komplett in main implementiert:

// main.cpp
#include <QMessageBox>
#include <QApplication>
#include <QPushButton>
#include <QList>
#include "Question.h"
 
int main ( int argc, char *argv[] )
{
  QApplication app( argc, argv );
 
  // Liste aus Fragen erstellen
  QList<Question> questions;
  questions.push_back( Question( "Unter welcher Lizenz kann Qt unter anderem verwendet werden?",
                       "LGPL",
                       "MIT",
                       0 ) );
  questions.push_back( Question( "Welches Konzept wird in Qt verwendet?",
                       "Callbacks",
                       "Signale und Slots",
                       1 ) );
  questions.push_back( Question( "Welches Layout gibt es in Qt nicht?",
                       "Box-Layout",
                       "Border-Layout",
                       1 ) );
  questions.push_back( Question( "Welche Methode gibt den Ausloeser eines Slots zurueck?",
                       "sender()",
                       "getSource()",
                       0 ) );
  // ...
 
  // Messagebox aus Buttons zusammenbauen
  QMessageBox mBox;
  QPushButton answer1, answer2, quit;
  quit.setText( "Beenden" );
  mBox.addButton( &answer1 , QMessageBox::AcceptRole );
  mBox.addButton( &answer2 , QMessageBox::RejectRole );
  mBox.addButton( &quit , QMessageBox::DestructiveRole );
  // Der Button zum Beenden wird nicht angezeigt. Indem wir ihn aber als
  // "Escape-Button" festlegen, wird er beim Schließen des Fensters betätigt.
  mBox.setEscapeButton( &quit );
  quit.hide();
 
  for( int i = 0; i < questions.size(); i++ )
  {
    // Frage in die Messagebox einfügen
    mBox.setWindowTitle( "Qt-Quiz: Frage " + QString::number( i + 1 )
                         + " von " + QString::number( questions.size() ) );
    mBox.setText( questions[i].question() );
    answer1.setText( questions[i].answer1() );
    answer2.setText( questions[i].answer2() );
    // Messagebox ausführen
    mBox.exec();
    // Ausgewählten Button feststellen und darauf reagieren
    if( mBox.clickedButton() == &quit )
      return 0;
    if( !questions[i].isCorrect( mBox.clickedButton() == &answer2 ) )
    {
      QMessageBox::critical( NULL, "Fehler!",
                             "Leider eine falsche Antwort, zurueck zum Start :(",
                             QMessageBox::Ok );
      i = -1;
    }
  }
 
  QMessageBox::information( NULL, "Geschafft!",
                            "Glueckwunsch! Du hast alle Fragen richtig beantwortet :)",
                            QMessageBox::Ok );
 
  return 0;
}

In Aktion sieht das Programm so aus: