如何在 QML 中创建一个没有标题栏但带有关闭/最小化/最大化按钮的窗口?

问题描述 投票:0回答:3

我想创建一个没有标题栏的应用程序,但具有本机关闭、最小化和最大化按钮。这就是布局的意图:

how it would look like on mac

该应用程序是使用 Go 和 QML 构建的。我可以通过添加删除标题栏:

flags: Qt.FramelessWindowHint | Qt.Window

但这意味着我必须重新创建各种本机行为,例如窗口移动和调整大小。我还手动重新创建关闭/最小化/全屏按钮,但这意味着我失去了各种本机操作系统行为,例如 Windows 中的窗口捕捉或 Mac 上的缩放选项。

有更好的方法吗?是否至少可以创建本机最大-最小-关闭按钮而不是从头开始构建它?

谢谢大家

user-interface go qml qt-quick qtquick2
3个回答
5
投票

您可以使用 Objective-C 来正确设置您的窗口。这可能有点问题,但我通过这个解决了它(创建一个单独的 .mm 类):

#include "macwindow.h"
#include <Cocoa.h>

MacWindow::MacWindow(long winid)
{
   NSView *nativeView = reinterpret_cast<NSView *>(winid);
   NSWindow* nativeWindow = [nativeView window];

   [nativeWindow setStyleMask:[nativeWindow styleMask] | NSFullSizeContentViewWindowMask | NSWindowTitleHidden];
   [nativeWindow setTitlebarAppearsTransparent:YES];

   [nativeWindow setMovableByWindowBackground:YES];
}

在你的 main.cpp 中,你需要像这样传递窗口 id:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QWindow>
#include "macwindow.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    QWindowList windows = QGuiApplication::allWindows();
    QWindow* win = windows.first();

    MacWindow* mac = new MacWindow(win->winId());

    return app.exec();
}   

在您的 .pro 文件中,您需要添加 Cocoa 引用:

macx:LIBS += -framework Foundation -framework Cocoa
macx:INCLUDEPATH += /System/Library/Frameworks/Foundation.framework/Versions/C/Headers \
/System/Library/Frameworks/AppKit.framework/Headers \
/System/Library/Frameworks/Cocoa.framework/Headers

不知道为什么,但我必须添加一个带有焦点属性的 TextEdit 才能正确绘制窗口,否则它看起来只是黑色(我的 main.qml):

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4

ApplicationWindow {
    visible: true
    color: "white"
    width: 600
    height: 400
    minimumWidth: width
    minimumHeight: height
    maximumWidth: width
    maximumHeight: height

    Rectangle {
        anchors.fill: parent
        color: "white"

        TextEdit {
            opacity: 0
            focus: true
        }
    }
}


0
投票

我的解决方案(基于 Eduard 的解决方案,进行调整,使窗口可拖动)。

(完整源代码https://github.com/teimuraz/qt-macos-without-title

创建macos.h和macos.mm文件(如果使用qt Creator创建,则将macos.cpp重命名为macos.mm)

macos.h

#ifndef MACOS_H
#define MACOS_H

#include <QGuiApplication>
#include <QWindow>

class MacOS {
    MacOS(long winid);
public:
    static void removeTitlebarFromWindow(long winId = -1);
};

#endif // MACOS_H

macos.mm

#include "macos.h"
#include <Cocoa/Cocoa.h>

#include <QGuiApplication>
#include <QWindow>

void MacOS::removeTitlebarFromWindow(long winId)
{
    if(winId == -1) {
        QWindowList windows = QGuiApplication::allWindows();
        QWindow* win = windows.first();
        winId = win->winId();
    }

    NSView *nativeView = reinterpret_cast<NSView *>(winId);
    NSWindow* nativeWindow = [nativeView window];

    [nativeWindow setStyleMask:[nativeWindow styleMask] | NSFullSizeContentViewWindowMask | NSWindowTitleHidden];
    [nativeWindow setTitlebarAppearsTransparent:YES];
    [nativeWindow setMovableByWindowBackground:YES];
}

main.qml

import QtQuick

import QtQuick.Controls

ApplicationWindow {
    id: mainWindow
    visible: true
    width: 640
    height: 480

   // Make windows draggable, currently whole windows area is draggable, but can be adjusted to make draggable only top area
   property int previousX
   property int previousY

    MouseArea {
        anchors {
            top: parent.top
            bottom: parent.bottom
            left: parent.left
            right: parent.right
        }

        onPressed: {
            previousX = mouseX
            previousY = mouseY
        }

        onMouseXChanged: {
            var dx = mouseX - previousX
            mainWindow.setX(mainWindow.x + dx)
        }

        onMouseYChanged: {
            var dy = mouseY - previousY
            mainWindow.setY(mainWindow.y + dy)
        }
    }
}

main.cpp

只需添加

MacWindow::removeTitlebarFromWindow();

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "macos.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/qt-macos-without-title/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    MacOS::removeTitlebarFromWindow();

    return app.exec();
}

最后在 .pro 文件中包含 cocoa lib

yourapp.pro

...
macx:LIBS += -framework Foundation -framework Cocoa
macx:INCLUDEPATH += /System/Library/Frameworks/Foundation.framework/Versions/C/Headers \
/System/Library/Frameworks/AppKit.framework/Headers \
/System/Library/Frameworks/Cocoa.framework/Headers

0
投票

我用你的方法成功去掉了系统标题栏,但是遇到了一个问题,当向窗口添加QTabBar控件时,原生系统标题栏又会出现,我该如何解决?

© www.soinside.com 2019 - 2024. All rights reserved.