various fixes and improvements
1. Make all demo applications be able to record and restore the previous window geometry. 2. Improve the robustness of the widgets and quick implementation. Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
915e775d94
commit
8042a78b8f
|
@ -23,13 +23,10 @@
|
|||
*/
|
||||
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <framelessconfig_p.h>
|
||||
#include "mainwindow.h"
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Not necessary, but better call this function, before the construction
|
||||
|
@ -38,8 +35,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
|
||||
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtWidgets/qboxlayout.h>
|
||||
#include <Utils>
|
||||
#include <StandardTitleBar>
|
||||
|
@ -34,6 +38,18 @@ FRAMELESSHELPER_USE_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(GeoKeyPath, "Window/Geometry")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(StateKeyPath, "Window/State")
|
||||
|
||||
[[nodiscard]] static inline QSettings *appConfigFile()
|
||||
{
|
||||
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
|
||||
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
|
||||
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
|
||||
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
|
||||
return settings;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent, const Qt::WindowFlags flags) : FramelessMainWindow(parent, flags)
|
||||
{
|
||||
initialize();
|
||||
|
@ -41,6 +57,14 @@ MainWindow::MainWindow(QWidget *parent, const Qt::WindowFlags flags) : Frameless
|
|||
|
||||
MainWindow::~MainWindow() = default;
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
settings->setValue(kGeoKeyPath, saveGeometry());
|
||||
settings->setValue(kStateKeyPath, saveState());
|
||||
FramelessMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::initialize()
|
||||
{
|
||||
m_titleBar.reset(new StandardTitleBar(this));
|
||||
|
@ -60,6 +84,19 @@ void MainWindow::initialize()
|
|||
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
|
||||
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
|
||||
helper->setHitTestVisible(mb); // IMPORTANT!
|
||||
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
const QByteArray geoData = settings->value(kGeoKeyPath).toByteArray();
|
||||
const QByteArray stateData = settings->value(kStateKeyPath).toByteArray();
|
||||
if (geoData.isEmpty()) {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
} else {
|
||||
restoreGeometry(geoData);
|
||||
}
|
||||
if (!stateData.isEmpty()) {
|
||||
restoreState(stateData);
|
||||
}
|
||||
});
|
||||
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt MainWindow"));
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@ public:
|
|||
explicit MainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {});
|
||||
~MainWindow() override;
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
|
|
|
@ -52,8 +52,6 @@
|
|||
#include <QApplication>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QOpenGLContext>
|
||||
#include <framelesshelpercore_global.h>
|
||||
#include <framelessconfig_p.h>
|
||||
#include "mainwindow.h"
|
||||
|
||||
// This example demonstrates easy, cross-platform usage of OpenGL ES 3.0 functions via
|
||||
|
@ -66,8 +64,6 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Not necessary, but better call this function, before the construction
|
||||
|
@ -76,8 +72,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
|
||||
|
||||
QSurfaceFormat fmt = {};
|
||||
fmt.setDepthBufferSize(24);
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include "mainwindow.h"
|
||||
#include "glwidget.h"
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtWidgets/qboxlayout.h>
|
||||
#include <FramelessWidgetsHelper>
|
||||
#include <StandardTitleBar>
|
||||
|
@ -33,6 +37,17 @@ FRAMELESSHELPER_USE_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
|
||||
|
||||
[[nodiscard]] static inline QSettings *appConfigFile()
|
||||
{
|
||||
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
|
||||
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
|
||||
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
|
||||
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
|
||||
return settings;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : FramelessWidget(parent)
|
||||
{
|
||||
initialize();
|
||||
|
@ -40,6 +55,13 @@ MainWindow::MainWindow(QWidget *parent) : FramelessWidget(parent)
|
|||
|
||||
MainWindow::~MainWindow() = default;
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
settings->setValue(kIniKeyPath, saveGeometry());
|
||||
FramelessWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::initialize()
|
||||
{
|
||||
resize(800, 600);
|
||||
|
@ -58,4 +80,13 @@ void MainWindow::initialize()
|
|||
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
|
||||
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
|
||||
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
|
||||
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
const QByteArray data = settings->value(kIniKeyPath).toByteArray();
|
||||
if (data.isEmpty()) {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
} else {
|
||||
restoreGeometry(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS QuickControls2)
|
|||
set(SOURCES
|
||||
qml.qrc
|
||||
main.cpp
|
||||
settings.h
|
||||
settings.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
|
|
@ -26,14 +26,33 @@ import QtQuick 2.0
|
|||
import QtQuick.Window 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import org.wangwenx190.FramelessHelper 1.0
|
||||
import Demo 1.0
|
||||
|
||||
FramelessWindow {
|
||||
id: window
|
||||
visible: false // Hide the window before we sets up it's correct size and position.
|
||||
width: 800
|
||||
height: 600
|
||||
title: qsTr("FramelessHelper demo application - Qt Quick")
|
||||
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark)
|
||||
? FramelessUtils.defaultSystemDarkColor : FramelessUtils.defaultSystemLightColor
|
||||
onClosing: Settings.saveGeometry(window)
|
||||
|
||||
FramelessHelper.onReady: {
|
||||
// Let FramelessHelper know what's our homemade title bar, otherwise
|
||||
// our window won't be draggable.
|
||||
FramelessHelper.titleBarItem = titleBar;
|
||||
// Make our own items visible to the hit test and on Windows, enable
|
||||
// the snap layouts feature (available since Windows 11).
|
||||
FramelessHelper.setSystemButton(titleBar.minimizeButton, FramelessHelperConstants.Minimize);
|
||||
FramelessHelper.setSystemButton(titleBar.maximizeButton, FramelessHelperConstants.Maximize);
|
||||
FramelessHelper.setSystemButton(titleBar.closeButton, FramelessHelperConstants.Close);
|
||||
if (!Settings.restoreGeometry(window)) {
|
||||
FramelessHelper.moveWindowToDesktopCenter();
|
||||
}
|
||||
// Finally, show the window after everything is setted.
|
||||
window.visible = true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 500
|
||||
|
@ -55,19 +74,9 @@ FramelessWindow {
|
|||
StandardTitleBar {
|
||||
id: titleBar
|
||||
anchors {
|
||||
top: window.topBorderBottom
|
||||
top: window.topBorderBottom // IMPORTANT!
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
Component.onCompleted: {
|
||||
// Make our homemade title bar draggable, and open the system menu
|
||||
// when the user right clicks on the title bar area.
|
||||
FramelessHelper.titleBarItem = titleBar;
|
||||
// Make our own items visible to the hit test and on Windows, enable
|
||||
// the snap layout feature (available since Windows 11).
|
||||
FramelessHelper.setSystemButton(titleBar.minimizeButton, FramelessHelperConstants.Minimize);
|
||||
FramelessHelper.setSystemButton(titleBar.maximizeButton, FramelessHelperConstants.Maximize);
|
||||
FramelessHelper.setSystemButton(titleBar.closeButton, FramelessHelperConstants.Close);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,12 +27,10 @@
|
|||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuickControls2/qquickstyle.h>
|
||||
#include <framelessquickmodule.h>
|
||||
#include <framelessconfig_p.h>
|
||||
#include "settings.h"
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Not necessary, but better call this function, before the construction
|
||||
|
@ -41,8 +39,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
QGuiApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
|
||||
|
||||
// Allow testing other RHI backends through environment variable.
|
||||
if (!qEnvironmentVariableIsSet("QSG_RHI_BACKEND")) {
|
||||
// This line is not relevant to FramelessHelper, we change
|
||||
|
@ -63,6 +59,13 @@ int main(int argc, char *argv[])
|
|||
// Don't forget to register our own custom QML types!
|
||||
FramelessHelper::Quick::registerTypes(&engine);
|
||||
|
||||
qmlRegisterSingletonType<Settings>("Demo", 1, 0, "Settings",
|
||||
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
return new Settings;
|
||||
});
|
||||
|
||||
// This line is not relevant to FramelessHelper, we change the default
|
||||
// Qt Quick Controls theme to "Basic" (Qt6) or "Default" (Qt5) just
|
||||
// because other themes will make our homemade system buttons look
|
||||
|
@ -73,11 +76,11 @@ int main(int argc, char *argv[])
|
|||
QQuickStyle::setStyle(FRAMELESSHELPER_STRING_LITERAL("Default"));
|
||||
#endif
|
||||
|
||||
const QUrl homepageUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/qml/MainWindow.qml"));
|
||||
const QUrl mainUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/qml/MainWindow.qml"));
|
||||
const QMetaObject::Connection connection = QObject::connect(
|
||||
&engine, &QQmlApplicationEngine::objectCreated, &application,
|
||||
[&homepageUrl, &connection](QObject *object, const QUrl &url) {
|
||||
if (url != homepageUrl) {
|
||||
[&mainUrl, &connection](QObject *object, const QUrl &url) {
|
||||
if (url != mainUrl) {
|
||||
return;
|
||||
}
|
||||
if (object) {
|
||||
|
@ -87,7 +90,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
engine.load(homepageUrl);
|
||||
engine.load(mainUrl);
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qdatastream.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
|
||||
|
||||
Settings::Settings(QObject *parent) : QObject(parent)
|
||||
{
|
||||
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
|
||||
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
|
||||
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
|
||||
m_settings.reset(new QSettings(iniFilePath, QSettings::IniFormat));
|
||||
}
|
||||
|
||||
Settings::~Settings() = default;
|
||||
|
||||
void Settings::saveGeometry(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
QByteArray data = {};
|
||||
QDataStream stream(&data, QDataStream::WriteOnly);
|
||||
stream.setVersion(QDataStream::Qt_5_6);
|
||||
stream << window->geometry();
|
||||
m_settings->setValue(kIniKeyPath, data);
|
||||
}
|
||||
|
||||
bool Settings::restoreGeometry(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const QByteArray data = m_settings->value(kIniKeyPath).toByteArray();
|
||||
if (data.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
QRect geometry = {};
|
||||
QDataStream stream(data);
|
||||
stream.setVersion(QDataStream::Qt_5_6);
|
||||
stream >> geometry;
|
||||
if (!geometry.isValid()) {
|
||||
return false;
|
||||
}
|
||||
window->setGeometry(geometry);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <framelesshelpercore_global.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWindow;
|
||||
class QSettings;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Settings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(Settings)
|
||||
|
||||
public:
|
||||
explicit Settings(QObject *parent = nullptr);
|
||||
~Settings() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void saveGeometry(QWindow *window);
|
||||
Q_NODISCARD bool restoreGeometry(QWindow *window);
|
||||
|
||||
private:
|
||||
QScopedPointer<QSettings> m_settings;
|
||||
};
|
|
@ -23,13 +23,10 @@
|
|||
*/
|
||||
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <framelessconfig_p.h>
|
||||
#include "widget.h"
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Not necessary, but better call this function, before the construction
|
||||
|
@ -38,8 +35,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Option::CenterWindowBeforeShow);
|
||||
|
||||
Widget widget;
|
||||
widget.show();
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include "widget.h"
|
||||
#include <QtCore/qdatetime.h>
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtWidgets/qlabel.h>
|
||||
#include <QtWidgets/qboxlayout.h>
|
||||
#include <FramelessManager>
|
||||
|
@ -36,6 +40,17 @@ FRAMELESSHELPER_USE_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
|
||||
|
||||
[[nodiscard]] static inline QSettings *appConfigFile()
|
||||
{
|
||||
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
|
||||
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
|
||||
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
|
||||
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
|
||||
return settings;
|
||||
}
|
||||
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent)
|
||||
{
|
||||
initialize();
|
||||
|
@ -53,6 +68,13 @@ void Widget::timerEvent(QTimerEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
void Widget::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
settings->setValue(kIniKeyPath, saveGeometry());
|
||||
FramelessWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void Widget::initialize()
|
||||
{
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt Widgets"));
|
||||
|
@ -83,6 +105,15 @@ void Widget::initialize()
|
|||
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
|
||||
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
|
||||
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
|
||||
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
const QByteArray data = settings->value(kIniKeyPath).toByteArray();
|
||||
if (data.isEmpty()) {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
} else {
|
||||
restoreGeometry(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Widget::updateStyleSheet()
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
|
|
@ -71,6 +71,7 @@ protected:
|
|||
|
||||
Q_SIGNALS:
|
||||
void titleBarItemChanged();
|
||||
void ready();
|
||||
|
||||
private:
|
||||
QScopedPointer<FramelessQuickHelperPrivate> d_ptr;
|
||||
|
|
|
@ -65,6 +65,8 @@ public:
|
|||
Q_NODISCARD bool isWindowFixedSize() const;
|
||||
void setWindowFixedSize(const bool value);
|
||||
|
||||
void emitSignalForAllInstances(const char *signal);
|
||||
|
||||
private:
|
||||
Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const;
|
||||
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, QuickGlobal::SystemButtonType *button) const;
|
||||
|
|
|
@ -64,6 +64,7 @@ public Q_SLOTS:
|
|||
|
||||
Q_SIGNALS:
|
||||
void titleBarWidgetChanged();
|
||||
void ready();
|
||||
|
||||
private:
|
||||
QScopedPointer<FramelessWidgetsHelperPrivate> d_ptr;
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
Q_NODISCARD bool isWindowFixedSize() const;
|
||||
void setWindowFixedSize(const bool value);
|
||||
|
||||
void emitSignalForAllInstances(const char *signal);
|
||||
|
||||
private:
|
||||
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
|
||||
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;
|
||||
|
|
|
@ -163,7 +163,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
switch (uMsg) {
|
||||
case WM_NCHITTEST: {
|
||||
// Try to determine what part of the window is being hovered here. This
|
||||
// is absolutely critical to making sure the snap layout works!
|
||||
// is absolutely critical to making sure the snap layouts works!
|
||||
const POINT nativeGlobalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
POINT nativeLocalPos = nativeGlobalPos;
|
||||
if (ScreenToClient(hWnd, &nativeLocalPos) == FALSE) {
|
||||
|
@ -371,7 +371,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
const auto dragBarWindowHandle = reinterpret_cast<HWND>(dragBarWindowId);
|
||||
const UINT flags = (SWP_NOACTIVATE | (hide ? SWP_HIDEWINDOW : SWP_SHOWWINDOW));
|
||||
// As you can see from the code, we only use the drag bar window to activate the
|
||||
// snap layout feature introduced in Windows 11. So you may wonder, why not just
|
||||
// snap layouts feature introduced in Windows 11. So you may wonder, why not just
|
||||
// limit it to the rectangle of the three system buttons, instead of covering the
|
||||
// whole title bar area? Well, I've tried that solution already and unfortunately
|
||||
// it doesn't work. Since our current solution works well, I have no plan to dig
|
||||
|
@ -536,7 +536,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const LPARAM lParam = msg->lParam;
|
||||
switch (uMsg) {
|
||||
case WM_NCCALCSIZE: {
|
||||
const bool isFixedSize = data.params.isWindowFixedSize();
|
||||
// Windows是根据这个消息的返回值来设置窗口的客户区(窗口中真正显示的内容)
|
||||
// 和非客户区(标题栏、窗口边框、菜单栏和状态栏等Windows系统自行提供的部分
|
||||
// ,不过对于Qt来说,除了标题栏和窗口边框,非客户区基本也都是自绘的)的范
|
||||
|
@ -870,8 +869,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
(GetAsyncKeyState(VK_RBUTTON) < 0) : (GetAsyncKeyState(VK_LBUTTON) < 0));
|
||||
const bool isTitleBar = (data.params.isInsideTitleBarDraggableArea(qtScenePos) && leftButtonPressed);
|
||||
const bool isFixedSize = data.params.isWindowFixedSize();
|
||||
if( frameBorderVisible )
|
||||
{
|
||||
if (frameBorderVisible) {
|
||||
// This will handle the left, right and bottom parts of the frame
|
||||
// because we didn't change them.
|
||||
const LRESULT originalRet = DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam);
|
||||
|
@ -1066,8 +1064,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
case WM_DISPLAYCHANGE: // Sent to a window when the display resolution has changed.
|
||||
{
|
||||
const bool isFixedSize = data.params.isWindowFixedSize();
|
||||
if( !resizeDragBarWindow(windowId, data.dragBarWindowId, isFixedSize) )
|
||||
{
|
||||
if (!resizeDragBarWindow(windowId, data.dragBarWindowId, isFixedSize)) {
|
||||
qWarning() << "Failed to re-position the drag bar window.";
|
||||
}
|
||||
} break;
|
||||
|
|
|
@ -148,8 +148,7 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
|
|||
return;
|
||||
}
|
||||
data->titleBarItem = value;
|
||||
Q_Q(FramelessQuickHelper);
|
||||
Q_EMIT q->titleBarItemChanged();
|
||||
emitSignalForAllInstances("titleBarItemChanged");
|
||||
}
|
||||
|
||||
void FramelessQuickHelperPrivate::attachToWindow()
|
||||
|
@ -218,11 +217,11 @@ void FramelessQuickHelperPrivate::attachToWindow()
|
|||
// we reach here, and all the modifications from the Qt side will be lost
|
||||
// due to QPA will reset the position and size of the window during it's
|
||||
// initialization process.
|
||||
QTimer::singleShot(0, this, [this, window](){
|
||||
QTimer::singleShot(0, this, [this](){
|
||||
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
|
||||
moveWindowToDesktopCenter();
|
||||
}
|
||||
window->setVisible(true);
|
||||
emitSignalForAllInstances("ready");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -391,6 +390,27 @@ void FramelessQuickHelperPrivate::setWindowFixedSize(const bool value)
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickHelperPrivate::emitSignalForAllInstances(const char *signal)
|
||||
{
|
||||
Q_ASSERT(signal);
|
||||
if (!signal) {
|
||||
return;
|
||||
}
|
||||
Q_Q(FramelessQuickHelper);
|
||||
const QQuickWindow * const window = q->window();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const auto rootObject = (window->contentItem() ? qobject_cast<const QObject *>(window->contentItem()) : qobject_cast<const QObject *>(window));
|
||||
const auto instances = rootObject->findChildren<FramelessQuickHelper *>();
|
||||
if (instances.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&instance : qAsConst(instances)) {
|
||||
QMetaObject::invokeMethod(instance, signal);
|
||||
}
|
||||
}
|
||||
|
||||
QRect FramelessQuickHelperPrivate::mapItemGeometryToScene(const QQuickItem * const item) const
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
|
@ -616,7 +636,7 @@ FramelessQuickHelper *FramelessQuickHelper::get(QObject *object)
|
|||
QObject *parent = nullptr;
|
||||
if (isItem(object)) {
|
||||
const auto item = qobject_cast<QQuickItem *>(object);
|
||||
parent = (item->window() ? item->window()->contentItem() : item);
|
||||
parent = ((item->window() && item->window()->contentItem()) ? item->window()->contentItem() : item);
|
||||
} else {
|
||||
parent = object;
|
||||
}
|
||||
|
@ -625,9 +645,8 @@ FramelessQuickHelper *FramelessQuickHelper::get(QObject *object)
|
|||
instance = new FramelessQuickHelper;
|
||||
if (isItem(parent)) {
|
||||
instance->setParentItem(qobject_cast<QQuickItem *>(parent));
|
||||
} else {
|
||||
instance->setParent(parent);
|
||||
}
|
||||
instance->setParent(parent);
|
||||
// No need to do this here, we'll do it once the item has been assigned to a specific window.
|
||||
//instance->d_func()->attachToWindow();
|
||||
}
|
||||
|
@ -734,8 +753,16 @@ void FramelessQuickHelper::itemChange(const ItemChange change, const ItemChangeD
|
|||
{
|
||||
QQuickItem::itemChange(change, value);
|
||||
if ((change == ItemSceneChange) && value.window) {
|
||||
if (parentItem() != value.window->contentItem()) {
|
||||
setParentItem(value.window->contentItem());
|
||||
QQuickItem * const rootItem = value.window->contentItem();
|
||||
if (rootItem) {
|
||||
if ((parentItem() != rootItem) || (parent() != rootItem)) {
|
||||
setParentItem(rootItem);
|
||||
setParent(rootItem);
|
||||
}
|
||||
} else {
|
||||
if (parent() != value.window) {
|
||||
setParent(value.window);
|
||||
}
|
||||
}
|
||||
Q_D(FramelessQuickHelper);
|
||||
d->attachToWindow();
|
||||
|
|
|
@ -128,6 +128,25 @@ void FramelessWidgetsHelperPrivate::setWindowFixedSize(const bool value)
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelperPrivate::emitSignalForAllInstances(const char *signal)
|
||||
{
|
||||
Q_ASSERT(signal);
|
||||
if (!signal) {
|
||||
return;
|
||||
}
|
||||
const QWidget * const window = getWindow();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const auto instances = window->findChildren<FramelessWidgetsHelper *>();
|
||||
if (instances.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&instance : qAsConst(instances)) {
|
||||
QMetaObject::invokeMethod(instance, signal);
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
|
||||
{
|
||||
Q_ASSERT(widget);
|
||||
|
@ -143,8 +162,7 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
|
|||
return;
|
||||
}
|
||||
data->titleBarWidget = widget;
|
||||
Q_Q(FramelessWidgetsHelper);
|
||||
Q_EMIT q->titleBarWidgetChanged();
|
||||
emitSignalForAllInstances("titleBarWidgetChanged");
|
||||
}
|
||||
|
||||
QWidget *FramelessWidgetsHelperPrivate::getTitleBarWidget() const
|
||||
|
@ -245,11 +263,11 @@ void FramelessWidgetsHelperPrivate::attachToWindow()
|
|||
// we reach here, and all the modifications from the Qt side will be lost
|
||||
// due to QPA will reset the position and size of the window during it's
|
||||
// initialization process.
|
||||
QTimer::singleShot(0, this, [this, window](){
|
||||
QTimer::singleShot(0, this, [this](){
|
||||
if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) {
|
||||
moveWindowToDesktopCenter();
|
||||
}
|
||||
window->setVisible(true);
|
||||
emitSignalForAllInstances("ready");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue