QtE5 – изучаем D и Qt-5 в комфортной графической среде

Немного лирики или с чего всё началось. Глядя на красивый KDE в Linux, мне хотелось научится писать программы и для него. Так я узнал о Qt. Всё хорошо, потихоньку изучаю, но «давит» гигантизм и запутанность С++. Хочется чего то компактного, быстрого и интелектуального. На глаза попадается D созданный Уолтером Брайтом. В своё время я начал изучение С++ с Zortech C++ (позже ставшего Symantec C++, а затем Digital Mars C++) и ни каких проблем с ним я не имел. Начал изучение D, который отлично работает в Windows/Linux, но вот проблема, хочется доступа к Qt. В инете есть QtD, но сколько я не пытался его реанимировать, ничего не получилось. Вот и решил я сделать что то для себя, благо ни куда не торопился.

QtE5 – это биндинг (обертка) функций Qt-5 в функции D. Сразу подчеркиваю, что Qt огромен, а QtE5 всего лишь очень маленькая его часть. Да, я постоянно дописываю новые функции, по мере изучения Qt и по мере необходимости в них, так как все свои проекты пишу на D + QtE5 + Qt. На момент написания статьи функций Qt в QtE5 около 400 штук.

QtE5 проверена и работает на Windows 32 (Win XP, 7, 10), Windows 64 ( Win 7, 10), Linux 32/64 (Fedora 23), Mac Os X 64 (Хакинтош Mavericks 10.9).

Примеры ниже – это Win 32 (Win 7). Для работы нам понадобится D (dmd) и RunTime Qt-5. Устанавливать Qt из дистрибутива нет необходимости, если вы не собираетесь расширять QtE5. Скачать QtE5 + RunTime Qt-5 можно с репозитория гитхаба. Для понимания работы исходного кода желательно иметь представление о работе Qt. Имена методов и классов в QtE5 повторяют имена в Qt, что позволяет пользоваться справочной системой самой Qt.

Первое приложение – классика. Привет мир! Сохраним текст в файле ex2.d

// ex2.d
import qte5;               // Подключим QtE5
import core.runtime;       // Разбор аргументов ком.строки

int main(string[] args) {
	// Загрузим и инициализируем QtE5
	if (1 == LoadQt(dll.QtE5Widgets, true)) return 1;
	// Создадим объект приложения
	QApplication app = new QApplication(&Runtime.cArgs.argc, Runtime.cArgs.argv, 1);
	// Создадим виджет Label
	QLabel lb = new QLabel(null);
	// Добавим в него текст (поддерживается HTML) и обобразим
	lb.setText("<h1>Привет мир!</h1>").show();
        // Начнем цикл обработки графических событий
	app.exec();
        // Закончим программу 
	return 0;
}

Компиляция и запуск:

dmd ex2 qte5
ex2

Результат:

1

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

Нажми на кнопку и получишь результат!

Сразу несколько замечаний. Что мы хотим и должны получить. Будем изготавливать форму (простенькую) с двумя кнопками и надписью. При нажатии на кнопку будем выводить текст в консоль Windows русскими буквами и отображать окно сообщения.

Файл Ex5.d

// ex5.d
import qte5;		// Подключим QtE5
import asc1251;	// Работа с русскими буквами в консоли Windows
import core.runtime;
import std.stdio;

// Обработчики событий
extern (C) {
	void on_acKn1() {
		string s = "Нажата кнопка № 1";
		writeln(toCON(s)); msgbox(s);
	}
	void on_acKn2() {
		string s = "Нажата кнопка № 2";
		writeln(toCON(s)); msgbox(s);
	}
}
class Forma : QWidget {
	QVBoxLayout	vblAll;		// Общий вертикальный выравниватель
	QHBoxLayout	hblKn;		// Горизонтальный выравниватель для кнопок
	QLabel lb;			// Надпись
	QPushButton kn1, kn2;		// Кнопки
	QAction acKn1, acKn2;		// События кнопок
	// ________________
	this(QWidget parent, QtE.WindowType fl) {
		super(parent, fl);
		resize(300, 100);
		setWindowTitle("Пример работы кнопок");
		// Горизонтальный и вертикальный выравниватели
		vblAll = new QVBoxLayout();
		hblKn  = new QHBoxLayout();
		// Надпись
		lb = new QLabel(this);
		lb.setText("<h1>Работа с кнопками</h1>");
		// Кнопки
		kn1 = new QPushButton("Кнопка № 1", this);
		kn2 = new QPushButton("Кнопка № 2", this);
		// События
		acKn1 = new QAction(this, &on_acKn1, null); 
		acKn2 = new QAction(this, &on_acKn2, null); 
		// Связываем нажатие кнопок с обработчиками событий
		connects(kn1, "clicked()", acKn1, "Slot()");
		connects(kn2, "clicked()", acKn2, "Slot()");
		// Кнопки в горизонтальный выравниватель
		hblKn.addWidget(kn1).addWidget(kn2);
		// Всё в вертикальный выравниватель
		vblAll.addWidget(lb).addLayout(hblKn);
		// Вертикальный выравниватель в форму
		setLayout(vblAll);
	}
}

int main(string[] args) {
	if (1 == LoadQt(dll.QtE5Widgets, true)) return 1;
	QApplication app = new QApplication(&Runtime.cArgs.argc, Runtime.cArgs.argv, 1);
	Forma f1 = new Forma(null, QtE.WindowType.Window);
	f1.show();
	app.exec();
	return 0;
}

Компиляция и запуск:

dmd ex5 qte5 asc1251
ex5

           

Результат:

2

В этом примере несколько интересных моментов. Первое, это обработчики события. Они обязательно должны быть объявляны как Extern (C) … Это связано с тем, что QtE5 может работать с любым языком программтрования поддерживающим такие обратные вызовы. Второе, это

connects(kn1, "clicked()", acKn1, "Slot()");

Это стандартная связка сигналов и слотов в Qt. Очень большое достижение QtE5 в том, что с одной стороны она позволяет обойтись без метакомпилятора Qt, а с другой стороны сохраняет механизм сигналов/слотов, тем самым обеспечивая очень гибкую структуру взаимодействия различных частей программы друг с другом. И последний момент, на который хотелось бы обратить внимание. Это «сложность» компиляции приложения. Ни огромных Make файлов, ни длинных ключей компилятора, да и время компиляции – мгновенно. Чудес конечно не бывает, и за это приходится платить отсутствием гибкости в других моментах, но для обычных, рядовых программ это не существенно.

Считаю, что QtE5 хорошее дополнение к D,  что бы сделать его изучение приятным и полезным.

Создатель QtE5 Мохов Геннадий Владимирович (MGW)

От администрации блога: благодарим Геннадия Владимировича за прекрасную статью и очень важную для развития D библиотеку-связку с Qt5!

Добавить комментарий