Dialoge selbst erstellen

Im vorherigen Kapitel haben wir gesehen wie wir vordefinierte Dialoge verwenden können. Diese Dialoge werden häufig benötigt und sind deshalb sehr praktisch. Trotzdem werden wir in den meisten Fällen einen benutzerdefinierten Dialog benötigen. Im folgenden beschränken wir uns darauf, dass ein Objekt von unserem Dialog angelegt werden muss und die eingegeben Daten über eine Methode abgefragt werden müssen.
Nun wollen wir Schritt für Schritt einen eigenen Dialog implementieren.

Einzugebende Daten festlegen

Dieser Schritt ist von einem Anwendungsfall zum andern verschieden. In jedem Fall ist es empfehlenswert sich eine eigene Klasse für diese Daten anzulegen. In unserem Beispiel wollen wir Informationen über eine Person abfragen. Dabei beschränken wir uns auf Vorname, Nachname, Alter und Geschlecht. Die Klasse für unsere Daten würde entsprechend so aussehen:

#include <QString>
 
class Person
{
 
public:
  Person( const QString& firstName, const QString& lastName,
          const unsigned char age, const bool gender )
    : m_firstName( firstName ),
      m_lastName( lastName ),
      m_age( age ),
      m_gender( gender ) { }
  const QString& firstName() { return m_firstName; }
  const QString& lastName() { return m_lastName; }
  unsigned char age() { return m_age; }
  bool gender() { return m_gender; }
 
  static const bool Male = true;
  static const bool Female = false;
 
private:
  QString m_firstName, m_lastName;
  unsigned char m_age;
  bool m_gender;
 
};

Diese Implementierung enthält natürlich nur jene für die Demonstration notwendige Funktionalität.

Design der Eingabemaske

Wir wollen unseren Dialog relativ schlicht halten. Deshalb verwenden wir 2 QLineEdit-Widgets für die beiden Namen, eine QSpinBox fürs Alter und eine QComboBox für das Geschlecht. Damit der Benutzer weiß welche Daten eingegeben werden sollen, wollen wir eine kurze Beschreibung vor dem jeweiligen Eingabefeld. Dafür eignet sich am besten ein Formular-Layout.
Das wars zu unseren Daten. Was natürlich noch fehlt ist ein Button zum Bestätigen der Eingabe, den wir mit einem QVBoxLayout mit dem Formular verbinden und auf unseren Dialog anwenden.

Implementierung des Dialogs

Wir könnten unseren Dialog natürlich auch basiert auf QWidget erstellen, jedoch nimmt uns QDialog einiges an Arbeit ab.

class PersonDialog : public QDialog


Wie wir wissen ist ein Dialog mit einem Parent-Objekt automatisch an oberster Stelle und zentriert über dem Eltern-Widget angezeig. Dieses Verhalten übernehmen wir einfach von QDialog und bieten einen entsprechenden Konstruktor mit einem optionalen QWidget als Parameter an. Der Rest des Konstruktors legt die weiteren Eigenschaften der einzelnen Widgets fest und platziert sie in einem Layout.
Hervorzuheben ist noch die Verbindung zwischen m_confirmButton.clicked() und accept() des Dialogs. Der Slot accept() erledigt gleich mehrere Schritte in einem. Der ausgeführte Dialog wird versteckt und das Ergebnis des Dialogs auf QDialog::Accepted. Das bedeutet, dass gültige Daten eingegeben wurden. Wir könnten auch noch eine Prüfung einfügen, ob überhaupt ein Vorname und ein Nachname eingegeben wurden und im Fehlerfall reject() aufrufen. Der Einfachheit wegen verzichten wir in diesem Beispiel darauf. Falls der Dialog modal war, wird die Ausführung des restlichen Programms nach dem Aufruf einer der beiden Funktionen fortgesetzt.

PersonDialog::PersonDialog( QWidget *parent )
  : QDialog( parent ),
    m_firstName( new QLineEdit() ),
    m_lastName( new QLineEdit() ),
    m_age( new QSpinBox() ),
    m_gender( new QComboBox() ),
    m_confirmButton( new QPushButton( "Confirm" ) )
{
  m_age->setRange( 0, 150 );
  m_gender->addItem( "Male" );
  m_gender->addItem( "Female" );
  connect( m_confirmButton, SIGNAL( clicked() ),
           this, SLOT( accept() ) );
 
  QVBoxLayout *vLayout = new QVBoxLayout( this );
  QFormLayout *fLayout = new QFormLayout();
  fLayout->addRow( "First Name:", m_firstName );
  fLayout->addRow( "Last Name:", m_lastName );
  fLayout->addRow( "Age:", m_age );
  fLayout->addRow( "Gender:", m_gender );
  vLayout->addLayout( fLayout );
  QHBoxLayout *hLayout = new QHBoxLayout();
  hLayout->addStretch();
  hLayout->addWidget( m_confirmButton );
  vLayout->addLayout( hLayout );
}


