Реклама

четверг, 19 декабря 2013 г.

Установка Qt Creator

Ubuntu
Запускаем Центр приложений Ubuntu, набираем в строке поиска Qt Creator, в найденном выделяем строку Qt Creator - кросс-платформенная IDE и нажимаем кнопку Установить. В результате будут установлены Qt Creator (на момент написания статьи версии 2.5.2) и библиотека Qt (версии 4.8.3).
Для работы рекомендуется выполнить минимальные настройки. С помощью compiz находим и запускаем установленное приложение. Выбираем пункт главного меню Инструменты > Параметры... В открывшемся окне на вкладке Сборка и запуск > Основное указываем каталог проектов, например, в домашней папке/home/login/qt-proj. Далее для самоуспокоения убеждаемся в наличии на вкладке Сборка и запуск > Профили Qt профиля Qt в PATH (Системная)и на вкладке Сборка и запуск > Инструментарии связки инструментов GCC (x86 32bit).
Если Qt Creator требуется установить на компьютер, не имеющий доступ в интернет, можно воспользоваться способом, изложенным в соответствующей статье.
Windows
Для начала Вам следует определиться какие инструменты Вы будете использовать, от этого зависит надо ли Вам производить отдельную установку Qt Creator. Если Вы используете готовую сборку библиотеки Qt 5, то необходимости устанавливать Qt Creator нет, поскольку он устанавливается вместе с библиотекой Qt (см.здесь). Вам, разве что, потребуется собрать отладчик GDB. Если же Вы собирали Qt 5 самостоятельно или предпочитаете использовать Qt 4, то тогда Qt Creator надо устанавливать, и данная статья призвана оказать Вам помощь в этом.
Рассмотрим подробно порядок действий.
1. Если это еще не сделано, устанавливаем MinGW (см. здесь).
2. Если это еще не сделано, устанавливаем Qt 4 или собираем Qt 5.
3. Скачиваем с сайта разработчика установочный файл под лицензией LGPL
qt-creator-win-opensource-2.6.2.exe   51 MB(версия файла на момент написания статьи)
4. Устанавливаем Qt Creator. Путь установки, предложенный по умолчанию, можно изменить, но пробелы в нем должны отсутствовать.
5. Собираем отладчик GDB, руководствуясь инструкциями, приведенными в посвященной этому статье. Собранный отладчик, для определенности, размещаем в папке C:\Qt\qtcreator-gdb-7.4.1 и используем цель i686-pc-mingw32.
6. Запускаем Qt Creator, выбираем пункт главного меню Инструменты > Параметры... на вкладке Сборка и запуск > Основное указываем каталог проектов, например, C:\Qt\qt-proj (этот каталог надо заблаговременно создать). На вкладке Текстовый редактор > Поведение назначаемКодировкам файлов > По умолчанию значение windows-1251 / CP1251. Далее выбираем вкладку Сборка и запуск > Профили Qt и убеждаемся, что имеется профиль Qt 4.8.4 в PATH (qt-4.8.4) или Qt 5.0.1 в PATH (qt-5.0.1), и для него определен помощник Дампер QML. Этот профиль добавился, благодаря значению системной переменной QTDIR и пути, прописанному в переменную Path. На вкладке Сборка и запуск > Наборы имеется связка инструментов Desktop (по умолчанию). Для нее выбран правильный компилятор MinGW (x86 32bit), но указан неработающий отладчик GDBC:\Qt\mingw-4.6\bin\gdb.exe или C:\Qt\mingw-4.7\bin\gdb.exe. Надо исправить ситуацию, нажав Управление... > Изменить... и указав собранный выше отладчик C:\Qt\qtcreator-gdb-7.4.1\gdb-i686-pc-mingw32.exe. Закрываем окно Параметры, нажав кнопку OK.
По каким-либо причинам в параметрах Qt Creator может не оказаться автоопределенных компилятора или профиля Qt. Это можно исправить, воспользовавшись кнопкой Добавить на соответствующей вкладке.
На этом установка завершена.
Замечание. Если посмотреть пункт главного меню Справка > О программе Qt Creator..., то можно убедиться, что установленный Qt Creator основан на Qt 4.8.3. Вместе с тем, он работает и с библиотекой Qt 5, поскольку dll-файлы Qt 4 устанавливается вместе с Qt Creator. Если захочется добиться гармонии используемого Qt Creator и библиотеки Qt, то можно пересобрать первый из исходников, опираясь на инструкции из соответствующей статьи. В качестве бонуса Вы сделаете видимыми плагины библиотек Qwt и QwtPolar в дизайнере, интегрированном в Qt Creator.

