Основной алгоритм прост. Он укладывается в следующую схему: - Г
рузим в память QtGui и QtCore (это основные файлы Qt)
-
Ищем в них нужные функции и помещаем их в таблицу
-
Пишем своё небольшое дерево классов, которое будет вызывать внешние функции из Qt, пользуясь нашей таблицей.
-
Всё, что не удастся вызвать напрямую из QtGui и QtCore, обернём в C функции в QtE.dll, маленькой dll, призванной обойти то, что сделать напрямую не удаётся.
Итак, после нескольких экспериментов, стало понятно, что справится напрямую с конструкторами и деструкторами Qt, мне не по силам. Программы разваливались из за конфликтов памяти. Тогда, я решил, что QtE будет создавать экземпляры классов Qt и отдавать их мне в D. Единственный объект, который создается реальным конструктором C++ непосредственно в D, это QApplication. Это позволило сохранить привычный вид программы, без использования сложного обратного вызова, как мне пришлось делать в Forth.
Следующий, хитрый момент, это события. В Qt основной механизм Слоты-Сигналы. Это отлично, но там есть и обычный подход к обработке событий, а именно виртуальные функции вызываемые в ответ на событие. Вот QtE и занимается тем, что добавляет в классы Qt поля (свойства) хранящие адреса функций обратных вызовов функций D, а так же перекрывает необходимые виртуальные функции. Таким образом, и в QtE минимум C++ кода, и в D его не много, только то, что нужно.
Немного попрактиковавшись, добавить нужный класс или метод класса можно довольно быстро.
Пример:
import qte; // Работа с Qt import core.runtime; import std.stdio;
// Это наш обработчик события изменения размера окна void resize(void* qq) { writeln("!"); }
// Это наш слот, вернее обработчик события вызова слота void Кнопка1() { gWidget w10 = new gWidget(null, 0); w10.setWindowTitle(new QString("Это окно из моего слота!!!!"w)); w10.resize(500, 150); w10.show(); }
int main(string[] args) { // Цепляем библиотеки QtCore, QtGui, QtE. int rez = LoadQt(); if (rez==1) return 1; // Ошибка загрузки библиотеки
QApplication app = new QApplication; // Создали, но конструктор не вызван // Изврат связанный с тем, что вызов конструктора QApplication // должен быть произведен в main(), иначе в Linux ошибка .... (app.adrQApplication())(cast(void*)app.bufObj, &Runtime.cArgs.argc, Runtime.cArgs.argv);
// Создаём окно gWidget w1 = new gWidget(null, 0); w1.setResizeEvent(&resize); // Установить обработчик на resize w1.resize(300, 100); w1.show(); wstring ss = "Привет!"w; wstring ss2 = ss ~ " - ура!"w; QString qs2 = new QString(ss2);
gWidget w2 = new gWidget(null, 0); w2.resize(400, 50); w2.show(); w2.setWindowTitle(new QString("Ещё одно окошко!"w));
QTextEdit textEd7 = new QTextEdit(null); textEd7.append(new QString("Это textEd7 ... При изменении текста вызов сигнала textChanged() с привязкой к aboutQt()")); textEd7.setWindowTitle(qs2); textEd7.show(); QByteArray ba = new QByteArray(); w1.setWindowTitle(qs2); gPushButton копка1 = new gPushButton(null, qs2); // Пример привязки стандартного сигнала к стандартному слоту textEd7.connect(textEd7.QtObj(), MSS("textChanged()", QSIGNAL), app.QtObj(), MSS("aboutQt()", QSLOT), 1);
// мы так же можем сделать свой СОБСТВЕННЫЙ СЛОТ!!! Для этого будем использовать // объект slot замечательного класса gSlot. gSlot slot0 = new gSlot(); slot0.setSlot0(&Кнопка1); // Установить обработчик на Кнопку // Вяжем стандартный сигнал на наш слот копка1.connect(копка1.QtObj(), MSS("clicked()", QSIGNAL), slot0.QtObj(), MSS("Slot0()", QSLOT), 1); // Вяжем наш сигнал с стандартным слотом aboutQt копка1.connect(slot0.QtObj(), MSS("Signal0()", QSIGNAL), app.QtObj(), MSS("aboutQt()", QSLOT), 1); // Инициируем наш сигнал slot0.emitSignal0(); копка1.show(); return app.exec(); }
|