Reordering OK and Cancel

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
Image:qt-logo_new.png Image:qq-title-article.png
Qt Quarterly | Выпуск 19 | Документация


The various platforms supported by Qt have different guidelines forthe order of buttons in dialogs. The most obvious issue is that the"OK" and "Cancel" buttons should be swapped onMac OS X and GNOME, but there are several other differences as well.To ensure that dialogs created with Qt or Qt Designer look native onall window systems, Qt 4.2 introduces the QDialogButtonBox class thatabstracts the button row usually located at the bottom or on theright side of dialogs.

Содержание

[править] The QDialogButtonBox Class

The QDialogButtonBox class is a QWidget subclass that you canpopulate with a set of buttons and insert in your dialog's layout. Bydefault, QDialogButtonBox lays out its buttons horizontally, butthis can be changed by passing Qt::Vertical to the constructor.

centercenter

When adding buttons to a QDialogButtonBox, we also pass a"button role" that specifies how the button should be handled. Forexample:

box->addButton(tr("OK"), QDialogButtonBox::AcceptRole);
box->addButton(tr("Cancel"),QDialogButtonBox::RejectRole);
box->addButton(tr("Apply"), QDialogButtonBox::ApplyRole);
box->addButton(tr("Reset"), QDialogButtonBox::ResetRole);
box->addButton(tr("Help"), QDialogButtonBox::HelpRole);

QDialogButtonBox uses the roles to orderthe buttons correctly with respect to the user's window system or desktopenvironment. The table below explains the available roles.

Role Description Examples
AcceptRole Accepts the dialog OK, Open, Save
RejectRole Rejects the dialog Cancel, Close
DestructiveRole Risky way of closing the dialog Discard, Don't Save
ActionRole Performs an action on the dialog without closing it Find Next, More Info
ResetRole A "reset"-like action Reset, Restore Defaults
ApplyRole An "apply"-like action Apply, Try
HelpRole Invokes help Help
YesRole Positive answer to a yes/no question Yes, Yes to All
NoRole Negative answer to a yes/no question No, No to All

As of Qt 4.2, the class supports four "layout styles": Windows,Mac OS X, KDE, and GNOME. The buttons are ordered according to thecurrent layout style (specified by the active QStyle) and totheir roles. If there are several buttons with the same role, therelative order in which they were inserted is preserved in the finaldialog. Thus, on Windows, the buttons are organized as follows:

center

(In Windows and Mac OS X styles, YesRole and NoRole aretreated the same as AcceptRole and RejectRole, respectively.)On Mac OS X, the order is normally as follows:

center

Notice how the Help button is pushed to the far left, and howthe dialog's accept button (e.g., OK) is pushed to the right.What the diagram doesn't show is that if there is more than oneaccept button, the extra ones are put to the left of the rejectbutton, as specified in Apple Human Interface Guidelines.

Some buttons, such as OK, Cancel, and Help, occurover and over again in dialogs. For these, QDialogButtonBoxprovides convenience enum values that can be used instead ofspecifying a text and a role. For example:

box->addButton(QDialogButtonBox::Ok);
box->addButton(QDialogButtonBox::Cancel);
box->addButton(QDialogButtonBox::Apply);
box->addButton(QDialogButtonBox::Reset);
box->addButton(QDialogButtonBox::Help);

An alternative to calling addButton() for every button is to setthe standardButtons property (which also shows up in QtDesigner):

box->setStandardButtons(QDialogButtonBox::Ok
                        | QDialogButtonBox::Cancel
                        | QDialogButtonBox::Apply
                        | QDialogButtonBox::Reset
                        | QDialogButtonBox::Help);

[править] An Extended Message Box

In Qt 4.2, the QMessageBox class has been rewritten to use QDialogButtonBox to display its buttons. The API has also beenrevised so that it supports the same standard buttons and buttonroles as QDialogButtonBox. As a result, QMessageBox'sbuttons are now ordered correctly on the different platforms.

centercenter

The new QMessageBox also features a more nativelook on Mac OS X, a more flexible API that caters for message boxeswith more than three buttons, and more sensible word-wrapping behavior.

[править] Example: A Mail Editor

In this section, we will review the source code of a MailEditordialog class that uses QDialogButtonBoxand QMessageBox. The screenshots below showthe MailEditor dialog on Windows XP and Mac OS X.

center

center

Let's start with the constructor:

MailEditor::MailEditor(QWidget *parent)
    : QDialog(parent)
{
    ...
 
    sendNowButton = new QPushButton(tr("Send Now"));
    ...
    saveDraftButton = new QPushButton(tr("Save Draft"));
    sendNowButton->setDefault(true);
 
     buttonBox = new QDialogButtonBox;
     buttonBox->addButton(sendNowButton,
                          QDialogButtonBox::AcceptRole);
     buttonBox->addButton(discardDraftButton,
                          QDialogButtonBox::DestructiveRole);
     buttonBox->addButton(sendLaterButton,
                          QDialogButtonBox::RejectRole);
     buttonBox->addButton(saveDraftButton,
                          QDialogButtonBox::ActionRole);
 
    QGridLayout *layout = new QGridLayout;
    ...
    layout->addWidget(buttonBox, 3, 0, 1, 2);
    setLayout(layout);
}

We instantiate the QPushButtons as usual, but instead ofinserting them in a QHBoxLayout, we put them in a QDialogButtonBox. The table below lists the buttons, the roles wechose for them, and the reasons for that choice.

Button Role Rationale
Send Now AcceptRole This button is the standard way of closing the dialog.
Discard Draft DestructiveRole This button closes the dialog and may result in data loss.
Send Later RejectRole This button closes thedialog but does not send the email. It is the equivalent of pressingEsc.
Save Draft ActionRole This button doesn't close the dialog.

In the sendNow() slot, we callQDialog::accept() to close the dialog withan "accepted" result:

void MailEditor::sendNow()
{
    ...
    accept();
}

In discardDraft() and sendLater(), we callQDialog::reject() to close the dialog with a "rejected" result:

void MailEditor::discardDraft()
{
    ...
    reject();
}
 
void MailEditor::sendLater()
{
    saveDraft();
    reject();
}

The dialog's result value is accessible throughQDialog::result(). Unlike the other three slots, thesaveDraft() slot doesn't close the dialog:

void MailEditor::saveDraft()
{
    ...
    textEdit->document()->setModified(false);
}

If the user closes the dialog while there are unsaved changes, weshow a message box:

void MailEditor::closeEvent(QCloseEvent *event)
{
    if (textEdit->document()->isModified()) {
        int r = QMessageBox::warning(this,
                    tr("Mail Editor"),
                    tr("Do you want to save the draft "
                       "before closing?"),
                     QMessageBox::Save
                     | QMessageBox::DontSave
                     | QMessageBox::Cancel);
        if (r == QMessageBox::Save) {
            saveDraft();
            event->accept();
        } else if (r == QMessageBox::DontSave) {
            event->accept();
        } else {
            event->ignore();
        }
    }
}

Notice that we give meaningful labels to the message box's buttons,namely Save, Don't Save, and Cancel. For the user,this is much less error-prone than the traditional Yes and No choice.


Copyright © 2006 Trolltech Trademarks