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

7
我希望创建一个没有标题栏但带有本地关闭、最小化和最大化按钮的应用程序。这是布局的意图: how it would look like on mac 该应用程序使用Go和QML构建。我通过添加以下内容成功地删除了标题栏:
flags: Qt.FramelessWindowHint | Qt.Window

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

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

感谢您的所有帮助。


1
本地样式可在Mac OS上使用。我认为你的问题有点类似于这个问题:提供的答案应该适用于你的问题。 - BaCaRoZzo
我不确定它是否适用。默认样式具有应用程序标题栏和彩色按钮。我想要没有(或带有自定义)标题栏的彩色按钮。 - Alexandre Van de Sande
嗯...它不适用。默认主题被认为是“原样”使用的。应用定制会删除默认主题。这样做是为了最小化不一致性。 - BaCaRoZzo
3
虽然这并没有什么帮助,但是你提出的设计方案将违反适用于 Windows 的 Apple 人机界面指南。你应该有很好的理由(可能需要一定的设计和可用性工程学位 :))来这样做。这是值得考虑的事情。 - Tod
2个回答

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
        }
    }
}

enter image description here


如果您在帖子中添加了“macwindow.h”,那就太好了。 - ervinbosenbacher
1
我电脑上没有这个示例了,但是头文件只是创建类时默认的头文件(确保在类创建向导中将cpp更改为mm)。只有构造函数,没有其他方法。构造函数必须带一个长参数。没有特殊的头文件包含等,这些都在mm文件中处理。顺便说一下,如果您在主函数开头使用: QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software); 会发现一些错误得到了修复。这将在Qt 5.8及以上版本中设置为软件渲染。 - Eduard

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 库

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接