Простой сервер на Qt/C++

В последнее время очень часто приходится слушать определенный порт, получать данные от клиента и отправлять соответствующий ответ. Решил поделиться с новичками, как же создать такой сервер и решить некоторые поставленные вопросы.
В этой статье мы рассмотрим:
— Создание tcp сервера.
— Подключение нескольких клиентов к серверу параллельно.
— Отключение клиентов (отключение сокетов).
— Получение и отправку данных.

Исходники: https://github.com/valualit/QTcpServer01

image


QTcpServer или слушаем нужный порт

В переменной server_status — храню статус QTcpServer, чтоб не происходило эксцессов при работе сервера (если 0 — то сервер не слушает порт, 1 — слушает).
Сигналы в данном случае решают лишний раз проблему с прослушиванием порта, т.е. слот newuser() в данный момент вызывается только тогда, когда появляется новое подключение к серверу.
    tcpServer = new QTcpServer(this);
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newuser()));
    if (!tcpServer->listen(QHostAddress::Any, 33333) && server_status==0) {
        qDebug() <<  QObject::tr("Unable to start the server: %1.").arg(tcpServer->errorString());
    } else {
        server_status=1;
        qDebug() << QString::fromUtf8("Сервер запущен!");
    }


Подключение нескольких клиентов к серверу параллельно

Код ниже демонстрирует, как создать новый сокет и заставить его слушать сигналы. Так же в нем получаем дескриптор сокета, который используем в качестве ключа для хранения объекта сокета, который пригодится нам при дальнейшей работе.
    if(server_status==1){
        qDebug() << QString::fromUtf8("У нас новое соединение!");
        QTcpSocket* clientSocket=tcpServer->nextPendingConnection();
        int idusersocs=clientSocket->socketDescriptor();
        SClients[idusersocs]=clientSocket;
        connect(SClients[idusersocs],SIGNAL(readyRead()),this, SLOT(slotReadClient()));
    }


QMap<int,QTcpSocket *> SClients; Данная карта хранит объекты созданных сокетов. Ее использую например если принудительно останавливаю сервер и мне необходимо закрыть открытые сокеты. Если их не закрыть, то клиент будет еще долго ждать ответ от нашего сервера и не закрывать соединение. Ниже выложен вариант принудительного закрытия всех сокетов.
    if(server_status==1){
        foreach(int i,SClients.keys()){
            QTextStream os(SClients[i]);
            os.setAutoDetectUnicode(true);
            os << QDateTime::currentDateTime().toString() << "\n";
            SClients[i]->close();
            SClients.remove(i);
        }
        tcpServer->close();
        qDebug() << QString::fromUtf8("Сервер остановлен!");
        server_status=0;
    }


При создании нового сокета Вы уже наверно заметили сигнал readyRead(), он выполняется когда клиент передает какие-то данные на наш сервер, в этот момент мы и будем давать ответ нашему клиенту, предварительно получив данные.

    // Получаем объект сокета, который вызвал данный слот
    QTcpSocket* clientSocket = (QTcpSocket*)sender();
    // Получаем дескриптор, для того, чтоб в случае закрытия сокета удалить его из карты
    int idusersocs=clientSocket->socketDescriptor();
    // Пример отправки ответа клиенту
    QTextStream os(clientSocket);
    os.setAutoDetectUnicode(true);
    os << "HTTP/1.0 200 Ok\r\n"
          "Content-Type: text/html; charset=\"utf-8\"\r\n"
          "\r\n"
          "<h1>Nothing to see here</h1>\n"
          << QDateTime::currentDateTime().toString() << "\n";
    // Полученные данные от клиента выведем в qDebug, 
    // можно разобрать данные например от GET запроса и по условию выдавать необходимый ответ. 
    qDebug() << clientSocket->readAll()+"\n\r");
    // Если нужно закрыть сокет
    clientSocket->close();
    // Удалим объект сокета из карты
    SClients.remove(idusersocs);


