Сравнение потребления памяти различных gui тулкитов

Знакомство с OpenGL

Так как мы будем разрабатывать платформо-независимую программу, наш выбор пал именно на OpenGL.


Данная графическая библиотека включает в себя более 250 функций для рисования сложных трёхмерных сцен из простых примитивов.

В основном используется при создании компьютерных игр, САПР (Система автоматизированного проектирования), виртуальной реальности, визуализации в научных исследованиях.

Стандарт OpenGL, с появлением новых технологий, позволяет отдельным производителям добавлять в библиотеку функциональность через механизм расширений. Расширения распространяются с помощью двух составляющих: заголовочный файл, в котором находятся прототипы новых функций и констант, а также драйвер устройства, поставляемого разработчиком. Каждый производитель имеет аббревиатуру, которая используется при именовании его новых функций и констант. Например, компания NVIDIA имеет аббревиатуру NV, которая используется при именовании её новых функций, как, например,glCombinerParameterfvNV(), а также констант, GL_NORMAL_MAP_NV. Может случиться так, что определённое расширение могут реализовать несколько производителей. В этом случае используется аббревиатура EXT. В случае же, когда расширение одобряется консорциумом ARB, оно приобретает аббревиатуру ARB и становится стандартным расширением. Обычно расширения, одобренные консорциумом, включаются в одну из следующих спецификаций OpenGL.

«Змейка»: создание и особенности реализации

В рамках проекта была разработана программа «Змейка» для демонстрации преимуществ кроссплатформенного фреймворка Qt и графической библиотеки OpenGL; я не ставил перед собой задачу написать программу, которая «взорвёт» рынок, главным было получить практический опыт разработки кроссплатформенных приложений и усовершенствовать свои навыки реального программирования.

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

Программный интерфейс включал в себя элегантный и переносимый код возможность поддержки, которого реализована с помощью GitHub’a.

В конечном итоге получился достаточно неплохой готовый продукт. Далее рассмотрим его более подробно.

Компиляция и запуск приложения

1. Компиляция приложения

После того, как все компоненты настроены, осталось скомпилировать и запустить наш код. В левом нижнем углу экрана Qt Creator вы можете увидеть кнопку Запустить, жмите на неё.

Подсказка справа говорит нам, что можно использовать сочетание клавиш Ctrl + R для этих целей, запомним это на будущее, дабы сэкономить наше драгоценное время. С другими сочетаниями клавиш можно познакомиться на официальном сайте Qt или в разделе Справка. 

Потребуется немного времени для того, чтобы Qt Creator скомпилировал ваше приложение. В вашем случае это должно занять не более минуты. Тогда как в достаточно сложных проектах компиляция может занимать порядка нескольких десятков минут. После этого вам предстоит сделать выбор устройства для запуска вашего приложения.

2. Выбор устройства для запуска приложения

Всего существуют два варианта для запуска ваших Android-приложений:

  1. Запуск приложения на Android-эмуляторе
  2. Запуск приложения на реальном устройстве

В первом случае вам потребуются виртуальное Android-устройство, а также установка Android Emulator из Android SDK (о том, как это сделать, я расскажу дальше). На этапе выбора компонент установки Android SDK мы указали пункт AVD, поэтому волшебник установки уже создал для нас одно виртуальное устройство Android.

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

Список доступных устройств

По завершении процесса компиляции, перед вами должно появиться следующее окно:

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

Запуск приложения на реальном устройстве

Теперь если вы выбрали использовать своё Android-устройство, то вам нужно сперва убедиться что оно представлено в открывшемся списке доступных устройств. Если вашего устройства в списке нет, то это может произойти по 3-м причинам:

  1. Вы не подключили устройство к компьютеру. Вам нужно подключить ваше устройство через провод USB.
  2. Вы не перевели своё устройство в режим отладки. Обычно это делается путём 7-и кратного нажатия на пункт Номер сборки в разделе меню Настройки -> О телефоне (планшете), после чего выбирается пункт Разрешить отладку по USB в разделе Настройки -> (Дополнительно ->) Для разработчиков. Подробнее о том как это сделать вы можете узнать здесь.
  3. В системе отсутствует драйвер вашего устройства. Это отдельная песня. Если предыдущие пункты выполнены, а устройство так и не обнаружилось, то пока что вам лучше использовать эмулятор.

