Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

Dialog Button Box Example

Files:

This example shows use of QDialogButtonBox.

QDialogButtonBox lays out buttons for dialogs and message boxes in a way that follows interface guidelines for the current widget style, e.g., QWindowsStyle or QMotifStyle.

Buttons in dialogs follow roles that describe the actions the buttons trigger (e.g., accepting or rejecting the dialog or asking for help). In a QDialogButtonBox each button is assigned such a role. A 'Yes' or 'Save' button will, for instance, have an accept role. The QDialogButtonBox has a finite number of predefined roles (defined by the ButtonRole enum).

This example lets the user add buttons to dialog button boxes in a QMdiArea; it is possible to select from a group of buttons that already have roles assigned (defined by the StandardButton enum) or enter the button's text and select a role. The StandardButton enum defines the available buttons. The user can change the style of the boxes; the styles available depend on the platform on which the example is run.

The dialog button box example consists of two classes: MainWindow and AddButtonDialog. MainWindow inherits QMainWindow and provides an mdi area to which the user can add dialog boxes. It also displays a table that shows the text and role of the buttons in the active dialog button box in the mdi area. AddButtonDialog lets the user select buttons to add to the dialog boxes. We have used the designer for the GUI in this example.

MainWindow Class Definition

 class MainWindow : public QMainWindow, Ui::MainWindow
 {
     Q_OBJECT

 public:
     enum Presets { SaveChanges, ReallyQuit, FileError, Empty };

     MainWindow();

 private slots:
     void addButton();
     void deleteButton();
     void loadPresetBox();
     void newStyle(QAction *action);
     void newOrientation(QAction *action);
     void subWindowActivated(QMdiSubWindow *widget);

 private:
     void connectActions();
     QWidget *createDialogButtonBox(Presets present);
     void setStyle(QDialogButtonBox *widget, QStyle *style);
     void resolveButtons();
     void resizeActiveWindow();

     int windowCount;

     QMdiArea *mdiArea;
     QMdiSubWindow *currentWindow;

     QActionGroup *styleGroup;
     QActionGroup *orientationGroup;

     QAbstractButton *myAddButton;
     QAbstractButton *myDeleteButton;
 };

The MainWindow class inherits the class generated by designer and QMainWindow. We connect the widgets with private slots, which we will examine as we encounter them in the code.

MainWindow Class Implementation

We will now look at the implementation of the class, and we start with the constructor:

 MainWindow::MainWindow()
 {
     setupUi(this);
     myAddButton = deleteAddDialogBox->addButton(tr("Add"),
                                                 QDialogButtonBox::AcceptRole);
     myDeleteButton = deleteAddDialogBox->addButton(tr("Delete"),
                                                 QDialogButtonBox::RejectRole);

We start by creating the menus and widgets of the main window by calling the setupUi() method generated by designer.

As mentioned, QDialogButtonBox supports a number of standard buttons, which we can add to dialog button boxes in designer. If we want buttons with custom texts and roles, we add them programmatically (as shown in the code above).

     ...
 }

The rest of the constructor sets up the QMdiArea and QTableWidget. We move on to connectActions():

 void MainWindow::connectActions()
 {
     loadSaveChangesAction->setData(int(SaveChanges));
     loadReallyQuitAction->setData(int(ReallyQuit));
     loadEmptyAction->setData(int(Empty));
     loadFileErrorAction->setData(int(FileError));

     verticalAction->setData(int(Qt::Vertical));
     horizontalAction->setData(int(Qt::Horizontal));

     styleGroup = new QActionGroup(this);
     foreach (QString style, QStyleFactory::keys()) {
         QAction *action = new QAction(style, this);
         action->setCheckable(true);
         action->setData(QStyleFactory::create(style));
         stylesMenu->addAction(action);
         styleGroup->addAction(action);
     }
     styleGroup->actions().first()->setChecked(true);

The user can choose from four different boxes (identified by the Presets enum) when adding boxes to the mdi area. The QAction class lets us store user data in a QVariant. We use the values from Presets as data for the actions. We cast them to ints as QVariant cannot store Presets values.

We iterate over the available styles and create an action for each of them using the string key as the actions' text, which we use in newStyle() to create styles with QStyleFactory::create().

     ...
 }

