Wiki

Обязательные поля

Mark Summerfield (перевод Racheengel)
Часто нам приходится отобразить пользователю форму, имеющую обязательные для заполнения поля. В данной статье представлен класс, который помогает работать с такими полями.

[Загрузить исходный код]

Если форма имеет обязательные поля, мы должны указать их, и активировать кнопку OK только в том случае, если все обязательные поля заполнены. Это можно сделать, используя класс MandatoryFieldGroup. Вот как его можно использовать в конструкторе диалога:

MoneyTransferDialog::MoneyTransferDialog(QWidget *parent)
    : QDialog(parent)
{
    ...
    MandatoryFieldGroup *group =
            new MandatoryFieldGroup(this);
    group->add(toAccountComboBox);
    group->add(amountLineEdit);
    group->setOkButton(acceptButton);
}

Как показано на скриншоте ниже, мы решили отмечать обязательные поля желтым фоном. (Для выпадающих списков, в некоторых стилях, желтый цвет появится только, если текст редактируем, либо список развернут.) Переключатели могут быть сделаны обязательными, если они принимают три состояния, и их начальное состояние - NoChange.

Mandatory1

После того, как мы увидели использование, давайте посмотрим на определение:

class MandatoryFieldGroup : public QObject
{
    Q_OBJECT
public:
    MandatoryFieldGroup(QObject *parent)
        : QObject(parent), okButton(0) {}
 
    void add(QWidget *widget);
    void remove(QWidget *widget);
    void setOkButton(QPushButton *button);
 
private slots:
    void changed();
 
private:
    QValueList<QWidget *> widgets;
    QPushButton *okButton;
};

Список widgets используется для хранения всех обязательных полей, а кнопка okButton - для связи с кнопкой диалога OK. Конструктор также требует инициализации okButton.

void MandatoryFieldGroup::add(QWidget *widget)
{
    if (!widgets.contains(widget)) {
        if (widget->inherits("QCheckBox")) {
            connect(widget, SIGNAL(clicked()),
                    this, SLOT(changed()));
        } else if (widget->inherits("QComboBox")) {
            connect(widget, SIGNAL(highlighted(int)),
                    this, SLOT(changed()));
        } else if (widget->inherits("QLineEdit")) {
            connect(widget,
                    SIGNAL(textChanged(const QString &)),
                    this, SLOT(changed()));
        } else {
            qWarning("%s unhandled", widget->className());
            return;
        }
        widget->setPaletteBackgroundColor(yellow);
        widgets.append(widget);
        changed();
    }
}

Если добавленный виджет еще не добавлен в группу обязательных полей, мы смотрим, от какого типа он порожден и соединяем наиболее подходящий его сигнал с нашим слотом changed(). Затем мы устанавливаем цвет фона, добавляем виджет в список обязательных полей, и вызываем слот changed() для обновления кнопки OK.

void MandatoryFieldGroup::setOkButton(QPushButton *button)
{
    if (okButton && okButton != button)
        okButton->setEnabled(true);
    okButton = button;
    changed();
}

Если кнопка OK была изменена, мы активируем старую кнопку. Затем мы вызываем changed() для обновления ее состояния.

void MandatoryFieldGroup::changed()
{
    if (!okButton)
        return;
    bool enable = true;
    QValueList<QWidget *>::const_iterator i;
    for (i = widgets.begin(); i != widgets.end(); ++i) {
        QWidget *widget = *i;
        if (widget->inherits("QCheckBox")) {
            if (((QCheckBox *)widget)->state() ==
                QButton::NoChange) {
                enable = false;
                break;
            }
        } else if (widget->inherits("QComboBox")) {
            if (currentText().isEmpty()) {
                enable = false;
                break;
            }
        } else if (widget->inherits("QLineEdit")) {
            if (((QLineEdit *)widget)->text().isEmpty()) {
                enable = false;
                break;
            }
        }
    }
    okButton->setEnabled(enable);
}

Если кнопка OK не была задана, мы не делаем ничего. Иначе, мы полагаем, что все обязательные поля имеют значения, и просматриваем их с целью проверки. Если какое-либо поле оказалось пустым (или неизменено, в случае переключателя), мы можем немедленно выйти из цикла, чтобы выключить кнопку OK. В конце мы соответственно включаем либо выключаем кнопку OK.

В некоторых ситуациях поле может перестать быть обязательным. Мы можем обеспечить это вызовом remove() (не приведено), при этом восстанавливается оригинальный цвет фона, виджет удаляется из списка обязательных полей, и вызывается changed() для обновления состояния кнопки OK.


Copyright © 2004 Trolltech Trademarks