Запуск приложения на эмуляторе

Если вы хотите использовать эмулятор, то вам скорее всего потребуется установка дополнительной компоненты из Android Studio.

3. Установка Android Emulator

Запустите Android Studio, воспользовавшись значком на вашем Рабочем столе или поиском программ в меню Windows.

Далее вам нужно выбрать пункт Configure в правом нижнем углу открывшегося окна приветствия и нажать на SDK Manager в выпавшем списке.

Если вы хотите создать своё виртуальное AVD устройство, то вам достаточно запустить AVD Manager, который предложит вам эту опцию.

В открывшемся окне настроек перейдите на вкладку SDK Tools и отметьте галочкой пункт Android Emulator. Нажмите на кнопку OK.

Далее подтвердите ваше согласие с лицензией и нажмите Next.

Подождите пока Android Emulator не будет установлен.

4. Запуск вашего первого Android-приложения

Вернёмся к списку доступных Android-устройств. Теперь вам остаётся найти ваше устройство в списке, выбрать его и нажать на кнопку OK.


После этого, если вы используете эмулятор, вам придётся немного подождать пока он загрузится. 

Подготовка и настройка сервера на FreeBSD

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

Для начала мы выкупили виртуальный сервер у хостера firstvds, процесс оказался довольно не сложный, в связи с тем, что я имел опыт работы с данным хостером и «возведением» серверов/баз данных.

Для начала к «новоиспечённому» серверу нужно было как-то подключаться, для данной цели мы выбрали, PuTTY — свободно распространяемый клиент для различных протоколов удалённого доступа, включая SSH, который нам и был нужен.

Далее нам нужно установить MySQL сервер, для этого мы использовали документацию из доверенных источников (ссылка прилагается в списке литературы), предварительно обновив порты (список пакетов).

После возведения MySQL сервера, нужно было настроить права доступа.

Как и любой толковый сисадмин, я решил ограничить подключения для всех пользователей кроме того, что был создан для подключения программно по ip.

Над именем пользователя для программы мы особо не задумывались, по этому, было решено назвать его «programm».

Из соображений безопасности данный пользователь имел доступ только к базе данных рекордов, о который мы ниже поговорим.

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

Для администрирования базы данных был выбран MySQL клиент – Navicat.

Так, как мы будем фиксировать рекорды пользователей, нам нужно их где-то хранить информацию о пользователях и их рекордах.

Для данной цели было решено создать 2 таблицы:

  • Account – Таблица содержащая информацию о пользователях
  • Record – Таблица содержащая информацию о достижениях пользователей

В таблице аккаунтов было решено хранить:

  • Id – Уникальный номер записи в таблице
  • Name – Уникальное имя аккаунта
  • Password – Пароль аккаунта (пароль из соображений безопасности хранятся в md5)

Прилагаю иллюстрацию структур таблиц:

Account:

Record:

Из данных иллюстраций ясно видна связь таблицы рекордов и таблицы аккаунтов.

These are third party language bindings for Qt

Ring uses Qt as its toolkit to provide cross-platform abilities.

QtJambi is Qt bindings for the Java programming language originally developed by Trolltech, the predecessor of The Qt Company.

The QtJambi5 project provides these bindings for the latest Qt5 releases and Java JDK versions.

Qt bindings for the Rust language

Project on Github

QML bindings for the Rust language

  • QML bindings for the Rust language

QML bindings for the Crystal language

Qt bindings for Go language

Qt bindings for Java

This project aims to create Mono/.NET libraries that wrap Qt thus enabling its usage through C#. It relies on the excellent CppSharp.

