QtとQMLを使用してウィンドウの位置とサイズを制御する

QtとQMLを使用してウィンドウの位置とサイズを制御する

Type
QtQMLC++
Description
Created time
May 3, 2024 3:06 AM
Last edited time
May 3, 2024 8:45 AM

この記事では、QtとQMLを使用して、メインウィンドウの位置とサイズを操作する方法を紹介します。

サブウィンドウのQMLファイル

まず、メインウィンドウの表示位置とサイズを制御するためのボタンを配置したSubWindow.qmlを作成します。以下にそのコードを示します。

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15

Window {
    id: subWindow
    width: 300
    height: 200
    title: "Sub Window"
    visible: false
    x: 0
    y: screenHeight - height
    color: "black"
    flags: Qt.WindowStaysOnTopHint

    // Properties for setting the position of the main window
    property int xPosition: mainWindow.x
    property int yPosition: mainWindow.y
    property int wSize: mainWindow.width
    property int hSize: mainWindow.height

    onXPositionChanged: mainWindow.x = xPosition
    onYPositionChanged: mainWindow.y = yPosition
    onWSizeChanged: mainWindow.width = wSize
    onHSizeChanged: mainWindow.height = hSize

    Column {
        anchors.centerIn: parent

        Row {
            Layout.alignment: Qt.AlignVCenter
            Label {
                text: "x"
            }

            Button {
                text: "-"
                onClicked: xField.text = parseInt(xField.text) - 1
            }

            TextField {
                id: xField
                text: mainWindow.x
                inputMethodHints: Qt.ImhDigitsOnly
                onTextChanged: xPosition = parseInt(text)
            }

            Button {
                text: "+"
                onClicked: xField.text = parseInt(xField.text) + 1
            }
        }

        Row {
            Layout.alignment: Qt.AlignVCenter
            Label {
                text: "y"
            }
            Button {
                text: "-"
                onClicked: yField.text = parseInt(yField.text) - 1
            }

            TextField {
                id: yField
                text: mainWindow.y
                inputMethodHints: Qt.ImhDigitsOnly
                onTextChanged: yPosition = parseInt(text)
            }

            Button {
                text: "+"
                onClicked: yField.text = parseInt(yField.text) + 1
            }
        }

        Row {
            Label {
                text: "w"
            }

            Button {
                text: "-"
                onClicked: wField.text = parseInt(wField.text) - 1
            }

            TextField {
                id: wField
                text: mainWindow.width
                inputMethodHints: Qt.ImhDigitsOnly
                onTextChanged: wSize = parseInt(text)
            }

            Button {
                text: "+"
                onClicked: wField.text = parseInt(wField.text) + 1
            }
        }

        Row {
            Label {
                text: "h"
            }

            Button {
                text: "-"
                onClicked: hField.text = parseInt(hField.text) - 1
            }

            TextField {
                id: hField
                text: mainWindow.height
                inputMethodHints: Qt.ImhDigitsOnly
                onTextChanged: hSize = parseInt(text)
            }

            Button {
                text: "+"
                onClicked: hField.text = parseInt(hField.text) + 1
            }
        }

    }

}

重要なポイントは、次の部分です。

// Properties for setting the position of the main window
property int xPosition: mainWindow.x/
property int yPosition: mainWindow.y
property int wSize: mainWindow.width
property int hSize: mainWindow.height

ここではmainWindowのパラメータを取得しています。mainWindowは後ほどmain.cppでQMLに公開します。

メインウィンドウのQML

次に、Main.qmlを作成します。これがメインウィンドウのQMLとなります。

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import Qt.labs.platform 1.1
import "QML" as QMLComponents

Window {
    id: mainWindow
    x: 0
    y: 0
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint

    MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onEntered: {
            cursorShape = Qt.BlankCursor
        }
    }

    QMLComponents.SubWindow {
        id: subWindow
        x: 0
        y: screenHeight - height

        onVisibleChanged: {
            if (!visible) {
                mainWindow.flags = Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
            }
        }
    }

    Shortcut {
        sequence: (Qt.platform.os === "windows") ? "Ctrl+," : "Ctrl+,"
        onActivated: {
            subWindow.visible = true
            mainWindow.flags = Qt.FramelessWindowHint
        }
    }
}

以下が注目すべきポイントです。

 flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint

上記のコードにより、メインウィンドウはタイトルバーが非表示になり、また常に最前面に表示されるように設定されます。

 MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onEntered: {
            cursorShape = Qt.BlankCursor
        }
}

これによりメインウィンドウ上でマウスカーソルが表示されなくなります。

QMLComponents.SubWindow {
        id: subWindow
        x: 0
        y: screenHeight - height

        onVisibleChanged: {
            if (!visible) {
                mainWindow.flags = Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
            }
        }
    }
    ・・・
}

上記コードで先ほど作成したSubWindow.qmlを登録しています。また、サブウィンドウが非表示になったタイミングで、メインウィンドウをタイトルバーを非表示にし、最前面に表示するようにしています。

    Shortcut {
        sequence: (Qt.platform.os === "windows") ? "Ctrl+," : "Ctrl+,"
        onActivated: {
            subWindow.visible = true
            mainWindow.flags = Qt.FramelessWindowHint
        }
    }

最後に、ショートカットキーを設定しています。Ctrl+,を押すとサブウィンドウが表示されるように設定しています。

以上がウィンドウの位置とサイズを操作するための主な設定です。これらを活用すれば、QtとQMLを用いて柔軟なウィンドウ操作が可能になります。

メイン関数

main.cppでスクリーンサイズを取得し、それとメインウィンドウをQMLに公開する方法を紹介します。以下にそのコードを示します。

#include <QGuiApplication>#include <QQmlApplicationEngine>#include <QQmlContext>#include <QScreen>int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    // Get default screen
    QScreen *screen = QGuiApplication::primaryScreen();

    // Get screen width and height
    int screenWidth = screen->availableSize().width();
    int screenHeight = screen->availableSize().height();

    QQmlApplicationEngine engine;
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
        &app, []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);

    // Screen sizes published in QML
    engine.rootContext()->setContextProperty("screenWidth", screenWidth);
    engine.rootContext()->setContextProperty("screenHeight", screenHeight);

    engine.loadFromModule("SubWindow", "Main");

    // Make the mainWindow object available to QML
    QObject *mainWindow = engine.rootObjects().value(0);
    engine.rootContext()->setContextProperty("mainWindow", mainWindow);

    return app.exec();
}

以下にこのコードの主要な部分を紹介します。

// Screen sizes published in QML
engine.rootContext()->setContextProperty("screenWidth", screenWidth);
engine.rootContext()->setContextProperty("screenHeight", screenHeight);

ここではスクリーンのサイズをQMLに公開しています。これにより、QMLの任意の場所でスクリーンサイズにアクセスすることが可能になります。

// Make the mainWindow object available to QML
QObject *mainWindow = engine.rootObjects().value(0);
engine.rootContext()->setContextProperty("mainWindow", mainWindow);

ここではメインウィンドウオブジェクトをQML側で使用できるように公開しています。これにより、QMLから直接メインウィンドウオブジェクトにアクセスし、それを制御することが可能になります。

これらの手法を用いることで、C++のコードとQMLを効果的に連携させることができます。これにより、QtとQMLを使用したアプリケーションの開発がより柔軟かつ効率的になります。