NEW: QMainWindow example (#50)

* WIP: qmainwindow example

* NEW: option to disable acrylic on QMainWindow

* IMP: accept standard QMainWindow parameters

* NEW: enable acrylic in QMainWindow example

* IMP: qmainwindow sets acrylic outside constructor

* IMP: center windowTitle

* cleanup

* IMP: move setContentMargin in QtAcrylicMainWIndow class

* more cleanup

* small cleanup

* improvement copied from qtacrylicwidget

* minor improvement

* always connect needRepaint

* close button thickness is now similar to native windows buttons

* add context menu on left icon

* simpler context menu implementation

* IMP: use displaySystemMenu from Utilities

Co-authored-by: Julien Maille <julien.maille@data-pixel.com>
This commit is contained in:
Julien 2021-03-26 09:53:32 +01:00 committed by GitHub
parent d4a5239d26
commit 0759f7f010
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1026 additions and 5 deletions

1
.gitignore vendored
View File

@ -69,3 +69,4 @@ Thumbs.db
*.bin
*.run
.qmake.conf
*.res

View File

@ -1,4 +1,4 @@
TEMPLATE = subdirs
CONFIG -= ordered
qtHaveModule(widgets): SUBDIRS += widget
qtHaveModule(widgets): SUBDIRS += widget qmainwindow
qtHaveModule(quick): SUBDIRS += quick

View File

@ -1,5 +1,5 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#000" stroke-width=".35278">
<g fill="none" stroke="#000" stroke-width=".17639">
<path d="m6.1295 3.6601 3.2632 3.2632z"/>
<path d="m9.3927 3.6601-3.2632 3.2632z"/>
</g>

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

@ -1,5 +1,5 @@
<svg width="45pt" height="30pt" version="1.1" viewBox="0 0 15.875 10.583" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#fff" stroke-width=".35278">
<g fill="none" stroke="#fff" stroke-width=".17639">
<path d="m6.1295 3.6601 3.2632 3.2632z"/>
<path d="m9.3927 3.6601-3.2632 3.2632z"/>
</g>

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>518</width>
<height>362</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>../windows.ico</normaloff>../windows.ico</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableWidget">
<row>
<property name="text">
<string>Nouvelle ligne</string>
</property>
</row>
<row>
<property name="text">
<string>Nouvelle ligne</string>
</property>
</row>
<row>
<property name="text">
<string>Nouvelle ligne</string>
</property>
</row>
<row>
<property name="text">
<string>Nouvelle ligne</string>
</property>
</row>
<row>
<property name="text">
<string>Nouvelle ligne</string>
</property>
</row>
<row>
<property name="text">
<string>Nouvelle ligne</string>
</property>
</row>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
<column>
<property name="text">
<string>Nouvelle colonne</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>518</width>
<height>25</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<widget class="QMenu" name="menuItem_1">
<property name="title">
<string>Menu 1</string>
</property>
<addaction name="actionItem_1"/>
<addaction name="actionItem_2"/>
</widget>
<widget class="QMenu" name="menuItem_2">
<property name="title">
<string>Menu 2</string>
</property>
</widget>
<widget class="QMenu" name="menuMenu_3">
<property name="title">
<string>Menu 3</string>
</property>
</widget>
<addaction name="menuItem_1"/>
<addaction name="menuItem_2"/>
<addaction name="menuMenu_3"/>
</widget>
<widget class="QDockWidget" name="dockWidget">
<property name="windowTitle">
<string>Dock 1</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_2">
<property name="windowTitle">
<string>Dock 2</string>
</property>
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidget"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>89</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionAction_1"/>
<addaction name="actionAction_2"/>
</widget>
<widget class="QToolBar" name="toolBar_2">
<property name="windowTitle">
<string>toolBar_2</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QToolBar" name="toolBar_3">
<property name="windowTitle">
<string>toolBar_3</string>
</property>
<attribute name="toolBarArea">
<enum>BottomToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionItem_1"/>
<addaction name="actionAction_2"/>
</widget>
<action name="actionAction_1">
<property name="text">
<string>Action 1</string>
</property>
</action>
<action name="actionAction_2">
<property name="text">
<string>Action 2</string>
</property>
</action>
<action name="actionItem_1">
<property name="text">
<string>Item 1</string>
</property>
</action>
<action name="actionItem_2">
<property name="text">
<string>Item 2</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,288 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TitleBar</class>
<widget class="QWidget" name="TitleBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>552</width>
<height>31</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>31</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>31</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QMenuBar {
background-color: transparent;
height: 23px;
}
#iconButton, #minimizeButton, #maximizeButton, #closeButton {
border-style: none;
background-color: transparent;
}
#minimizeButton:hover, #maximizeButton:hover {
background-color: #80c7c7c7;
}
#minimizeButton:pressed, #maximizeButton:pressed {
background-color: #80808080;
}
#closeButton:hover {
background-color: #e81123;
icon: url(:/images/button_close_white.svg);
}
#closeButton:pressed {
background-color: #8c0a15;
}</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="iconButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="titleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Segoe UI</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="text">
<string>WIndow Title</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="minimizeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="toolTip">
<string>Minimize</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/button_minimize_black.svg</normaloff>:/images/button_minimize_black.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="maximizeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="toolTip">
<string>Maximize</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/button_maximize_black.svg</normaloff>
<normalon>:/images/button_restore_black.svg</normalon>:/images/button_maximize_black.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="toolTip">
<string>Close</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/button_close_black.svg</normaloff>:/images/button_close_black.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>45</width>
<height>30</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,136 @@
/*
* MIT License
*
* Copyright (C) 2021 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 "../../framelesswindowsmanager.h"
#include "../../qtacrylicmainwindow.h"
#include "ui_MainWindow.h"
#include "ui_TitleBar.h"
#include <QApplication>
#include <QStyleOption>
#include <QWidget>
#include <QWindow>
#ifdef WIN32
#include <Windows.h>
#endif
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
// High DPI scaling is enabled by default from Qt 6
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
// Windows: we are using the manifest file to get maximum compatibility
// because some APIs are not supprted on old systems such as Windows 7
// and Windows 8. And once we have set the DPI awareness level in the
// manifest file, any attemptation to try to change it through API will
// fail. In other words, Qt won't be able to enable or disable high DPI
// scaling or change the DPI awareness level once we have set it in the
// manifest file. So the following two lines are uesless actually (However,
// they are still useful on other platforms).
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
// Don't round the scale factor.
// This will break QWidget applications because they can't render correctly.
// Qt Quick applications won't have this issue.
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
#endif
QApplication application(argc, argv);
QtAcrylicMainWindow *mainWindow = new QtAcrylicMainWindow(NULL, Qt::WindowFlags());
mainWindow->setAcrylicEnabled(true);
Ui::MainWindow appMainWindow;
appMainWindow.setupUi(mainWindow);
QWidget *widget = new QWidget;
Ui::TitleBar titleBarWidget;
titleBarWidget.setupUi(widget);
QMenuBar *menuBar = mainWindow->menuBar();
titleBarWidget.horizontalLayout->insertWidget(1, menuBar);
mainWindow->setMenuWidget(widget);
QObject::connect(mainWindow,
&QMainWindow::windowIconChanged,
titleBarWidget.iconButton,
&QPushButton::setIcon);
QObject::connect(mainWindow,
&QMainWindow::windowTitleChanged,
titleBarWidget.titleLabel,
&QLabel::setText);
QObject::connect(titleBarWidget.closeButton,
&QPushButton::clicked,
mainWindow,
&QMainWindow::close);
QObject::connect(titleBarWidget.minimizeButton,
&QPushButton::clicked,
mainWindow,
&QMainWindow::showMinimized);
QObject::connect(titleBarWidget.maximizeButton,
&QPushButton::clicked,
[mainWindow, titleBarWidget]() {
if (mainWindow->isMaximized()) {
mainWindow->showNormal();
} else {
mainWindow->showMaximized();
}
});
QStyleOption option;
option.initFrom(mainWindow);
const QIcon icon = mainWindow->style()->standardIcon(QStyle::SP_ComputerIcon, &option);
mainWindow->setWindowIcon(icon);
mainWindow->setWindowTitle(QObject::tr("Hello, World!"));
mainWindow->createWinId(); // Qt's internal function, make sure it's a top level window.
const QWindow *win = mainWindow->windowHandle();
QObject::connect(mainWindow,
&QtAcrylicMainWindow::windowStateChanged,
[mainWindow, titleBarWidget]() {
titleBarWidget.maximizeButton->setChecked(mainWindow->isMaximized());
titleBarWidget.maximizeButton->setToolTip(mainWindow->isMaximized() ? QObject::tr("Restore") : QObject::tr("Maximize"));
});
QObject::connect(titleBarWidget.iconButton,
&QPushButton::clicked,
mainWindow,
&QtAcrylicMainWindow::displaySystemMenu);
FramelessWindowsManager::addIgnoreObject(win, titleBarWidget.iconButton);
FramelessWindowsManager::addIgnoreObject(win, titleBarWidget.minimizeButton);
FramelessWindowsManager::addIgnoreObject(win, titleBarWidget.maximizeButton);
FramelessWindowsManager::addIgnoreObject(win, titleBarWidget.closeButton);
FramelessWindowsManager::addIgnoreObject(win, appMainWindow.menubar);
mainWindow->resize(800, 600);
Q_EMIT mainWindow->windowStateChanged();
mainWindow->show();
return QApplication::exec();
}

View File

@ -0,0 +1,6 @@
TARGET = QMainWindow
TEMPLATE = app
QT += widgets
SOURCES += main.cpp
FORMS += TitleBar.ui MainWindow.ui
include($$PWD/../common.pri)

View File

@ -24,8 +24,10 @@ SOURCES += \
qtacryliceffecthelper.cpp
qtHaveModule(widgets) {
QT += widgets
HEADERS += qtacrylicwidget.h
SOURCES += qtacrylicwidget.cpp
HEADERS += qtacrylicwidget.h \
qtacrylicmainwindow.h
SOURCES += qtacrylicwidget.cpp \
qtacrylicmainwindow.cpp
}
qtHaveModule(quick) {
QT += quick

202
qtacrylicmainwindow.cpp Normal file
View File

@ -0,0 +1,202 @@
/*
* MIT License
*
* Copyright (C) 2021 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 "qtacrylicmainwindow.h"
#include "utilities.h"
#include "framelesswindowsmanager.h"
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
#include <QtGui/qpainter.h>
QtAcrylicMainWindow::QtAcrylicMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) {}
QtAcrylicMainWindow::~QtAcrylicMainWindow() = default;
QColor QtAcrylicMainWindow::tintColor() const
{
const QColor color = m_acrylicHelper.getTintColor();
if (color.isValid() && (color != Qt::transparent)) {
return color;
} else {
return palette().color(backgroundRole());
}
}
void QtAcrylicMainWindow::setTintColor(const QColor &value)
{
if (!value.isValid()) {
qWarning() << "Tint color not valid.";
return;
}
if (m_acrylicHelper.getTintColor() != value) {
m_acrylicHelper.setTintColor(value);
QPalette pal = palette();
pal.setColor(backgroundRole(), m_acrylicHelper.getTintColor());
setPalette(pal);
//m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintColorChanged();
}
}
qreal QtAcrylicMainWindow::tintOpacity() const
{
return m_acrylicHelper.getTintOpacity();
}
void QtAcrylicMainWindow::setTintOpacity(const qreal value)
{
if (m_acrylicHelper.getTintOpacity() != value) {
m_acrylicHelper.setTintOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintOpacityChanged();
}
}
qreal QtAcrylicMainWindow::noiseOpacity() const
{
return m_acrylicHelper.getNoiseOpacity();
}
void QtAcrylicMainWindow::setNoiseOpacity(const qreal value)
{
if (m_acrylicHelper.getNoiseOpacity() != value) {
m_acrylicHelper.setNoiseOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT noiseOpacityChanged();
}
}
bool QtAcrylicMainWindow::frameVisible() const
{
return m_frameVisible;
}
void QtAcrylicMainWindow::setFrameVisible(const bool value)
{
if (m_frameVisible != value) {
m_frameVisible = value;
update();
Q_EMIT frameVisibleChanged();
}
}
QColor QtAcrylicMainWindow::frameColor() const
{
return m_acrylicHelper.getFrameColor();
}
void QtAcrylicMainWindow::setFrameColor(const QColor &value)
{
if (m_acrylicHelper.getFrameColor() != value) {
m_acrylicHelper.setFrameColor(value);
update();
Q_EMIT frameColorChanged();
}
}
qreal QtAcrylicMainWindow::frameThickness() const
{
return m_acrylicHelper.getFrameThickness();
}
void QtAcrylicMainWindow::setFrameThickness(const qreal value)
{
if (m_acrylicHelper.getFrameThickness() != value) {
m_acrylicHelper.setFrameThickness(value);
update();
Q_EMIT frameThicknessChanged();
}
}
bool QtAcrylicMainWindow::acrylicEnabled() const
{
return m_acrylicEnabled;
}
void QtAcrylicMainWindow::setAcrylicEnabled(const bool value)
{
if (m_acrylicEnabled != value) {
m_acrylicEnabled = value;
if (m_inited) {
Utilities::setBlurEffectEnabled(windowHandle(), m_acrylicEnabled);
}
setAutoFillBackground(!m_acrylicEnabled);
setAttribute(Qt::WA_NoSystemBackground, m_acrylicEnabled);
setAttribute(Qt::WA_OpaquePaintEvent, m_acrylicEnabled);
setBackgroundRole(m_acrylicEnabled ? QPalette::Base : QPalette::Window);
update();
Q_EMIT acrylicEnabledChanged();
}
}
void QtAcrylicMainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
updateContentMargin();
if (!m_inited) {
FramelessWindowsManager::addWindow(windowHandle());
m_acrylicHelper.install(windowHandle());
m_acrylicHelper.updateAcrylicBrush(tintColor());
connect(&m_acrylicHelper, &QtAcrylicEffectHelper::needsRepaint, this, qOverload<>(&QtAcrylicMainWindow::update));
m_inited = true;
}
}
void QtAcrylicMainWindow::updateContentMargin()
{
const qreal m = isMaximized() ? 0.0 : 1.0 / devicePixelRatioF();
setContentsMargins(m, m, m, m);
}
void QtAcrylicMainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
const QRect rect = {0, 0, width(), height()};
if (acrylicEnabled()) {
m_acrylicHelper.paintWindowBackground(&painter, rect);
}
if (frameVisible()) {
m_acrylicHelper.paintWindowFrame(&painter, rect);
}
QMainWindow::paintEvent(event);
}
void QtAcrylicMainWindow::changeEvent(QEvent *event)
{
if( event->type()==QEvent::WindowStateChange ) {
updateContentMargin();
Q_EMIT windowStateChanged();
}
QMainWindow::changeEvent(event);
}
void QtAcrylicMainWindow::displaySystemMenu()
{
#ifdef WIN32
Utilities::displaySystemMenu(windowHandle());
#endif
}

92
qtacrylicmainwindow.h Normal file
View File

@ -0,0 +1,92 @@
/*
* MIT License
*
* Copyright (C) 2021 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 "framelesshelper_global.h"
#include <QtWidgets/qmainwindow.h>
#include "qtacryliceffecthelper.h"
class FRAMELESSHELPER_EXPORT QtAcrylicMainWindow : public QMainWindow
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QtAcrylicMainWindow)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged)
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged)
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged)
Q_PROPERTY(bool frameVisible READ frameVisible WRITE setFrameVisible NOTIFY frameVisibleChanged)
Q_PROPERTY(QColor frameColor READ frameColor WRITE setFrameColor NOTIFY frameColorChanged)
Q_PROPERTY(qreal frameThickness READ frameThickness WRITE setFrameThickness NOTIFY frameThicknessChanged)
Q_PROPERTY(bool acrylicEnabled READ acrylicEnabled WRITE setAcrylicEnabled NOTIFY acrylicEnabledChanged)
public:
explicit QtAcrylicMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
~QtAcrylicMainWindow() override;
QColor tintColor() const;
void setTintColor(const QColor &value);
qreal tintOpacity() const;
void setTintOpacity(const qreal value);
qreal noiseOpacity() const;
void setNoiseOpacity(const qreal value);
bool frameVisible() const;
void setFrameVisible(const bool value);
QColor frameColor() const;
void setFrameColor(const QColor &value);
qreal frameThickness() const;
void setFrameThickness(const qreal value);
bool acrylicEnabled() const;
void setAcrylicEnabled(const bool value);
Q_SIGNALS:
void tintColorChanged();
void tintOpacityChanged();
void noiseOpacityChanged();
void frameVisibleChanged();
void frameColorChanged();
void frameThicknessChanged();
void acrylicEnabledChanged();
void windowStateChanged();
public Q_SLOTS:
void displaySystemMenu();
protected:
void showEvent(QShowEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void changeEvent(QEvent *event) override;
private:
QtAcrylicEffectHelper m_acrylicHelper;
bool m_frameVisible = true;
bool m_acrylicEnabled = false;
bool m_inited = false;
void updateContentMargin();
};

View File

@ -73,6 +73,7 @@ Q_SIGNALS:
void frameColorChanged();
void frameThicknessChanged();
void acrylicEnabledChanged();
void windowStateChanged();
protected:
void showEvent(QShowEvent *event) override;