The rest of the function connects widgets to slots in MainWindow.

Here is the createDialogButtonBox() implementation:

 QWidget *MainWindow::createDialogButtonBox(Presets preset)
 {
     QDialogButtonBox *box;
     QWidget *widget = new QWidget;

      switch (preset) {
         case SaveChanges:
             box = new QDialogButtonBox(QDialogButtonBox::Yes |
                                        QDialogButtonBox::YesToAll |
                                        QDialogButtonBox::No |
                                        QDialogButtonBox::NoToAll |
                                        QDialogButtonBox::Help);
             widget->setWindowTitle(tr("Save Changes"));
             break;
         case ReallyQuit:
             box = new QDialogButtonBox(QDialogButtonBox::Cancel |
                                        QDialogButtonBox::Yes);
             widget->setWindowTitle(tr("Really Quit"));
             break;
         case FileError:

The createDialogButtonBox() function returns a QDialogButtonBox (to add to the mdi area).In the constructor we select which of the StandardButtons the new dialog button box should start out with. We show two of the four different boxes that the function can create.

     ...
     setStyle(box,
     QStyleFactory::create(styleGroup->checkedAction()->text()));
     box->adjustSize();

     QGridLayout *layout = new QGridLayout;
     layout->addItem(new QSpacerItem(box->width() + 50, 75), 0, 0);
     layout->addWidget(box, 1, 0);
     widget->setLayout(layout);
     widget->adjustSize();
     horizontalAction->setChecked(true);

     return widget;
 }

The style of the boxes is individual and not based on the current application style, so we set the style with setStyle() function, which we will examine shortly.

The addButton() slot opens an AddButtonDialog, which lets the user add buttons to the active - or, if no sub window is active, the previously active sub window - dialog box in the mdi area (revise this sentence). We take a closer look at the deleteButton() slot:

 void MainWindow::deleteButton()
 {
     QList<QTableWidgetItem *> list = tableWidget->selectedItems();

     if (!list.isEmpty()) {
         int row = list.first()->row();
         QString buttonText = tableWidget->item(row, 0)->text();
         tableWidget->removeRow(row);
         QDialogButtonBox *box = qFindChild<QDialogButtonBox *>(currentWindow);

         if (box) {
             foreach (QAbstractButton *button, box->buttons()) {
                 if (button->text().remove('&') == buttonText) {
                     box->removeButton(button);
                     resizeActiveWindow();
                 }
             }
         }
     }
 }

The deleteButton() slot removes the button selected in the table from the dialog button box. The text column in the table contains the text of the buttons in the last activated dialog box. We iterate over the buttons in the box and remove the box that has the same text as the selected button in the table.

Here is the loadPresetBox() slot:

 void MainWindow::loadPresetBox()
 {
     QAction *action = qobject_cast<QAction *>(sender());

     currentWindow =
     mdiArea->addSubWindow(
         createDialogButtonBox(Presets(qVariantValue<int>(action->data()))));
     currentWindow->show();

     resolveButtons();
 }

The loadPresetBox() slot is connected to the actions that let the user add dialog boxes to the mdi area: loadSaveChangesAction, loadReallyQuitAction, loadEmptyAction, and loadFileErrorAction. The dialog box is created with createDialogButtonBox(). We retrieve the user data stored in the action with data() and cast it to a Preset.

Here is the newStyle() slot:

 void MainWindow::newStyle(QAction *action)
 {
     if (currentWindow)  {
         QDialogButtonBox *box = qFindChild<QDialogButtonBox *>(currentWindow);
         QStyle *newStyle = QStyleFactory::create(action->text());
         setStyle(box, newStyle);
         currentWindow->adjustSize();
     }
 }

The newStyle() slot is called when the user changes the style used for the dialog button boxes; the active box in the mdi area and future boxes will take the new style. We have set the text of the actions to the keys used by QStyleFactory::create().

 void MainWindow::newOrientation(QAction *action)
 {
     if (currentWindow) {
         QDialogButtonBox *box = qFindChild<QDialogButtonBox *>(currentWindow);
         box->setOrientation(Qt::Orientation(qVariantValue<int>(action->data())));
         box->adjustSize();
         resizeActiveWindow();
     }
 }

The newOrientation() slot is called when the user requests that the orientation of the active dialog box should change. We have stored the two values of the Qt::Orientation enum in horizontalAction and verticalAction.

Here follows the implementation of the windowActivated() slot:

 void MainWindow::subWindowActivated(QMdiSubWindow *window)
 {
     currentWindow = window;

     QDialogButtonBox *box = qFindChild<QDialogButtonBox *>(currentWindow);

     if (box) {
         if (box->orientation() == Qt::Vertical)
             verticalAction->setChecked(true);
         else
             horizontalAction->setChecked(true);

         foreach (QAction *action, styleGroup->actions()) {
             if (QStyleFactory::create(action->text())->metaObject()->className()
                 == box->style()->metaObject()->className()) {
                 action->setChecked(true);
             }
         }
         resolveButtons();
     } else
         tableWidget->setRowCount(0);
 }

When a new window in the mdi area is activated we need to update the table and menus.

 void MainWindow::setStyle(QDialogButtonBox *box, QStyle *style)
 {
     box->setStyle(style);
     box->setPalette(style->standardPalette());

     foreach (QObject *child, box->children()) {
         QWidget *widget = qobject_cast<QWidget *>(child);

         if (widget) {
             widget->setStyle(style);
             widget->setPalette(style->standardPalette());
         }
     }
 }

The setStyle() function does not set the style of children of the widget. We loop through the children of the box (the buttons) and set the style and palette on each of them.

Here is the resolveButtons() implementation:

 void MainWindow::resolveButtons()
 {
     QDialogButtonBox *box = qFindChild<QDialogButtonBox *>(currentWindow);

     if (box) {
         int i = 0;
         tableWidget->clearContents();
         tableWidget->setRowCount(box->buttons().count());

         foreach (QAbstractButton *button, box->buttons()) {
             QTableWidgetItem *textItem = new QTableWidgetItem(
             button->text().remove('&'));
             textItem->setFlags(textItem->flags() ^ Qt::ItemIsEditable);
             tableWidget->setItem(i, 0, textItem);

             QDialogButtonBox::ButtonRole role = box->buttonRole(button);
             QTableWidgetItem *roleItem =
                 new QTableWidgetItem(AddButtonDialog::roleToString(role));
             roleItem->setFlags(roleItem->flags() ^ Qt::ItemIsEditable);
             tableWidget->setItem(i, 1, roleItem);
             ++i;
         }
     }
 }

resolveButtons() fills the table when a button is added or a new window is activated in the mdi area. We iterate through the buttons in the active button box and set the texts and roles in the table.

AddButtonDialog Class Definition

The AddButtonDialog class lets the user choose a button to add to a dialog button box. It uses widgets laid out with designer in the Ui::AddDialogButton class.

 class AddButtonDialog : public QDialog, Ui::AddButtonDialog
 {
     Q_OBJECT

 public:
     AddButtonDialog(QDialogButtonBox *box, QWidget *parent = 0);

     static QString roleToString(QDialogButtonBox::ButtonRole role);

 public slots:
     void addButton();

 private slots:
     void standardButtonSelected(const QString &text);

 private:
     void fillStandardButtonCombo();
     void fillCustomButtonCombo();
     bool contains(QAbstractButton *button, QList<QAbstractButton *> buttons);

     QDialogButtonBox *dialogBox;
 };

AddButtonDialogBox Class Implementation

We start with a look at the constructor:

 AddButtonDialog::AddButtonDialog(QDialogButtonBox *box, QWidget *parent)
     : QDialog(parent)
 {
     dialogBox = box;

     setupUi(this);
     fillStandardButtonCombo();
     fillCustomButtonCombo();
     standardButtonSelected(standardButtonCombo->currentText());

     connect(standardButtonCombo, SIGNAL(activated(const QString &)),
             this, SLOT(standardButtonSelected(const QString &)));
     connect(okCancelDialogBox, SIGNAL(accepted()), this, SLOT(accept()));
     connect(okCancelDialogBox, SIGNAL(rejected()),
             this, SLOT(reject()));
 }

We start by creating the GUI from designer by calling setupUi(). We then fill the comboboxes with items with the fillStandardButtonCombo() and fillCustomButtonCombo() functions.

We move on to the fillStandardButtonCombo() function:

 void AddButtonDialog::fillStandardButtonCombo()
 {
     QMetaEnum standardEnum = QDialogButtonBox::staticMetaObject.enumerator(0);
     QDialogButtonBox box;

     for (int i = 1; i < standardEnum.keyCount(); ++i) {
         QString key = standardEnum.key(i);

         QDialogButtonBox::StandardButton standardButton =
             QDialogButtonBox::StandardButton(
             standardEnum.keyToValue(standardEnum.key(i)));
         standardButtonCombo->addItem(
             box.addButton(standardButton)->text().remove('&'),
                           int(standardButton));
     }
 }

We want the Standard button combo to have one item for each of the standard buttons QDialogButtonBox supports. In stead of adding the items individually with QComboBox::addItem(), we make use of Qt's meta object system.

 void AddButtonDialog::fillCustomButtonCombo()
 {
     customButtonCombo->addItem("Accept Role",
                                int(QDialogButtonBox::AcceptRole));
     customButtonCombo->addItem("Reject Role",
                                int(QDialogButtonBox::RejectRole));
     customButtonCombo->addItem("Destructive Role",
                                int(QDialogButtonBox::DestructiveRole));

The fillCustomButtonCombo() functions fill the Custom combo box with items. The combobox lets the user select which QDialogButtonBox::ButtonRole the added button will have.

We have one combobox item for each of the button roles. We can attach user data in QVariants to combobox items; we store the QDialogButtonBox::ButtonRole values in the items as ints (QVariant does not support ButtonRole).

     ...
 }

The addButton() slot is called when the user adds a button to the mdi area. It first checks whether it is a standard or custom button to be added; we will look at the code for each possibility. Here is its implementation:

 void AddButtonDialog::addButton()
 {
     QAbstractButton *addedButton = 0;

     if (tabWidget->tabText(tabWidget->currentIndex()) ==
         "Standard Button") {
         QDialogButtonBox::StandardButton standardButton =
             QDialogButtonBox::StandardButton(
                 qVariantValue<int>(standardButtonCombo->itemData(
                     standardButtonCombo->currentIndex())));

     if (dialogBox->button(standardButton) == 0)
         addedButton = dialogBox->addButton(standardButton);

We fetch the QDialogButton::StandardButton value from the current item of the combo box.

     } else {
         addedButton = new QPushButton(customButtonLineEdit->text());

         if (!contains(addedButton, dialogBox->buttons()))
             dialogBox->addButton(addedButton, QDialogButtonBox::ButtonRole(
                 qVariantValue<int>(customButtonCombo->itemData(
                     customButtonCombo->currentIndex()))));
     }

     if (addedButton)
         addedButton->setStyle(dialogBox->style());
 }

When we add a custom button, we create a new button and add it to the button box with the role from the Custom button combo.

The button is created by default with the application style, so we must set the style currently used by the dialog button box.

 void AddButtonDialog::standardButtonSelected(const QString & /* text */)
 {
     int value = standardButtonCombo->itemData(
     standardButtonCombo->currentIndex()).toInt();

     QDialogButtonBox box;
     QAbstractButton *button =
     box.addButton(QDialogButtonBox::StandardButton(value));
     standardRoleLabel->setText(roleToString(box.buttonRole(button)));
     standardTextLabel->setText(button->text().remove('&'));
 }

The standardButtonSelected() slot is called when the selected item in the Standard button combo changes. We fill the Standard text label and Standard role label.


Copyright © 2007 Trolltech Trademarks
Qt 4.3.0beta