Die einzige Methode die wir noch brauchen ist für die Abfrage der eingegebenen Daten. Sie übernimmt einfach die in die Widgets eingegeben Daten und schreibt sie in unser Person-Objekt, das dann zurückgegeben wird.

Person PersonDialog::getPerson() const
{
  return Person( m_firstName->text(), m_lastName->text(),
                 m_age->value(),
                 m_gender->itemText( m_gender->currentIndex() ) == "Male"
                 ? Person::Male
                 : Person::Female );
}

Verwendung des Dialogs

Die Verwendung des Dialogs ist recht intuitiv und sollte klar sein:

PersonDialog dialog;
dialog.exec();
Person p = dialog.getPerson();

Gesamter Beispielcode, Screenshot und Ausgabe

Zusammenfassend noch der gesamte Code des Beispiels:

// main.cpp
#include <QApplication>
#include <QDebug>
#include "PersonDialog.h"
#include "Person.h"
 
int main( int argc, char *argv[] )
{
  QApplication app( argc, argv );
  PersonDialog dialog;
 
  dialog.exec();
  Person p = dialog.getPerson();
  qDebug() << p.firstName()
           << p.lastName()
           << p.age()
           << ( p.gender() == Person::Male ? "Male" : "Female" );
 
  return 0;
}
// Person.h
#ifndef PERSON_H
#define PERSON_H
 
#include <QString>
 
class Person
{
 
public:
  Person( const QString& firstName, const QString& lastName,
          const unsigned char age, const bool gender )
    : m_firstName( firstName ),
      m_lastName( lastName ),
      m_age( age ),
      m_gender( gender ) { }
  const QString& firstName() { return m_firstName; }
  const QString& lastName() { return m_lastName; }
  unsigned char age() { return m_age; }
  bool gender() { return m_gender; }
 
  static const bool Male = true;
  static const bool Female = false;
 
private:
  QString m_firstName, m_lastName;
  unsigned char m_age;
  bool m_gender;
 
};
 
#endif // PERSON_H
// PersonDialog.h
#ifndef PERSONDIALOG_H
#define PERSONDIALOG_H
 
#include <QDialog>
 
class Person;
class QLineEdit;
class QSpinBox;
class QComboBox;
class QPushButton;
 
class PersonDialog : public QDialog
{
 
public:
    PersonDialog( QWidget *parent = NULL );
    Person getPerson() const;
 
private:
    QLineEdit *m_firstName, *m_lastName;
    QSpinBox *m_age;
    QComboBox *m_gender;
    QPushButton *m_confirmButton;
 
};
 
#endif // PERSONDIALOG_H
// PersonDialog.cpp
#include "PersonDialog.h"
 
#include "Person.h"
#include <QLineEdit>
#include <QSpinBox>
#include <QComboBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
 
PersonDialog::PersonDialog( QWidget *parent )
  : QDialog( parent ),
    m_firstName( new QLineEdit() ),
    m_lastName( new QLineEdit() ),
    m_age( new QSpinBox() ),
    m_gender( new QComboBox() ),
    m_confirmButton( new QPushButton( "Confirm" ) )
{
  m_age->setRange( 0, 150 );
  m_gender->addItem( "Male" );
  m_gender->addItem( "Female" );
  connect( m_confirmButton, SIGNAL( clicked() ),
           this, SLOT( accept() ) );
 
  QVBoxLayout *vLayout = new QVBoxLayout( this );
  QFormLayout *fLayout = new QFormLayout();
  fLayout->addRow( "First Name:", m_firstName );
  fLayout->addRow( "Last Name:", m_lastName );
  fLayout->addRow( "Age:", m_age );
  fLayout->addRow( "Gender:", m_gender );
  vLayout->addLayout( fLayout );
  QHBoxLayout *hLayout = new QHBoxLayout();
  hLayout->addStretch();
  hLayout->addWidget( m_confirmButton );
  vLayout->addLayout( hLayout );
}
 
 
Person PersonDialog::getPerson() const
{
  return Person( m_firstName->text(), m_lastName->text(),
                 m_age->value(),
                 m_gender->itemText( m_gender->currentIndex() ) == "Male"
                 ? Person::Male
                 : Person::Female );
}


Nun bekommen wir folgenden Dialog angezeigt:

Ein Klick auf den Button liefert diese Ausgabe:

"Max" "Mustermann" 18 Male