ウィンドウの埋め込み
非 Qt UI 要素を Qt アプリケーションに埋め込む方法のデモです。
Qt は Qt Widget と Qt Quick ベースのアプリケーションの両方に幅広い UI コントロールを提供していますが、プラットフォームのネイティブ UI ツールキットなど、他の UI ツールキットのコントロールを使用することが望ましい場合もあります。
QWindow これらのコントロールを統合するために、ネイティブUIコントロールのQWindow 表現を作成し、Qt UI内に埋め込むことができます。このようにして作成されたウィンドウは、(Qtにとって)外来のUIツールキットによって作成されたコントロールを表すため、Qtでは外来ウィンドウとして知られています。
外部ウィンドウの作成
QWindow 表現を作成するには、QWindow::fromWinId() を使用し、不透明な WId 型で表現されるネイティブ・ウィンドウ・ハンドルへの参照を渡します。
各プラットフォームは、WId不透明型がどのネイティブ型にマッピングされるかを定義している。
結果は、ネイティブ・ウィンドウ・ハンドルを表すQWindow 。
QWindow注意: Qtは、外部ウィンドウを作成する際に、ネイティブウィンドウハンドルの(排他的な)所有権を取りません。
QWindow::fromWinId() を使ってQWindow を作成する前に、ネイティブ・ウィンドウ・ハンドルが必要です。この例では、月カレンダー・コントロールを埋め込みます。ほとんどのプラットフォームでは、ネイティブUIツールキットに月カレンダー・コントロールが含まれているか、すぐに利用できるからです。各プラットフォームでのカレンダーの作成方法の詳細は、以下のコード・スニペットに示されています。
アプリケーションの終了時に、ネイティブ・ハンドルが生き続け、かつ適切にクリーンアップされるように、main()
から戻る前に実行するクリーンアップ関数のリストを保持しています。
ネイティブ・ウィンドウ・ハンドルを作成し、それをQWindow に変換することに加え て、QWindow に最小サイズを設定します。これによってQtは、埋め込まれた外部ウィンドウを適切にレイアウトすることができます。
X11#x11#include <AppKit/NSDatePicker.h> #include <AppKit/NSLayoutConstraint.h> QWindow *createCalendarWindow() { auto *datePicker = [NSDatePicker new]; cleanupFunctions.push_back([=]{ [datePicker release]; }); datePicker.datePickerStyle = NSDatePickerStyleClockAndCalendar; datePicker.datePickerElements = NSDatePickerElementFlagYearMonthDay; datePicker.drawsBackground = YES; datePicker.dateValue = [NSDate now]; auto *calendarWindow = QWindow::fromWinId(WId(datePicker)); calendarWindow->setMinimumSize(QSizeF::fromCGSize(datePicker.fittingSize).toSize()); return calendarWindow; }
#include <windows.h> #include <commctrl.h> QWindow *createCalendarWindow() { static bool initializedDateControl = []{ INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(icex); icex.dwICC = ICC_DATE_CLASSES; return InitCommonControlsEx(&icex); }(); Q_ASSERT(initializedDateControl); HWND monthCalendar = CreateWindow(MONTHCAL_CLASSW, nullptr, MCS_NOTODAYCIRCLE | MCS_NOTODAY, 0, 0, 0, 0, nullptr, nullptr, GetModuleHandle(nullptr), nullptr); cleanupFunctions.push_back([=]{ DestroyWindow(monthCalendar); }); auto *calendarWindow = QWindow::fromWinId(WId(monthCalendar)); RECT minimumSize; MonthCal_GetMinReqRect(monthCalendar, &minimumSize); const auto dpr = calendarWindow->devicePixelRatio(); calendarWindow->setMinimumSize(QSize( minimumSize.right / dpr,minimumSize.bottom / dpr)); return calendarWindow; }
#include <gtk/gtk.h> #include <gtk/gtkx.h> QWindow *createCalendarWindow() { static bool initializedGTK = []{ qputenv("GDK_BACKEND", "x11"); return gtk_init_check(nullptr, nullptr); }(); Q_ASSERT(initializedGTK); auto *plug = gtk_plug_new(0); g_signal_connect(GTK_WIDGET(plug), "delete-event", G_CALLBACK(+[]{ return true; // Don't destroy on close }), nullptr); cleanupFunctions.push_back([=]{ gtk_widget_destroy(GTK_WIDGET(plug)); }); auto *calendar = gtk_calendar_new(); gtk_container_add(GTK_CONTAINER(plug), GTK_WIDGET(calendar)); gtk_widget_show_all(plug); auto *calendarWindow = QWindow::fromWinId(gtk_plug_get_id(GTK_PLUG(plug))); GtkRequisition minimumSize; gtk_widget_get_preferred_size(calendar, &minimumSize, NULL); calendarWindow->setMinimumSize(QSize(minimumSize.width, minimumSize.height)); return calendarWindow; }
#include <UIKit/UIDatePicker.h> QWindow *createCalendarWindow() { auto *datePicker = [UIDatePicker new]; cleanupFunctions.push_back([=]{ [datePicker release]; }); datePicker.datePickerMode = UIDatePickerModeDate; datePicker.preferredDatePickerStyle = UIDatePickerStyleInline; datePicker.backgroundColor = UIColor.systemBackgroundColor; auto *calendarWindow = QWindow::fromWinId(WId(datePicker)); calendarWindow->setMinimumSize(QSizeF::fromCGSize(datePicker.frame.size).toSize()); return calendarWindow; }
Q_DECLARE_JNI_CLASS(CalendarView, "android/widget/CalendarView") Q_DECLARE_JNI_CLASS(Color, "android/graphics/Color") QWindow *createCalendarWindow() { using namespace QtJniTypes; using namespace QNativeInterface; auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>(); Q_ASSERT(androidApp); auto *calendarView = new CalendarView(androidApp->context()); cleanupFunctions.push_back([=]{ delete calendarView; }); // Resolving Android default colors is not trivial, so let's ask Qt QColor paletteColor = qGuiApp->palette().color(QPalette::Window); int backgroundColor = Color::callStaticMethod<int>("rgb", paletteColor.red(), paletteColor.green(), paletteColor.blue()); calendarView->callMethod<void>("setBackgroundColor", backgroundColor); auto *calendarWindow = QWindow::fromWinId(WId(calendarView->object())); calendarWindow->setMinimumSize(QSize(200, 220)); return calendarWindow; }
外部ウィンドウの埋め込み
さて、外部QWindow 、それをQt UIに埋め込むことができます。以下のように、いくつかのオプションがあります。
Qt Guiへの埋め込み
最も低いレベルでは、QWindow::setParent() を使って、別のQWindow に再ペアレントすることで、外部ウィンドウを埋め込むことができます。この方法は、アプリケーション開発者に、埋め込まれた子ウィンドウの位置、サイズ変更、その他の管理を任せることになります。
この例では、まず最小限のコンテナウィンドウを作成します。
class ContainerWindow : public QRasterWindow { protected: bool event(QEvent *event) override { if (event->type() == QEvent::ChildWindowAdded) { auto *childWindow = static_cast<QChildWindowEvent*>(event)->child(); childWindow->resize(childWindow->minimumSize()); setMinimumSize(childWindow->size().grownBy(contentsMargins)); resize(minimumSize()); } return QRasterWindow::event(event); } void showEvent(QShowEvent *) override { findChild<QWindow*>()->setVisible(true); } void resizeEvent(QResizeEvent *) override { auto *containedWindow = findChild<QWindow*>(); containedWindow->setPosition( (width() / 2) - containedWindow->width() / 2, (height() / 2) - containedWindow->height() / 2 ); } void paintEvent(QPaintEvent *) override { QPainter painter(this); painter.fillRect(0, 0, width(), height(), "#00414A"); } };
次に、このコンテナウィンドウに外部ウィンドウをリペアレントします。
ContainerWindow window; window.setTitle("Qt Gui"); auto *calendarWindow = createCalendarWindow(); calendarWindow->setParent(&window);
Qtウィジェットへの埋め込み
Qt Widgets UIスタック上に構築されたアプリケーションでは、QWindow::fromWinId() と同じアプローチで、QWindow のQWidget 表現を、QWidget::createWindowContainer() 経由で作成します。
その後、QWidget::setParent() を使って、ウィジェットを別のウィジェットに再ペアレントできます。上記のQt Guiの例と同じ注意点があり、位置決めやサイズ変更などを手動で管理する必要があります。この例では、ウィンドウ・コンテナ・ウィジェットをQVBoxLayout に追加します。
QWidget widget; widget.setPalette(QColor("#CDB0FF")); widget.setWindowTitle("Qt Widgets"); widget.setLayout(new QVBoxLayout); widget.layout()->setContentsMargins(contentsMargins); widget.layout()->setAlignment(Qt::AlignCenter); auto *calendarWidget = QWidget::createWindowContainer(createCalendarWindow()); widget.layout()->addWidget(calendarWidget);
Qt Quickでの埋め込み
最後に、Qt Quick UI スタック上に構築されたアプリケーションでは、WindowContainer を使って外部ウィンドウを管理します。
Window { title: "Qt Quick" color: "#2CDE85" required property QtObject calendarWindow; property int contentsMargins: 20 minimumWidth: calendarWindow.minimumWidth + contentsMargins * 2 minimumHeight: calendarWindow.minimumHeight + contentsMargins * 2 WindowContainer { id: calendar window: calendarWindow width: window.minimumWidth height: window.minimumHeight anchors.centerIn: parent } }
この例では、外部ウィンドウはコンテキストプロパティとしてQMLエンジンに公開されていますが、アプリケーションのニーズに応じて、さまざまな方法で解決することができます。
QQmlApplicationEngine engine; engine.setInitialProperties({{ "calendarWindow", QVariant::fromValue(createCalendarWindow()) }}); engine.loadFromModule("windowembedding", "Main");
©2024 The Qt Company Ltd. ここに含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。