英文:
How to create a window without a title bar but with the close/minimize/maximizie buttons in QML?
问题
我想创建一个没有标题栏,但带有本地关闭、最小化和最大化按钮的应用程序。这是布局的意图:
该应用程序使用Go和QML构建。我能够通过添加以下代码来移除标题栏:
flags: Qt.FramelessWindowHint | Qt.Window
但这意味着我需要重新创建各种本地行为,比如窗口移动和调整大小。我还要手动重新创建关闭/最小化/全屏按钮,但这意味着我失去了窗口在Windows上的吸附功能或Mac上的缩放选项等各种本地操作系统行为。
有没有更好的方法来实现这一点?是否至少可以创建本地的最大化、最小化和关闭按钮,而不是从头开始构建?
谢谢
英文:
I want to create an application without the title bar, but with native close, minimize and maximize buttons. This is the intent of the layout:
The app is built using Go and QML. I was able to remove the title bars by adding:
flags: Qt.FramelessWindowHint | Qt.Window
But this means that I'm having to recreate all kinds of native behaviors, like window moving and resizing. I'm also recreating the close/minimize/fullscreen buttons by hand, but it means I lose all kinds of native OS behaviour like the window snapping in windows or the zoom option on mac.
Is there a better way to do this? Is it possible at least to create the native max-min-close buttons instead of building it by scratch?
Thanks for all
答案1
得分: 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
}
}
}
英文:
You can use objective-c to setup your window correctly. This might be a little buggy, but I got it working through this (create a separate .mm class):
#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];
}
In your main.cpp you need to pass the window id like this:
#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();
}
In your .pro file you'll need to add the Cocoa reference:
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
Not sure why, but I had to add a TextEdit with the focus attribute to get the window drawn correctly, otherwise it appeared just black (my 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
}
}
}
答案2
得分: 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
// 让窗口可拖动,当前整个窗口区域都可拖动,但可以调整为只能拖动顶部区域
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(QStringLiteral("qrc:/qt-macos-without-title/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, (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
英文:
My solution (based on Eduard's one, adjusted so window is draggable).
(Complete source code https://github.com/teimuraz/qt-macos-without-title)
Create macos.h and macos.mm files (If you create it with qt creator rename macos.cpp to 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
Just add 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, (QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
MacOS::removeTitlebarFromWindow();
return app.exec();
}
And finally include cocoa lib in .pro file
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论