KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Жасмин Бланшет - QT 4: программирование GUI на С++

Жасмин Бланшет - QT 4: программирование GUI на С++

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Жасмин Бланшет, "QT 4: программирование GUI на С++" бесплатно, без регистрации.
Перейти на страницу:

header.setValue("Host", "www.trolltech.com");

header.setContentType("application/x-www-form-urlencoded");

http.setHost(www.trolltech.com);

http.request(header, "qt-interest=on&search=opengl");

QHttp генерирует сигнал requestStarted(int) в начале выполнения команды и сигнал requestFinished(int, bool) после завершения выполнения команды. Параметр типа int является числом, которое идентифицирует запрос. Если мы собираемся отслеживать результаты выполнения отдельных запросов, мы можем сохранять эти идентификаторы при постановке запросов в очередь. Отслеживание идентификаторов обеспечивает более оперативную обратную связь с пользователем.

В большинстве приложений нас интересует результат исполнения всей последовательности команд. Это легко достигается путем подсоединения сигнала done(bool), который генерируется всякий раз, когда очередь запросов становится пустой.

При возникновении ошибки очередь запросов автоматически очищается. Но если мы после возникновения ошибки зададим новые запросы с использованием того же объекта QHttp, они будут поставлены в очередь и затем выполнены в обычном порядке.

Как и QFtp, класс QHttp содержит сигнал readyRead(), а также функции read() и readAll(), которые мы можем использовать вместо указания устройства ввода—вывода.

Написание клиент—серверных приложений на базе TCP

Классы QTcpSocket и QTcpServer могут использоваться для реализации клиентов и серверов TCP. TCP — это транспортный протокол, который составляет основу большинства прикладных протоколов сети Интернет, включая FTP и HTTP, и который может также использоваться для создания пользовательских протоколов.

TCP является потокоориентированным протоколом. Для приложений данные представляются в виде большого потока данных, очень напоминающего большой однородный файл. Протоколы высокого уровня, построенные на основе TCP, являются либо строкоориентированными, либо блокоориентированными:

• строкоориентированные протоколы передают текстовые данные построчно, завершая каждую строку символом перехода на новую строку;

• блокоориентированные протоколы передают данные в виде двоичных блоков. Каждый блок имеет в начале поле, где указан его размер, и затем идут байты данных.

Класс QTcpSocket наследует QIODevice через класс QAbstractSocket, и поэтому чтение с него или запись на него могут производиться с применением средств класса QDataStream или QTextStream. Одно существенное отличие чтения данных из сети по сравнению с чтением обычного файла заключается в том, что мы должны быть уверены в получении достаточного количества данных от партнерского узла (peer) перед использованием оператора >>. В противном случае результат может быть непредсказуемым.

В данном разделе мы рассмотрим программный код клиента и сервера, которые используют пользовательский протокол блочной передачи. Клиент называется Trip Planner (планировщик путешествий) и позволяет пользователям составлять план путешествия на поезде. Сервер называется Trip Server (сервер путешествий) и обеспечивает клиента информацией о путешествии. Мы начнем с написания клиентского приложения Trip Planner.

Приложение Trip Planner содержит поле From (из пункта), поле To (до пункта), поле Date (дата), поле Approximate Time (приблизительное время) и два переключателя, определяющие приблизительное время отправления или прибытия. Когда пользователь нажимает клавишу Search, приложение посылает запрос на сервер, который возвращает список железнодорожных рейсов, которые удовлетворяют критериям пользователя. Этот список отображается в виджете QTableWidget в окне Trip Planner. В нижней части окна расположены текстовая метка QLabel, показывающая состояние последней операции, и индикатор состояния процесса QProgressBar.

Рис. 14.1. ПриложениеТпр Planner.

Пользовательский интерфейс приложения Trip Planner был создан при помощи QtDesigner в файле tripplanner.ui. Ниже мы основное внимание уделим исходному коду подкласса QDialog, который реализует функциональность приложения:

#include "ui_tripplanner.h"

01 class TripPlanner : public QDialog, public Ui::TripPlanner

02 {

03 Q_OBJECT

04 public:

05 TripPlanner(QWidget *parent = 0);

06 private slots:

07 void connectToServer();

08 void sendRequest();

09 void updateTableWidget();

10 void stopSearch();

11 void connectionClosedByServer();

12 void error();

13 private:

14 void closeConnection();

15 QTcpSocket tcpSocket;

16 quint16 nextBlockSize;

17 };