Qml.Net is cross-platform integration of Qml/QtQuick for .NET Core/.NET Framework/Mono. It is a binding that brings .NET types into JavaScript with full interoperability.

The qtHaskell project provides a comprehensive set of Haskell bindings for 50 Qt modules with extensive examples and demo programs including qtHaskell versions of Tetrix, DiagramScene, PathDeform and the Qt Asteroids game which uses FRP (Functional Reactive Programming) techniques to control game states and behaviors.

The qtah project provides a set of Haskell bindings for Qt.

This project provides bindings to Julia.

HsQML provides a Haskell binding to the Qt Quick framework. It allows you to write graphical applications where the front-end is written in Qt Quick’s QML language (incorporating JavaScript) and the back-end is written in Haskell.

QML Bindings to OCaml.

Build performant, native and cross-platform desktop applications with Node.js and CSS like styling. NodeGUI is powered by Qt Widgets which makes it CPU and memory efficient as compared to other chromium based solutions like electron.

Qt Quick: The Brig project provides library for Qt Quick framework, making it possible to write graphical applications in JavaScript and QML languages.

Nelson is an array programming language providing a powerful open computing environment for engineering and scientific applications using modern C/C++ libraries and others state of art numerical libraries.

Top qapplication Askers

All Time

18

Sir2B 54655 silver badges1414 bronze badges

13

Valla 1,96477 gold badges3737 silver badges6464 bronze badges

11

Sir Visto 63744 silver badges77 bronze badges

8

Bush Walker 8111 silver badge55 bronze badges

7

DeducibleSteak 1,25699 silver badges1919 bronze badges

7

marius_linux 58544 silver badges1414 bronze badges

7

Nicolas Holthaus 6,15933 gold badges3131 silver badges7575 bronze badges

6

Marcel H. 12711 silver badge1313 bronze badges

6

Zhigalin — Reinstate CMs 63577 silver badges3030 bronze badges

6

d21d3q 19511 silver badge88 bronze badges

5

Aquarius_Girl 16.5k5353 gold badges172172 silver badges328328 bronze badges

5

Anže 18188 bronze badges

4

tinlyx 17.6k2323 gold badges7474 silver badges136136 bronze badges

4

ComradeJoecool 54133 silver badges1515 bronze badges

4

cbuchart 7,97266 gold badges3939 silver badges6363 bronze badges

4

The Beast 1,36511 gold badge2323 silver badges3535 bronze badges

4

ScumCoder 58011 gold badge44 silver badges1616 bronze badges

4

user2717575 26333 silver badges1616 bronze badges

3

AFP 1,28788 silver badges1919 bronze badges

3

Flare Cat 50122 gold badges1010 silver badges2121 bronze badges

Only non community-wiki questions and answers are included in these totals (updated daily)

Путь к файлу

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

#include <QTextStream> #include <QFileInfo> #include <conio.h>

