![]() |
Главная · Все классы · Основные классы · Классы по группам · Модули · Функции | ![]() |
Пример "Dot Net" демонстрирует, как объекты Qt могут быть использованы в окружении .NET, и как объекты .NET можно использовать в окружении Qt.
Если вам нужно сочетать виджеты Qt и Win Forms в одном приложении, вы можете захотеть использовать взамен высокоуровневое Решение QtWinForms.
Содержание:
Qt - библиотека C++ и она скомпилирована в традиционно, "родные" двоичные файлы, которые дают полное использование производительности, предоставляемой окружением времени выполнения.
Одной из ключевых концепций .NET является идея "кода на промежуточном языке" (intermediate language code) - исходный код компилируется в формат байт-кода, а во время выполнения этот байт-код выполняется в виртуальной машине - Common Language Runtime (CLR).
Другая ключевая концепция - это управляемый код (managed code). Этот код на промежуточном языке по существу написан таким образом, что CLR будет заботиться об управлении памятью, т.е. CLR автоматически производит сборку мусора, поэтому коду приложения не нужно явно освобождать память от неиспользуемых объектов.
Компиляторы MS для C# и VB.NET производят только управляемый код. Такие программы не могут непосредственно вызывать нормальные, "родные" функции или классы.
С другой стороны, компилятор MS C++ для .NET может производить как нормальный, так и управляемый код. Чтобы написать класс C++, который можно компилировать в управляемый код, разработчик должен отметить класс как управляемый используя ключевое слов __gc, и ограничить использование кодом только подмножество C++, известное как "Управляемые расширения C++" (Managed Extensions for C++), или для краткости MC++. Преимуществом MC++ является то, что код может свободно вызывать и использовать обычные функции и классы C++. А также работаю другие способы обхода: нормальный код C++ вызывает управляемые функции и использует управляемые классы (например, вся библиотека классов каркаса .NET), включая управляемые функции и классы, реализованные на C# или VB.NET. Эта возможность смешивать управляемый и нормальный код C++ весьма облегчает функциональную совместимость с .NET, и является тем, что Microsoft упоминает как возможность "Оно просто работает" (It Just Works, IJW).
Этот документ демонстрирует два разных способа интеграции нормального кода C++ (который использует Qt) с управляемым кодом .NET. Во-первых, имеется ручной способ, который включает в себя использование тонкого класса-обёртки MC++ вокруг нормального Qt/C++ класса. Затем, имеется автоматический способ, который использует каркас ActiveQt как общий (generic) мост. Преимущество первого метода в том, что он даёт разработчику приложения полный контроль, в то время как второй метод требует меньше кодировать и помогает разработчику заниматься перекодированием между управляемыми и нормальными объектами данных.
Нетерпеливый читатель, который немедленно хочет увидеть QPushButton и пользовательский виджет Qt (QAxWidget2) запустит в .NET приложение с ГПИ обратившись к каталогу примеров ActiveQt. Он содержит результат этого критического анализа используя и C# и VB.NET, созданный с помощью Visual Studio .NET (не 2003). Загружите examples/dotnet/walkthrough/csharp.csproj, examples/dotnet/walkthrough/vb.vbproj или examples/dotnet/wrapper/wrapper.sln в ИСР и запустите решение (solution).
Замечание: Вас уведомят о том, что в сгенерированном коде следующая строка закомментирована:
' VB регистронезависимый, а наши элементы управления C++ - нет. ' Me.resetButton.enabled = True
Эта строка возобновляется без комментария когда вы изменяете диалог, в этом случае вам нужно снова закомментировать её чтобы получить возможность запустить проект. Это ошибка оригинальной версии Visual Studio.NET, она была исправлена в редакции 2003.
Обычные классы и функции C++ могут быть использованы из управляемого кода .NET путем предоставления тонких классов-обёрток, написанных на MC++. Класс-обёртка будет заботиться о пересылке вызовов обычным функциям или методам C++ и конвертированию, в случае необходимости, данных параметров. Поскольку класс-обёртка - управляемый класс, он может быть использован без добавочных хлопот в любом управляемом приложении .NET, написанном на C#, VB.NET, MC++ или на другом управляемом языке программирования.
Класс Qt не содержит ничего необычного для пользователей Qt, и даже такие тонкости Qt как Q_PROPERTY, слоты и сигналы реализованные на чистом C++, они не послужат причиной каких-либо проблем когда этот класс компилируется любым компилятором C++.
Класс-обёртка .NET использует ключевые слова, являющиеся частью MC++, чтобы обозначить что класс является управляемым/сборщиком мусора (__gc), и что StatusString будет доступен как свойство в языках, которые поддерживают эту концепцию (__property). Мы также объявляем функцию события statusStringChanged(String*) (__event), эквивалент соответствующего сигнала в классе Qt.
Перед тем, как мы сможем начать реализацию класса-обёртки нам нужен способ конвертации типов данных Qt (и, потенциально, ваши) в типы данных .NET, например, объекты QString нужно конвертировать в объекты типа String*.
При оперировании с управляемыми объектами в обычном коде C++, нужно соблюдать небольшую дополнительную осторожность из-за сборки мусора CLR. Нормальная переменная указателя не будет
использоваться для ссылки на управляемый объект. Основанием является то, что сборка мусора может активироваться в любой момент и переместить объект в другое место на куче, оставив с недействительным указателем.Тем не менее, представляются два метода, легко решающих эту проблему. Первый - используйте pinned указатель, т.е. объявите переменную указателя с ключевым словом __pin. Это гарантирует, что объект на который ссылаются, не будет перемещен сборщиком мусора. Не рекомендуется использовать этот метод для сохранения ссылок на управляемые объекты в течение длительного времени, поскольку он уменьшает эффективность сборщика мусора. Второй метод - использовать шаблонный тип интеллектуального указателя gcroot. Это позволит вам создавать безопасные указатели на управляемые объекты. Например, переменная типа gcroot<String> будет всегда указывать на объект типа String, даже если она будет перемещена сборщиком мусора, и её можно использовать так же как и обычный указатель.
Затем могут быть использованы функции конвертора реализации класса-обёртки для вызова функций в обычном классе C++.
Конструктор и деструктор просто создают и разрушают объект Qt, обёрнутый с использованием операторов C++ new и delete.
Класс netWorker делегирует вызовы из кода .NET в "родной" код. Несмотря на то, что переход между этими двумя мирами подразумевает незначительное снижение производительности для каждого вызова функции и для преобразования типов, оно будет незначительным поскольку мы в любом случае собираемся запускать внутри CLR.
Функция-сеттер свойства вызывает "родно" класс Qt перед активизацией события используя ключевое слово __raise.
Этот класс-обёртка может быть теперь использован в коде .NET, например, используя C++, C#, Visual Basic или любой другой доступный для .NET язык программирования.
К счастью, .NET предоставялет обобщенную обёртку для COM-объектов, Runtime Callable Wrapper (RCW). Эта RCW является прокси для COM-объекта и генерируется CLR когда клиент .NET Framework активирует COM-объект. Это предоставляет общий способ повторного использования COM-объектов в проекте .NET Framework.
Превратив класс QObject в COM-объект легко достигается с помощью ActiveQt и продемонстрировано в примерах QAxServer (например, в примере "Simple"). Критический анализ будет использовать классы Qt, реализованные в этих примерах, поэтому первой вещью которую нужно сделать - убедиться, что эти примеры были правильно собраны, например, открыв demonstration pages в Internet Explorer для проверки того, что элементы управления работают.
Запустим Visual Studio.NET и создадим новый проект C# для написания приложения Windows. Это представит вам пустую форму в редакторе диалога Visual Studio. Вы увидите панель инструментов, которая представит вам некоторое количество доступных элементов управления и объектов различных категорий. Если вы щелкните правой кнопкой мыши на панели инструментов, это позволит вам добавить новые вкладки. Мы добавим вкладку "Qt".
Категория по умолчанию имеет только инструмент указателя, а мы добавим объекты Qt, которые хотим использовать на нашей форме. Щелкаем правой кнопкой мыши на пустом пространстве и выбираем "Customize". Открывается диалог, в котором есть две вкладки, "COM Components" и ".NET Framework Components". Мы используем ActiveQt для обёртывания объектов QWidget в COM-объекты, поэтому мы выбираем страницу "COM Components", и ищем классы, которые собираемся использовать, например, "QPushButton" и "QAxWidget2".
Когда мы выбрали эти виджеты и закрыли диалог, два виджета будут доступны из панели инструментов в виде серых квадратиков с их именами рядом
.Мы можем теперь добавить экземпляры классов QAxWidget2 и QPushButton на форму. Visual Studio автоматически сгенерирует RCW для серверов объектов. Экземпляр класса QAxWidget2 займёт большую часть вверху формы с QPushButton в нижнем правом углу.
В редакторе свойств Visual Studio мы можем изменить свойства наших элементов управления - QPushButton открывает API QWidget и обладает многими свойствами, в то время как QAxWidget2 имеет только стандартные свойства Visual Studio в дополнение к своему собственному свойству "lineWidth" в категории "Miscellaneous". Объекты получили имена "axQPushButton1" и "axQAxWidget21", и поскольку особенно последнее имя немного смущает, мы переименуем объекты в "resetButton" и "circleWidget".
Мы также можем изменить совйства Qt, например, установить свойство "text" кнопки resetButton в значение "Reset", а свойство "lineWidth" circleWidget - равным 5. Мы также можем поместить эти объекты в систему компоновки, которую предоставляет редактор диалога Visual Studio, например, установив якори circleWidget равными "Left, Top, Right, Bottom", а якори resetButton равными "Bottom, Right".
Теперь мы можем скомпилировать и запустить проект, который будет открывать пользовательский интерфейс с двумя нашими виджетами Qt. Если мы изменим размер диалога, то виджеты соответственно изменят свои размеры.
Теперь мы будем реализовывать обработчики событий для виджетов. Выберем circleWidget и выберем страницу "Events" в редакторе свойств. Виджет делает видимыми события потому что класс QAxWidget2 в своём определении класса имеет установленный атрибут "StockEvents". Мы реализуем обработчик события circleClicked для ClickEvent чтобы увеличить толщину линии на единицу каждый щелчок мыши:
Вообще мы может реализовать обработчик событий по умолчанию дважды щелкнув по виджету в форме, но события по умолчанию для наших виджетов в данный момент не определены.
Мы также реализуем обработчик событий для сигнала clicked, испускаемого кнопкой QPushButton. Добавим обработчик событий resetLineWidth для событию clicked и реализуем порождённую функцию:
Мы сбросим свойство в значение 1, а также вызовем слот setFocus() чтобы симулировать пользовательский стиль в Windows, где кнопка захватывает фокус когда вы щелкаете по ней (так что вы можете щелкнуть по ней снова пробелом).
Если мы теперь скомпилируем и запустим проект, то мы можем щелкать на виджете окружности для увеличения толщины её линии, а также нажимать кнопку сброса для установки толщины линии снова равной 1.
Использовать ActiveQt в качестве универсального моста взаимодействия между миром .NET и миром Qt очень легко, и часто это делает лишним реализацию множества вручную написанных классов-обёрток. Instead, the QAxFactory implementation in the otherwise completely cross-platform Qt project provides the glue that .NET needs to to generate the RCW.
Если этого недостаточно, мы можем реализовать наши собственные классы-обёртки - спасибо расширениям C++, предоставляемым Microsoft.
Все ограничения при использовании ActiveQt предполагают, когда используют этот приём для взаимодействия с .NET, например, типы данных мы можем использовать в API могут быть только теми, что поддерживаются ActiveQt и COM. Однако, поскольку это включает подклассы QObject и QWidget мы можем обернуть любой из наших типов данных в подкласс QObject чтобы сделать его API доступным для .NET. Это имеет положительный побочный эффект, что тот же API автоматически доступен в QSA, кроссплатформенное решение сценариев для приложений Qt и для клиентов COM в общем.
При использовании метода "IJW", в принципе ограничением являются только время, требуемое для написания классов-обёрток и функций преобразования типа данных.
Каждый вызов из байт-кода CLR в "родной" код предполагает небольшое снижение производительности и необходимый преобразования типа вносит дополнительную задержку в каждом слое, существующем между двумя библиотеками. Следовательно каждый подход по смешиванию кода .NET и "родного" кода будет пытаться минимизировать необходимую связь между разными мирами.
Так как ActiveQt сразу помещает три слоя - RCW, COM и наконец сам ActiveQt - потеря производительности при использовании общего моста Qt/ActiveQt/COM/RCW/.NET больше, чем при использовании вручную созданного класса-обёртки IJW. Скорость выполнения, однако, остаётся достаточной для присоединения и модификации интерактивных элементов пользовательского интерфейса, и, как только появляется выгода от использования Qt и C++ для реализации и компиляции производительности критических алгоритмов в "родном" коде, ActiveQt становится эффективным выбором чтобы сделать даже невизуальные части вашего приложения доступными для .NET.
Смотрите также Решение QtWinForms.
Copyright © 2008 Trolltech | Торговые марки | Qt 4.3.5 |