Пример 2.7. Приложение «Возведение числа в квадрат». Создание новых слотов.
На рисунке 2.6 представлено окно создаваемого приложения в разные моменты времени. В момент запуска приложения кнопка Следующее не активна, поскольку нажатие на нее бессмысленно. При выдаче результата эта кнопка становится доступной, но строчный редактор, используемый для ввода значения, блокируется, чтобы предотвратить изменение исходных данных и, как следствие, появление на экране результата, не связанного с исходными данными.
Ввод будем считать завершенным, если пользователь нажимает клавиши Enter или Tab клавиатуры или щелкает мышью вне поля ввода. При этом строчный редактор теряет фокус ввода. При вводе неправильных (например буквенных) исходных данных приложение должно выдавать сообщение об ошибке в специальном окне.
Рисунок 2.6 – Окно приложения: при запуске программы (а), при выдаче результата (б)
Создание приложения начинаем с описания класса окна Win . Этот класс, кроме рамки, меток, строчных редакторов и кнопок должен включать:
· объект класса QTextCodec – для русификации интерфейса;
· менеджеры вертикальной и горизонтальной компоновки.
Поскольку в качестве сигнала завершения ввода мы собираемся использовать returnPressed()– сигнал нажатия клавиши Enter, кроме класса окна нам понадобится описать специальный класс-валидатор StrValidator, наследуемый от класса QValidator.
Объект этого класса, включающего метод проверки вводимой строки validate(), передается строчному редактору, осуществляющему ввод. При завершении ввода этот метод вызывается автоматически. Если этот метод возвращает Acceptable, то редактор ввода генерирует сигналы editingFinished()– завершение редактирования и returnPressed()– сигнал нажатия клавиши Enter. В противном случае эти сигналы не генерируются. Метод validate()разрабатываемого нами приложения будет всегда принимать вводимую строку. Проверка этой строки будет осуществляться позднее.
Окончательно получаем следующий файл win . h :
#ifndef win_h
#define win_h
#include <QTextCodec>
#include <QFrame>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QValidator>
class Win:public QWidget // класс окна
{
Q _ OBJECT // макрос Qt, обеспечивающий корректное создание сигналов и слотов
protected:
QTextCodec *codec;
QFrame *frame; // рамка
QLabel *inputLabel; // метка ввода
QLineEdit *inputEdit; // строчный редактор ввода
QLabel *outputLabel; // метка вывода
QLineEdit *outputEdit; // строчный редактор вывода
QPushButton *nextButton; // кнопка Следующее
QPushButton *exitButton; // кнопка Выход
public:
Win(QWidget *parent = 0); // конструктор
public slots:
void begin(); // метод начальной настройки интерфейса
void calc(); // метод реализации вычислений
};
class StrValidator:public QValidator // класс компонента проверки ввода
{
public:
StrValidator(QObject *parent):QValidator(parent){}
virtual State validate(QString &str,int &pos)const
{
return Acceptable; // метод всегда принимает вводимую строку
}
};
#endif
Как следует из текста класс окна добавляет к множеству стандартно объявленных слотов еще два слота – методы начальной настройки и реализации вычислений:
public slots :
void begin(); // метод начальной настройки интерфейса
void calc(); // метод реализации вычислений
после этого указанные методы могут подключаться к сигналам с использованием оператора Qt connect.
Файл реализации win.cpp содержит описание трех методов класса окна. При этом конструктор создает все необходимые объекты и строит окно, метод начальной настройки настраивает компоненты интерфейса на ввод, делая невидимыми окно вывода и его метку, метод вычислений выполняет необходимые преобразования и расчеты, а также перестраивает интерфейс на вывод результатов:
#include "win.h"
#include <QVBoxLayout>
#include <QMessageBox>
Win::Win(QWidget *parent):QWidget(parent)
{
codec = QTextCodec::codecForName("Windows-1251");
setWindowTitle(codec->toUnicode("Возведение в квадрат"));
frame = new QFrame(this);
frame->setFrameShadow(QFrame::Raised);
frame->setFrameShape(QFrame::Panel);
inputLabel = new QLabel(codec->toUnicode("Введите число:"),
this);
inputEdit = new QLineEdit("",this);
StrValidator *v=new StrValidator(inputEdit);
inputEdit->setValidator(v);
outputLabel = new QLabel(codec->toUnicode("Результат:"),
this);
outputEdit = new QLineEdit("",this);
nextButton = new QPushButton(codec->toUnicode("Следующее"),
this);
exitButton = new QPushButton(codec->toUnicode("Выход"),
this);
// компоновка приложения выполняется согласно рисунку 2.
QVBoxLayout *vLayout1 = new QVBoxLayout(frame);
vLayout1->addWidget(inputLabel);
vLayout1->addWidget(inputEdit);
vLayout1->addWidget(outputLabel);
vLayout1->addWidget(outputEdit);
vLayout1->addStretch();
QVBoxLayout *vLayout2 = new QVBoxLayout();
vLayout2->addWidget(nextButton);
vLayout2->addWidget(exitButton);
vLayout2->addStretch();
QHBoxLayout *hLayout = new QHBoxLayout(this);
hLayout->addWidget(frame);
hLayout->addLayout(vLayout2);
begin();
connect(exitButton,SIGNAL(clicked(bool)),
this,SLOT(close()));
connect(nextButton,SIGNAL(clicked(bool)),
this,SLOT(begin()));
connect(inputEdit,SIGNAL(returnPressed()),
this,SLOT(calc()));
}
void Win::begin()
{
inputEdit->clear();
nextButton->setEnabled(false);
nextButton->setDefault(false);
inputEdit->setEnabled(true);
outputLabel->setVisible(false);
outputEdit->setVisible(false);
outputEdit->setEnabled(false);
inputEdit->setFocus();
}
void Win::calc()
{
bool Ok=true; float r,a;
QString str=inputEdit->text();
a=str.toDouble(&Ok);
if (Ok)
{
r=a*a;
str.setNum(r);
outputEdit->setText(str);
inputEdit->setEnabled(false);
outputLabel->setVisible(true);
outputEdit->setVisible(true);
nextButton->setDefault(true);
nextButton->setEnabled(true);
nextButton->setFocus();
}
else
if (!str.isEmpty())
{
QMessageBox msgBox(QMessageBox::Information,
codec->toUnicode("Возведение в квадрат."),
codec->toUnicode("Введено неверное значение."),
QMessageBox::Ok);
msgBox.exec();
}
}
Рисунок 2.7 – Схема компоновки интерфейса приложения
Основная программа данного примера помещается в файл source . cpp :
#include "win.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Win win(0);
win.show();
return app.exec();
}
Метод calc () , реализующий основную обработку, проверяет правильность ввода данных и выдает окно сообщения, если данные введены неверно. При этом используется прямой вызов метода вывода окна сообщения QMessage : : exec () . Эту же операцию можно осуществить, создав новый сигнал, который генерируется, если обнаруживается ошибка данных.
2.3.2 Генерация новых сигналов
Аналогично новым слотам новые сигналы должны быть объявлены в классе, объекты которого этот сигнал генерируют, например:
signals : void input _ error ();
Сама генерация выполняется специальным оператором Qt emit , например:
emit input _ error ();