-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathborderlesswindow.cpp
More file actions
140 lines (120 loc) · 4.93 KB
/
borderlesswindow.cpp
File metadata and controls
140 lines (120 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "borderlesswindow.h"
#include "ui_borderlesswindow.h"
#include "lmsghandler.h"
#include <QDialog>
#include <QDebug>
#include <QPainter>
#include <windows.h>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#pragma comment(lib, "user32.lib")
#include <QMovie>
#include <QLabel>
BorderlessWindow::BorderlessWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::BorderlessWindow),
_isShadow(false)
{
ui->setupUi(this);
/* 虽然在之后的SetWindowLongPtr里面已经设置了各种Style,这里其实已经无意义,但是此处必须设置,
* 相当于一个标志,告诉Qt我们是无边框的,否则frameGeometry的返回以及绘制区域都会出现错误.*/
this->setWindowFlags(Qt::FramelessWindowHint);
// we cannot just use WS_POPUP style
// WS_THICKFRAME: without this the window cannot be resized and so aero snap, de-maximizing and minimizing won't work
// WS_SYSMENU: enables the context menu with the move, close, maximize, minize... commands (shift + right-click on the task bar item)
// HOWEVER, this also enables the menu with the maximize buttons in the title bar, which will exist inside your client area and are clickable.
// WS_CAPTION: enables aero minimize animation/transition
// WS_MAXIMIZEBOX, WS_MINIMIZEBOX: enable minimize/maximize
SetWindowLongPtr((HWND)this->winId(), GWL_STYLE, WS_POPUP | WS_THICKFRAME
| WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);
//因为过滤器我们安在了QAbstractEventDispatcher上,这个过滤器可以收到所有线程的消息,防止影响其他窗体,做一个注册标志.
LMsgHandler *pMsgHandler = LMsgHandler::getInstance();
emit pMsgHandler->registerBorderlessWin((quint32)winId());
setAttribute(Qt::WA_StyledBackground);
connect(ui->pTitleBar, <itleBar::minRequested, this, &QWidget::showMinimized);
connect(ui->pTitleBar, <itleBar::maxRequested, this, &QWidget::showMaximized);
connect(ui->pTitleBar, <itleBar::restoreRequested, this, &QWidget::showNormal);
connect(ui->pTitleBar, <itleBar::closeRequested, this, &QWidget::close);
}
BorderlessWindow::~BorderlessWindow()
{
delete ui;
}
void BorderlessWindow::on_pAddBtn_clicked()
{
QWidget *w = new QWidget;
w->show();
}
void BorderlessWindow::on_pShadowBtn_clicked()
{
_isShadow = !_isShadow;
static const MARGINS shadow_state[2] = { { 0, 0, 0, 0 }, { 1, 1, 1, 1 } };
DwmExtendFrameIntoClientArea((HWND)this->winId(), &shadow_state[_isShadow]);
// redraw frame
SetWindowPos((HWND)winId(), nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
}
bool BorderlessWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
const MSG *msg = static_cast<MSG*>(message);
// WM_CREATE、WM_NCCALCSIZE这两消息在这里获取不到,只能在外面的过滤器才可以获取到.Fuck it.
if (msg->message == WM_CREATE) {
int a = 0;
}
if (msg->message == WM_NCCALCSIZE) {
int a = 0;
}
if(msg->message == WM_SIZE)
{
// fix margin for SIZE_MAXIMIZED
if(msg->hwnd && msg->wParam == SIZE_MAXIMIZED)
setContentsMargins(0,0, 16, 16);
else
setContentsMargins(0, 0, 0, 0);
return false;
}
if (msg->message == WM_NCHITTEST) {
const int HIT_BORDER = 8;
int xPos = ((int)(short)LOWORD(msg->lParam)) - this->frameGeometry().x();
int yPos = ((int)(short)HIWORD(msg->lParam)) - this->frameGeometry().y();
/* 1、下面的判断顺序不可改变。比如HTTOPLEFT包括Top,我们要保证优先级高的先执行.
* 2、每次必须return,不可最后return,因为除了这些情况,我们一定要返回false,让Qt自己处理,否则会影响其他控件的事件接收.*/
if (xPos > 0 && xPos < HIT_BORDER && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPLEFT;
return true;
}
if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPRIGHT;
return true;
}
if (xPos > 0 && xPos < HIT_BORDER && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMLEFT;
return true;
}
if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMRIGHT;
return true;
}
if (xPos >= 0 && xPos < HIT_BORDER) {
*result = HTLEFT;
return true;
}
if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {
*result = HTRIGHT;
return true;
}
if (yPos >= 0 && yPos < HIT_BORDER) {
*result = HTTOP;
return true;
}
if (yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOM;
return true;
}
// 相当于选中标题栏,用于移动操作.为了判断点击在哪个子窗体上,所以放在这里,没有在LNativeEventFilter中处理.
if (this->childAt(xPos, yPos) == ui->pTitleBar) {
*result = HTCAPTION;
return true;
}
}
return false;
}