Таким образом мы получаем сервер (например HTTP), который слушает порт 33333, сможет обрабатывать сразу несколько запросов одновременно и отдавать нужный результат.

image

среда, 18 декабря 2013 г.

Qt+OpenGl

Данная cтатья вводная, рассчитана на знакомство с Qt+OpenGL для новичков, которые планируют изучать Qt (как кросс-платформенный инструментарий разработки ПО на языке программирования C++) + OpenGL (как графическую библиотеку).

Что потребуется новичку:
1) Qt Creator (имеет хорошую встроенную документацию и подсказки во время набора кода). Скчаать
2) doc.qt.nokia.com — официальная документация на английском языке
3) doc.crossplatform.ru — документация на русском языке
4) Обязательно прочесть про Qt и OpenGL
5) Отличная статья для начала изучения

Что мы будем делать
Поскольку данная статья посвящена конкретно основам, в нашей задаче будет следующее:
1) Разобрать как создается приложение
2) Как рисовать объекты
3) Как работать с указателем мыши и событиями(нажатие клавиш на клавиатуре и на мышке)
4) Работа с таймером
5) Создадим нашу первую банальную игру. Будем с помощью таймера, случайным образом перемещать квадрат. После наведения на квадрат указателя и кликнув по нему левой кнопки мышки, в случае попадания по квадрату, будем прибавлять к полученным очкам +1.



Создаем проект

При открытии Qt Creator, начинаем создавать новый проект.
Выбираем проект Qt Widget -> GUI приложение Qt
В разделе Информация о классе снимает галочку для создания формы.
В результате действий мы получим проект с файлами:
opengl.pro — необходим для компиляции нашего проекта
mainwindow.h — для объявления всех глобальных данных
main.cpp 
mainwindow.cpp — методы нашей программы

Подключение библиотек

В файле *.pro вашего проекта в строке Qt += необходимо дописать opengl для того, чтоб подключить использование библиотеки opengl. Таким же образом подключаются и другие библиотеки.

В файле mainwindow.h — если у вас имя по умолчанию выбрано, необходимо подключить:
#include <QGLWidget>
#include <QtOpenGL>
#include <QTimer>


Предопределение для нас нужных методов и переменных

Открываем mainwindow.h
В первую очередь сменим:
class MainWindow: public QMainWindow
на
class MainWindow: public QGLWidget
Это потому, что QMainWindow — класс для вывода простого окна, а т.к. мы будем работать с opengl, нам понадобится QGLWidget — это класс для вывода графики, реализующий функции библиотеки OpenGL.

Теперь предопределим переменные и методы
protected:
    int geese_size; // Сторона квадрата
    int point; // набранные очки
    int gdx, gdy; // Координаты квадрата
    int cax, cay, cbx, cby; // Координаты курсора (текущие и начальные(при зажатии клавиши мыши) для выделение области)
    int wax ,way; // Размеры окна нашей программы
    bool singling; // Для выделение области, если true то рисуем прямоугольник по координатам cax, cay, cbx, cby
    void self_cursor(); // метод для рисования своего курсора
    void initializeGL(); // Метод для инициализирования opengl
    void resizeGL(int nWidth, int nHeight); // Метод вызываемый после каждого изменения размера окна
    void paintGL(); // Метод для вывода изображения на экран
    void keyPressEvent(QKeyEvent *ke); // Для перехвата нажатия клавиш на клавиатуре
    void mouseMoveEvent(QMouseEvent *me); // Метод реагирует на перемещение указателя, но по умолчанию setMouseTracking(false)
    void mousePressEvent(QMouseEvent *me); // Реагирует на нажатие кнопок мыши
    void mouseReleaseEvent(QMouseEvent *me); // Метод реагирует на "отжатие" кнопки мыши
    void singling_lb(); // Рисуем рамку выделенной области
    void geese(); // Рисуем квадрат по которому кликать для получения очков


Так же у нас есть один слот, для того, чтоб по таймеру пересчитывать новые координаты квадрата по которому кликать.

protected slots:
    void geese_coord(); // Определяем координаты объектов


Принцип построения изображения

