Создание графических интерфейсов пользователя с использованием Qt 5.12 (1245345), страница 8
Текст из файла (страница 8)
При этомконструктор создает все необходимые объекты и строит окно, метод начальной настройкинастраивает компоненты интерфейса на ввод, делая невидимыми окно вывода и его метку,метод вычислений выполняет необходимые преобразования и расчеты, а такжеперестраивает интерфейс на вывод результатов:#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();}elseif (!str.isEmpty()){QMessageBox msgBox(QMessageBox::Information,codec->toUnicode("Возведение в квадрат."),codec->toUnicode("Введено неверное значение."),QMessageBox::Ok);msgBox.exec();}}QHBoxLayoutQVBoxLayoutQVBoxLayoutРисунок 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();Пример 2.8.
Приложение «Счетчик». Генерация нового сигнала.В качестве примера разработаем приложение, которое считает отдельные нажатия накнопку и серии по пять нажатий (рисунок 2.8).Рисунок 2.8 – Внешний вид счетчика нажатийНа рисунке 2.9 приведена диаграмма взаимодействия объектов приложения в процессе работы посредством генерации и обработки сигналов (сообщения создания/уничтожения объектов и изменения их размеров в процессе компоновки не показаны,чтобы не усложнять рисунок).Таким образом оба объекта счетчиков должны уметь увеличивать свое содержимоена единицу, т.е. включать соответствующий метод – слот.
А первый счетчик еще и долженгенерировать сигнал по достижении пяти нажатий.ОкноприложенияЗавершитьКнопка "+1"+1Счетчик 1+1Кнопка"Выход"Счетчик 2Рисунок 2.9 – Сигналы в приложенииОба счетчика будем строить на базе одного класса Counter, наследуемого от класса QLineEdit. В производном классе предусмотрим соответствующие сигналtick_signal() и слот add_one() (рисунок 2.10).QLineEditCountertick_signal()add_one()Рисунок 2.10 – Структура класса CounterОписание класса Counter можно поместить в отдельный файл, но для простоты чтения программы включим его в файл win.h вместе с описанием класса окна:#ifndef win_h#define win_h#include <QLineEdit>#include <QString>#include <QLabel>#include <QPushButton>class Counter:public QLineEdit{Q_OBJECTpublic:Counter(const QString & contents, QWidget *parent=0):QLineEdit(contents,parent){}signals:void tick_signal();public slots:void add_one(){QString str=text();int r=str.toInt();if (r!=0 && r%5 ==0) emit tick_signal();r++;str.setNum(r);setText(str);}};class Win: public QWidget{Q_OBJECTprotected:QTextCodec *codec;QLabel *label1,*label2;Counter *edit1,*edit2;QPushButton *calcbutton;QPushButton *exitbutton;public:Win(QWidget *parent = 0);};#endifФайл win.cpp в этом случае содержит только описание конструктора класса окна:#include "win.h"#include <QTextCodec>#include <QHBoxLayout>Win::Win(QWidget *parent):QWidget(parent){codec = QTextCodec::codecForName("Windows-1251");this->setWindowTitle(codec->toUnicode("Счетчик"));label1 = new QLabel(codec->toUnicode("Cчет по 1"),this);label2 = new QLabel(codec->toUnicode("Cчет по 5"),this);edit1 = new Counter("0",this);edit2 = new Counter("0",this);calcbutton=new QPushButton("+1",this);exitbutton=new QPushButton(codec->toUnicode("Выход"),this);QHBoxLayout *layout1 = new QHBoxLayout();layout1->addWidget(label1);layout1->addWidget(label2);QHBoxLayout *layout2 = new QHBoxLayout();layout2->addWidget(edit1);layout2->addWidget(edit2);QHBoxLayout *layout3 = new QHBoxLayout();layout3->addWidget(calcbutton);layout3->addWidget(exitbutton);QVBoxLayout *layout4 = new QVBoxLayout(this);layout4->addLayout(layout1);layout4->addLayout(layout2);layout4->addLayout(layout3);// связь сигнала нажатия кнопки и слота закрытия окнаconnect(calcbutton,SIGNAL(clicked(bool)),edit1,SLOT(add_one()));connect(edit1,SIGNAL(tick_signal()),edit2,SLOT(add_one()));connect(exitbutton,SIGNAL(clicked(bool)),this,SLOT(close()));}Файл main.cpp не отличается от соответствующих файлов предыдущих программ:#include "win.h"#include <QApplication>int main(int argc, char *argv[]){QApplication app(argc, argv);Win win(0);win.show();return app.exec();}Связь «сигнал-слот» устанавливается между объектами на этапе выполнения, поэтому она может быть разорвана при использовании операции disconnect().
Однаконеобходимость рассоединять объекты обычно не возникает, поскольку связь автоматически разрывается при уничтожении любого из объектов в ней участвующих.2.4 Обработка событий. Рисование. События таймераВ соответствии с идеологией событийного программирования обо всех изменениях,зафиксированных операционной системой, приложение узнает при получении от нее соответствующих сообщений. Так нажатие и отпускание клавиш клавиатуры и мыши инициируют сообщения от клавиатуры и мыши, перемещение окон на экране, в результатекоторых открываются ранее закрытые фрагменты окна, – сообщения перерисовки окна ит.п.В большинстве случаев сообщения генерируются системой в ответ на действияпользователя, но причиной генерации новых сообщений могут быть также, например сигналы таймера или запросы, пришедшие по сети.Все сообщения операционной системы поступают в очередь сообщений приложения, откуда выбираются приложением для последующей обработки.
Результатом этой обработки является активизация соответствующих событий.Таким образом, в отличие от сигналов, которые используются для организации взаимодействия виджетов, события служат для передачи виджетам информации от операционной системы.Как правило, необходимости в обработке событий при работе с виджетами не возникает: обработка большинства событий уже выполняется методами виджетов, и в результате этой обработки формируются необходимые сигналы. Так при щелчке пользователя покнопке QPushButton виджет кнопки обрабатывает событие Нажатие на Кнопку и формирует сигнал clicked().
Но при необходимости возможно создание нестандартныхобработчиков событий.Одним из случаев, когда приходится выполнять обработку событий, является рисование.Рисование в простейшем варианте выполняется с помощью объекта класса QPainter. Объект этого класса получает доступ к фрагменту экрана, отведенному под окно, вкотором выполняется рисование.Само рисование программируют в обработчике события перерисовкиpaintEvent(), тогда каждый раз при перерисовке окна (например, когда окно появляется из-за других окон) рисунок возобновляется. Кроме того, при использовании этого события необходимость в стирании рисунка отпадает.