int main(int argc, char *argv[]) { QTextStream out(stdout); out.setCodec(«cp-866»);

if (argc != 2) { out << «Usage: file_times file» << endl; return 1; } QString filename = argv; // Определяем путь к файлу QFileInfo fileinfo(filename); QString absPath = fileinfo.absoluteFilePath(); // возвращаем абсолютный путь, включающий имя файла QString baseName = fileinfo.baseName(); // возвращаем базовое имя: имя файла без пути QString compBaseName = fileinfo.completeBaseName(); // возвращаем полное базовое имя: все символы в файле до последней точки (но не включая её) QString fileName = fileinfo.fileName(); // возвращаем имя файла, которое является базовым именем + расширение QString suffix = fileinfo.suffix(); // возвращаем расширение файла, которое состоит из всех символов в файле после последнего символа точки (но не включая её) QString compSuffix = fileinfo.completeSuffix(); // возвращаем расширение файла, которое состоит из всех символов в файле после первого символа точки (но не включая её) out << «Absolute file path: » << absPath << endl; out << «Base name: » << baseName << endl; out << «Complete base name: » << compBaseName << endl; out << «File name: » << fileName << endl; out << «Suffix: » << suffix << endl; out << «Whole suffix: » << compSuffix << endl; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

#include <QTextStream> #include <QFileInfo> #include <conio.h>  

intmain(intargc,char*argv){

QTextStream out(stdout);

out.setCodec(«cp-866»);


if(argc!=2){

out<<«Usage: file_times file»<<endl;

return1;

}

QString filename=argv1;

// Определяем путь к файлу

QFileInfo fileinfo(filename);

QString absPath=fileinfo.absoluteFilePath();// возвращаем абсолютный путь, включающий имя файла

QString baseName=fileinfo.baseName();// возвращаем базовое имя: имя файла без пути

QString compBaseName=fileinfo.completeBaseName();// возвращаем полное базовое имя: все символы в файле до последней точки (но не включая её)

QString fileName=fileinfo.fileName();// возвращаем имя файла, которое является базовым именем + расширение

QString suffix=fileinfo.suffix();// возвращаем расширение файла, которое состоит из всех символов в файле после последнего символа точки (но не включая её)

QString compSuffix=fileinfo.completeSuffix();// возвращаем расширение файла, которое состоит из всех символов в файле после первого символа точки (но не включая её)

out<<«Absolute file path: «<<absPath<<endl;

out<<«Base name: «<<baseName<<endl;

out<<«Complete base name: «<<compBaseName<<endl;

out<<«File name: «<<fileName<<endl;

out<<«Suffix: «<<suffix<<endl;

out<<«Whole suffix: «<<compSuffix<<endl;

}

Примечание: Для запуска программы см. часть «Размер файла» (Подготовка и Запуск программы).

Результат выполнения программы выше:

Вместо заключения

Я умышленно избегал технических деталей, чтобы не породить бессмыссленных дебатов о способах реализации конкретных решений. Для связки фронтенда/PHP/C++ cуществует огромное количество возможных комбинаций функций отдельных компонентов и их взаимного размещения, способов хранения информации и обмена сигналами/сообщениями, возможностей разработчиков в конкретном коллективе и т.д. Но однозначно можно говорить, что для всего этого уже всё придумано, на stackoverflow уже всё есть беспокоиться нечего.

Основной посыл такой – в огромном пласте приложений нет особых причин продолжать использовать Qt, а где-то теперь есть и противопоказания. И многое, что надо для замены, и в значительно большем количестве, уже есть в web-технологиях, от компоновки интерфейса до вывода графиков и трёхмерных моделей. И технологии эти теперь имеют человеческое лицо со всех сторон: для владельца бизнеса, для пользователя, для программиста, и при общении с быстрым нативным кодом. Будем с ними дружить. А вот будем ли скучать по Qt — не знаю…

Important macros

The most important macro is Q_OBJECT. Signal-Slot connections and their syntax cannot be interpreted by a regular C++ compiler. The moc is provided to translate the QT syntax like «connect», «signals», «slots», etc into regular C++ syntax. This is done by specifying the Q_OBJECT macro in the header containing class definitions that use such syntax.

mywidget.h

class MyWidget  public QWidget
{
 Q_OBJECT
 public
  MyWidget(QWidget *parent = );
}

Others marker macros for moc are

  • signals
  • public / protected / private slots

that mark the different methods that need to be extended.

SIGNAL and SLOT are also two very important and useful macros. When a signal is emitted, the meta-object system is used to compare the signature of the signal, to check the connection, and to find the slot using it’s signature. These macros are actually used to convert the provided method signature into a string that matches the one stored in the meta-object.

Qt class hierarchy

Qt widely uses inheritance, especially in the Widgets module. The following graph shows some of these inheritances:

is the most basic class in Qt. Most of classes in Qt inherit from this class. QObject provides some very powerful capabilities like:

  • object name : you can set a name, as a string, to an object and search for objects by names.
  • parenting system (described in the following section)
  • signals and slots (described in the next chapter)
  • event management

Widgets are able to respond to events and use parenting system and signals and slots mechanism. All widgets inherit from QObject. The most basic widget is the . QWidget contains most properties that are used to describe a window, or a widget, like position and size, mouse cursor, tooltips, etc.

Remark : in Qt, a widget can also be a window. In the previous section, we displayed a button that is a widget, but it appears directly as a window. There is no need for a «QWindow» class.

Nearly all graphical elements inherit from QWidget. We can list for example:

QAbstractButton, a base class for all button types
  QPushButton
  QCheckBox
  QRadioButton
QFrame, that displays a frame
QLabel, that displays text or picture

This inheritance is done in order to facilitate properties management. Shared properties like size and cursors can be used on other graphical components, and provides basic properties that are shared by all buttons.

Widgets

Radio button is a standard GUI component. It is often used to make a unique choice from a list. In Qt, the is used to create radio buttons.

Thanks to a nice heritance, a QRadioButton behaves just like a QPushButton. All properties of the QPushButton are also the same in the QRadioButton, and everything that was learned in the second chapter can be reused here.

  • text
  • icon
  • tooltip

By default, QRadioButtons are not grouped, so many of them can be checked at the same time. In order to have the «exclusive» behaviour of many radio buttons, we need to use . This class can be used like this: We allocate a new button group and attach it to the parent object. Note that the parent object might be the mainwindow, or «this»:

QButtonGroup *buttonGroup = new QButtonGroup(object);

// Add buttons in the button group
buttonGroup->addButton(button1);
buttonGroup->addButton(button2);
buttonGroup->addButton(button3);
...

What we want is to create a menu picker. In a window, a list of yummy plates should be displayed with radio buttons, and a push button that is used to select the chosen plate should be displayed.

Obviously, nothing will happen (now) when the buttons are clicked.

Установка Qt Creator в Linux

В этих уроках используется операционная система Linux (Debian 9.x 64-bit), поэтому мы скачиваем , но вы также можете использовать соответствующие файлы Qt для Windows или Mac:

После окончания загрузки переходим в папку с необходимым нам файлом, нажимаем по нему правой кнопкой мыши и выбираем «Свойства». В закладке «Основные» видим «Имя», «Тип», «Размер файла», а также наименование родительской папки:

Переходим на вкладку «Права» и ставим галочку в поле «Разрешить выполнение файла как программы»:

Закрываем «Свойства» и запускаем программу.

Шаг №2: На следующем этапе установщик сообщает, что нам предоставлена версия с открытым исходным кодом Qt 5.13.0. Дальнейшая установка Qt предполагает регистрацию в Qt и создание Qt Account, который предоставляет доступ ко всем возможностям Qt. Кроме того, данное действие необходимо для проверки лицензии (коммерческая/некоммерческая). Если у вас уже есть учётная запись в Qt Account, то используйте кнопку «Next».

Если учётной записи в Qt Account у вас ещё нет, то её можно создать сейчас: для этого перейдите по соответствующей ссылке в установщике, и вы будете перенаправлены на сайт qt.io в соответствующий раздел, или просто используйте кнопку «Next» — вы сможете это сделать в следующем шаге:

Шаг №3: Здесь необходимо ввести логин и пароль от Qt Account или создать Qt Account, если его ещё нет. Кнопка «Next» переводит нас на следующий этап:

 Добро пожаловать в настройки Qt 5.13.0! Для перехода к следующему шагу нажимаем «Далее»:

Шаг №4: Выбираем каталог для установки Qt 5.13.0

Обратите внимание, адрес каталога указывается латинскими буквами (без кириллицы) и без пробелов! После того, как выбрали каталог, нажимаем «Далее»:

Шаг №5: Выбираем компоненты, которые хотим установить. Если на данном этапе нет уверенности в выборе конкретных компонентов, то добавление и удаление можно будет сделать позже, после установки программы:

Шаг №6: Принимаем лицензионное соглашение:

И нажимаем на кнопку «Установить»:


Для завершения установки нажимаем «Завершить». После завершения загрузки Qt Creator запустится самостоятельно (для этого необходимо по умолчанию оставить галочку в поле «Launch Qt Creator»):

Вот примерно следующее вы должны увидеть при запуске Qt Creator:

Поздравляем! Qt Creator установлен.

How a Qt program is compiled

Qt Creator does the job of invoking the build system for us, but it might be interesting to know how Qt programs are compiled.

For small programs, it is easy to compile everything by hand, creating objects files, then linking them. But for bigger projects, the command line easily becomes hard to write. If you are familiar with Linux, you may know that all the programs are compiled using a makefile that describes all these command lines to execute. But for some projects, even writing a makefile can become tedious.

qmake is build system that comes with Qt, and it generates those makefiles for you (there are others that can be used, but we here give the example with qmake). With a simple syntax, it produces the makefile that is used to compile a Qt program. But that is not its only goal. Qt uses meta-objects to extend C++ functionalities, and qmake is responsible for preparing a makefile that contains this meta-object extraction phase. You will see this in another chapter.

So, Qt apps are compiled in 3 steps

  1. A .pro file is written to describe the project to compile
  2. A makefile is generated using qmake
  3. The program is built using make (or nmake or jom on windows)

Владелец файла и группы

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

extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; qt_ntfs_permission_lookup++; // включение проверки

1 2

externQ_CORE_EXPORT intqt_ntfs_permission_lookup;

qt_ntfs_permission_lookup++;// включение проверки

Каждый файл имеет конкретного пользователя, который является его владельцем. Файл также принадлежит и некоторой группе пользователей. В следующем примере выводится информация о владельце и основной группе файла, с которым мы работаем:

#include <QTextStream> #include <QFileInfo>

int main(int argc, char *argv[]) {

extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; qt_ntfs_permission_lookup++; // включение проверки QTextStream out(stdout);

if (argc != 2) { qWarning(«Usage: owner file»); return 1; } QString filename = argv; // Создаём объект класса QFileInfo. В качестве параметра используем имя файла из аргумента командной строки QFileInfo fileinfo(filename); // Определяем основную группу файла QString group = fileinfo.group();

// Определяем владельца файла QString owner = fileinfo.owner(); out << «Group: » << group << endl; out << «Owner: » << owner << endl; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

#include <QTextStream> #include <QFileInfo>  

intmain(intargc,char*argv){

externQ_CORE_EXPORT intqt_ntfs_permission_lookup;

qt_ntfs_permission_lookup++;// включение проверки

QTextStream out(stdout);

if(argc!=2){

qWarning(«Usage: owner file»);

return1;

}

QString filename=argv1;

// Создаём объект класса QFileInfo. В качестве параметра используем имя файла из аргумента командной строки

QFileInfo fileinfo(filename);

// Определяем основную группу файла

QString group=fileinfo.group();

// Определяем владельца файла

QString owner=fileinfo.owner();

out<<«Group: «<<group<<endl;

out<<«Owner: «<<owner<<endl;

}

Примечание: Для запуска программы см. часть «Размер файла» (Подготовка и Запуск программы).

Результат выполнения программы выше:

Установка через командную строку в Linux

Ещё одним альтернативным и простым способом установки Qt Creator в Linux на основе Debian является установка из пакетов. Если при работе с Linux вы используете терминал, то перед скачиванием и установкой Qt Creator программа запросит пароль sudo пользователя. Только после этого начнётся скачивание и извлечение файлов. Обычно пакты Linux не содержат последней версии Qt и их необходимо обновить. Ниже приведен алгоритм действий, позволяющий за 4 шага установить Qt Creator через терминал.

Шаг №1. Обновление:

Шаг №2. Скачивание и установка Qt:

Шаг №3. Установка Qt Creator:

Шаг №4. Исходники:


С этим читают