03 GoToCellDialog::GoToCellDialog(QWidget *parent)
04 : QDialog(parent)
05 {
06 setupUi(this);
07 QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
08 lineEdit->setValidator(new QRegExpValidator(regExp, this));
09 connect(okButton, SIGNAL(clicked()),
10 this, SLOT(accept()));
11 connect(cancelButton, SIGNAL(clicked()),
12 this, SLOT(reject()));
13 }
14 void GoToCellDialog::on_lineEdit_textChanged()
15 {
16 okButton->setEnabled(lineEdit->hasAcceptableInput());
17 }
В конструкторе мы вызываем setupUi() для инициализации формы. Благодаря множественному наследованию мы можем непосредственно получить доступ к членам класса Ui::GoToCellDialog. После создания пользовательского интерфейса setupUi() будет также автоматически подключать все слоты с именами типа on_objectName_signalName() к соответствующему сигналу signalName() виджета objectName. В нашем примере это означает, что setupUi() будет устанавливать следующее соединение «сигнал—слот»:
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(on_lineEdit_textChanged()));
Также в конструкторе мы задаем ограничение на допустимый диапазон вводимых значений. Qt обеспечивает три встроенных класса по проверке правильности значений: QIntValidator, QDoubleValidator и QRegExpValidator. В нашем случае мы используем QRegExpValidator, задавая регулярное выражение «[A—Za—z][1—9][0—9]{0,2}», которое означает следующее: допускается одна маленькая или большая буква, за которой следует одна цифра в диапазоне от 1 до 9; затем идут ноль, одна или две цифры в диапазоне от 0 до 9. (Введение в регулярные выражения вы можете найти в документации по классу QRegExp.)
Указывая в конструкторе QRegExpValidator значение this, мы его делаем дочерним элементом объекта GoToCellDialog. После этого нам можно не беспокоиться об удалении в будущем QRegExpValidator; этот объект будет удален автоматически после удаления его родительского элемента.
Механизм взаимодействия объекта с родительскими и дочерними элементами реализован в QObject. Когда мы создаем объект (виджет, функцию по проверке правильности значений или любой другой объект) и он имеет родительский объект, то к списку дочерних элементов этого родителя добавится и данный объект. При удалении родительского элемента будет просмотрен список его дочерних элементов и все они будут удалены. Эти дочерние элементы, в свою очередь, сами удалят все свои дочерние элементы, и эта процедура будет выполняться до тех пор, пока ничего не останется.
Механизм взаимодействия объекта с родительскими и дочерними элементами значительно упрощает управление памятью, снижая риск утечек памяти. Явным образом мы должны удалять только объекты, которые созданы оператором new и которые не имеют родительского элемента. А если мы удаляем дочерний элемент до удаления его родителя, то Qt автоматически удалит этот объект из списка дочерних объектов этого родителя.
Для виджетов родительский объект имеет дополнительный смысл: дочерние виджеты размещаются внутри области, которую занимает родительский объект. При удалении родительского виджета не только освобождается занимаемая дочерними объектами память — он исчезает с экрана.
В конце конструктора мы подключаем кнопку OK к слоту accept() виджета QDialog и кнопку Cancel к слоту reject(). Оба слота закрывают диалог, но accept() устанавливает результат диалога на значение QDialog::Accepted (которое равно 1), a reject() устанавливает значение QDialog::Rejected (которое равно 0). При использовании этого диалога мы можем использовать значение результата, чтобы узнать, была ли нажата кнопка OK, и действовать соответствующим образом.
Слот on_lineEdit_textChanged() устанавливает кнопку OK в активное или неактивное состояние в зависимости от наличия в строке редактирования допустимого обозначения ячейки. QLineEdit::hasAcceptableInput() использует функцию проверки допустимости значений, которую мы задали в конструкторе.
На этом завершается построение диалога. Теперь мы можем переписать main.cpp следующим образом:
01 #include <QApplication>
02 #include "gotocelldialog.h"
03 int main(int argc, char *argv[])
04 {
05 QApplication app(argc, argv);
06 GoToCellDialog *dialog = new GoToCellDialog;
07 dialog->show();
08 return app.exec();
09 }
Постройте еще раз приложение (qmake —project; qmake gotocell.pro) и выполните его. Наберите в строке редактирования значение «A12» и обратите внимание на то, как кнопка OK становится активной. Попытайтесь ввести какой-нибудь произвольный текст и посмотрите, как сработает функция по проверке допустимости значения. Нажмите кнопку Cancel для закрытия диалогового окна.