Класс TripPlanner наследует не только QDialog, но и Ui::TripPlanner (который генерируется компилятором uic, используя файл tripplanner.ui). Переменная—член tcpSocket инкапсулирует соединение TCP. Переменная nextBlockSize используется при синтаксическом анализе блоков, поступивших с сервера.

01 TripPlanner::TripPlanner(QWidget *parent)

02 : QDialog(parent)

03 {

04 setupUi(this);

05 QDateTime dateTime = QDateTime::currentDateTime();

06 dateEdit->setDate(dateTime.date());

07 timeEdit->setTime(QTime(dateTime.time().hour(), 0));

08 progressBar->hide();

09 progressBar->setSizePolicy(QSizePolicy::Preferred,

10 QSizePolicy::Ignored);

11 tableWidget->verticalHeader()->hide();

12 tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);

13 connect(searchButton, SIGNAL(clicked()),

14 this, SLOT(connectToServer()));

15 connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSearch()));

16 connect(&tcpSocket, SIGNAL(connected()),

17 this, SLOT(sendRequest()));

18 connect(&tcpSocket, SIGNAL(disconnected()),

19 this, SLOT(connectionClosedByServer()));

20 connect(&tcpSocket, SIGNAL(readyRead()),

21 this, SLOT(updateTableWidget()));

22 connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),

23 this, SLOT(error()));

24 }

В конструкторе мы инициализируем поля редактирования даты и времени текущей датой и временем. Мы также не показываем индикатор состояния программы, потому что он необходим только при активном соединении. В Qt Designer свойства minimum и maximum индикатора состояния устанавливались в 0. Это определяет поведение QProgressBar как индикатора занятости вместо стандартного индикатора, показывающего процент выполнения работы.

В конструкторе мы также связываем сигналы connected(), disconnected(), readyRead() и error(QAbstractSocket::SocketError) класса QTcpSocket с закрытыми слотами.

01 void TripPlanner::connectToServer()

02 {

03 tcpSocket.connectToHost("tripserver.zugbahn.de", 6178);

04 tableWidget->setRowCount(0);

05 searchButton->setEnabled(false);

06 stopButton->setEnabled(true);

07 statusLabel->setText(tr("Connecting to server..."));

08 progressBar->show();

09 nextBlockSize = 0;

10 }

Слот connectToServer() выполняется, когда пользователь нажимает клавишу Search для запуска процедуры поиска. Мы вызываем функцию connectToHost() объекта типа QTcpSocket для подсоединения к серверу, который, как мы предполагаем, доступен через порт 6178 по вымышленному адресу хоста tripserver.zugbahn.de. (Если вы собираетесь проверить работу этого примера на вашей машине, замените имя хоста на QHostAddress::LocalHost.) Вызов connectToHost() выполняется асинхронно; эта функция всегда немедленно возвращает управление. Соединение обычно устанавливается позже. Объект QTcpSocket генерирует сигнал connected(), если соединение успешно осуществлено и действует, или error(QAbstractSocket::SocketError), если соединение завершилось неудачей.

Затем мы обновляем интерфейс пользователя, в частности делаем видимым индикатор состояния приложения.

Наконец, мы устанавливаем переменную nextBlockSize на 0. Эта переменная содержит длину следующего блока, полученного от сервера. Мы задали значение 0, поскольку еще не знаем размер следующего блока.

01 void TripPlanner::sendRequest()

02 {

03 QByteArray block;

04 QDataStream out(&block, QIODevice::WriteOnly);

05 out.setVersion(QDataStream::Qt_4_1);

06 out << quint16(0) << quint8('S') << fromComboBox->currentText()

07 << toComboBox->currentText() << dateEdit->date()

08 << timeEdit->time();

09 if (departureRadioButton->isChecked()) {

10 out << quint8('D');

11 } else {

12 out << quint8('A');

13 }

14 out.device()->seek(0);

15 out << quint16(block.size() - sizeof(quint16));

16 tcpSocket.write(block);

17 statusLabel->setText(tr("Sending request..."));

18 }

Слот sendRequest() выполняется, когда объект QTcpSocket генерирует сигнал connected(), уведомляя об установке соединения. Задача этого слота — сгенерировать запрос к серверу с передачей всей введенной пользователем информации.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*