QGLWidget так устроен, что при первой инициализации класса он автоматически вызывает методы в следующем порядке:
При запуске: initializeGL()->resizeGL()->paintGL()
При изменении размера окна: resizeGL()->paintGL()
updateGL() вызывает paintGL()

initializeGL — необходимо использовать для глобальных настрое построения изображения, которые нет необходимости указывать при построении кадра.
resizeGL — служит для построения размера окна. Если в ходе работы изменится размер окна, но не изменить область просмотра, то при увеличении размера можно наблюдать непредсказуемые явления.
paintGL — этот метод будет выстраивать каждый наш кадр для отображения.
    glClear(GL_COLOR_BUFFER_BIT); // чистим буфер
    glMatrixMode(GL_PROJECTION); // устанавливаем матрицу
    glLoadIdentity(); // загружаем матрицу
    glOrtho(0,500,500,0,1,0); // подготавливаем плоскости для матрицы
    // BlendFunc позволяет работать в альфа режиме, например если нам нужно указывать прозрачность
    // glEnable(GL_BLEND);
    // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    qglColor(Qt::white); // Дальше рисуем белым цветом
    //  renderText позволяет писать текст на экран, так же можно указать различный стиль (читаем QFont)
    renderText(10, 10 , 0, QString::fromUtf8("Вы набрали %1 очков:").arg(17), QFont() , 2000);

    // glBegin и glEnd - обозначают блок для рисования объекта(начало и конец), glBegin принимает параметр того, что нужно рисовать.
    glBegin(GL_POLYGON);
        glColor4f(0,1,0, 0.25);// Цвет которым рисовать
        glVertex2f(200, 300); // Точка 1 из 4 - отсчет по часовой стрелке
        glVertex2f(300, 300);
        glVertex2f(300, 400);
        glVertex2f(200, 400);
    glEnd();
    swapBuffers();


Для чего двойная буферизация

PaintGL сразу картинку не рисует на экран, а заносит в буфер, а по запросу swapBuffers() заменяет текущие изображение на то, что появилось в буфере. Сама по себе буфериция позволяет более корректно заменять изображение, чтоб не происходили скачки на экране.

События клика мыши

mousePressEvent() — метод автоматически вызывается при нажатии клавиш мыши. В передаваемых параметрах можно получить различную информацию например какой именно кнопкой было сделано нажатие и по какой точке по координатам.
-Данное событие в нашем примере используется для определения куда кликнули мышью, затем если наши координаты находятся в поле квадрата, то добавляем к нашим очкам + 1 и перестраиваем наш кадр.
-Так же используем для определения начальных координат для выделения области на экране, при зажатии и перемещении указателя.

Событие перемещения указателя мыши

mouseMoveEvent() — автоматически вызывается при изменении координат указателя мыши. Но есть одно Но, по умолчанию установлено setMouseTracking(false), поэтому событие вызывается только при условии нажатия клавиш мыши, для того, чтоб метод вызывался даже без нажатия необходимо установить setMouseTracking(true).
— Данный метод мы используем для получения текущего положения указателя, чтоб перестроить выделение области или нарисовать собственный курсор.

Событие когда «отжимается» кнопка мыши

mouseReleaseEvent() — автоматически вызывается при условии «отжатия» кнопки мыши. Так же принимает различные параметры.
— В данном случае мы используем метод, чтоб стереть с экрана выделенную нами область.

Событие нажатие клавиш на клавиатуре

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

Таймер

QTimer — позволяет нам создать поток, который будет слушать сигналы и запускать соответственные слоты.
— В данном случае мы создаем таймер, который будет ждать 750мс после чего он завершает свою работу, отправляя нам сигнал timeout() , но мы при окончании сигнала будем не останавливать работу, а снова запускать слот на переопределение координат квадрата, по которому нужно кликать для того, чтоб набрать очки.
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(geese_coord()));
    timer->start(750);


Задание по данному материалу для усвоения.

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

Заключение!

Большинство из немногого написанного здесь, в нашей первой примитивной игре просто не нужно. Но хочу отметить еще раз: "Статья вводная, рассчитана на знакомство с Qt+OpenGL". Так же если Вы заметили написанные таким образом программы можно компилировать для любой операционной среды.