Skip to content

Commit 7661ae6

Browse files
JimZhouZZYda-liii
authored andcommitted
!767 [201_26] 在 macOS 平台上实现无边框标签栏
1 parent a252777 commit 7661ae6

File tree

10 files changed

+780
-11
lines changed

10 files changed

+780
-11
lines changed

devel/201_26.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 201_26 无边框标签栏
2+
## 2025/10/06 在 macOS 平台上实现无边框标签栏
23
## 2025/10/05 在 macOS 平台上添加 QWindowKit 依赖
34
## 2025/10/05 在 macOS 上把菜单栏放到工具栏中
45
### What?
Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
1+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
2+
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#include "windowbar.hpp"
6+
#include "windowbar_p.hpp"
7+
8+
#include <QtCore/QDebug>
9+
#include <QtCore/QLocale>
10+
#include <QtGui/QtEvents>
11+
12+
namespace QWK {
13+
14+
WindowBarPrivate::WindowBarPrivate () {
15+
w = nullptr;
16+
autoTitle= true;
17+
autoIcon = false;
18+
}
19+
20+
WindowBarPrivate::~WindowBarPrivate ()= default;
21+
22+
void
23+
WindowBarPrivate::init () {
24+
Q_Q (WindowBar);
25+
layout= new QHBoxLayout ();
26+
if (QLocale::system ().textDirection () == Qt::RightToLeft) {
27+
layout->setDirection (QBoxLayout::RightToLeft);
28+
}
29+
30+
layout->setContentsMargins (QMargins ());
31+
layout->setSpacing (0);
32+
for (int i= IconButton; i <= CloseButton; ++i) {
33+
insertDefaultSpace (i);
34+
}
35+
q->setLayout (layout);
36+
}
37+
38+
void
39+
WindowBarPrivate::setWidgetAt (int index, QWidget* widget) {
40+
auto item = layout->takeAt (index);
41+
auto orgWidget= item->widget ();
42+
if (orgWidget) {
43+
orgWidget->deleteLater ();
44+
}
45+
delete item;
46+
if (!widget) {
47+
insertDefaultSpace (index);
48+
}
49+
else {
50+
layout->insertWidget (index, widget);
51+
}
52+
}
53+
54+
QWidget*
55+
WindowBarPrivate::takeWidgetAt (int index) {
56+
auto item = layout->itemAt (index);
57+
auto orgWidget= item->widget ();
58+
if (orgWidget) {
59+
item= layout->takeAt (index);
60+
delete item;
61+
insertDefaultSpace (index);
62+
}
63+
return orgWidget;
64+
}
65+
66+
WindowBar::WindowBar (QWidget* parent)
67+
: WindowBar (*new WindowBarPrivate (), parent) {}
68+
69+
WindowBar::~WindowBar ()= default;
70+
71+
QMenuBar*
72+
WindowBar::menuBar () const {
73+
Q_D (const WindowBar);
74+
return static_cast<QMenuBar*> (d->widgetAt (WindowBarPrivate::MenuWidget));
75+
}
76+
77+
QLabel*
78+
WindowBar::titleLabel () const {
79+
Q_D (const WindowBar);
80+
return static_cast<QLabel*> (d->widgetAt (WindowBarPrivate::TitleLabel));
81+
}
82+
83+
QWidget*
84+
WindowBar::titleWidget () const {
85+
Q_D (const WindowBar);
86+
return d->widgetAt (WindowBarPrivate::TitleLabel);
87+
}
88+
89+
QAbstractButton*
90+
WindowBar::iconButton () const {
91+
Q_D (const WindowBar);
92+
return static_cast<QAbstractButton*> (
93+
d->widgetAt (WindowBarPrivate::IconButton));
94+
}
95+
96+
QAbstractButton*
97+
WindowBar::pinButton () const {
98+
Q_D (const WindowBar);
99+
return static_cast<QAbstractButton*> (
100+
d->widgetAt (WindowBarPrivate::PinButton));
101+
}
102+
103+
QAbstractButton*
104+
WindowBar::minButton () const {
105+
Q_D (const WindowBar);
106+
return static_cast<QAbstractButton*> (
107+
d->widgetAt (WindowBarPrivate::MinimizeButton));
108+
}
109+
110+
QAbstractButton*
111+
WindowBar::maxButton () const {
112+
Q_D (const WindowBar);
113+
return static_cast<QAbstractButton*> (
114+
d->widgetAt (WindowBarPrivate::MaximizeButton));
115+
}
116+
117+
QAbstractButton*
118+
WindowBar::closeButton () const {
119+
Q_D (const WindowBar);
120+
return static_cast<QAbstractButton*> (
121+
d->widgetAt (WindowBarPrivate::CloseButton));
122+
}
123+
124+
void
125+
WindowBar::setMenuBar (QMenuBar* menuBar) {
126+
Q_D (WindowBar);
127+
auto org= takeMenuBar ();
128+
if (org) org->deleteLater ();
129+
if (!menuBar) return;
130+
d->setWidgetAt (WindowBarPrivate::MenuWidget, menuBar);
131+
menuBar->setSizePolicy (QSizePolicy::Maximum, QSizePolicy::Minimum);
132+
}
133+
134+
void
135+
WindowBar::setTitleLabel (QLabel* label) {
136+
// 使用setTitleWidget来保持一致性
137+
setTitleWidget (label);
138+
}
139+
140+
void
141+
WindowBar::setTitleWidget (QWidget* widget) {
142+
Q_D (WindowBar);
143+
auto org= takeTitleWidget ();
144+
if (org) org->deleteLater ();
145+
if (!widget) return;
146+
d->setWidgetAt (WindowBarPrivate::TitleLabel, widget);
147+
widget->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Minimum);
148+
149+
// 如果设置的是QLabel,且开启了autoTitle,则设置文本
150+
if (QLabel* label= qobject_cast<QLabel*> (widget)) {
151+
if (d->autoTitle && d->w) label->setText (d->w->windowTitle ());
152+
}
153+
}
154+
155+
void
156+
WindowBar::setIconButton (QAbstractButton* btn) {
157+
Q_D (WindowBar);
158+
auto org= takeIconButton ();
159+
if (org) org->deleteLater ();
160+
if (!btn) return;
161+
d->setWidgetAt (WindowBarPrivate::IconButton, btn);
162+
if (d->autoIcon && d->w) btn->setIcon (d->w->windowIcon ());
163+
btn->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred);
164+
}
165+
166+
void
167+
WindowBar::setPinButton (QAbstractButton* btn) {
168+
Q_D (WindowBar);
169+
auto org= takePinButton ();
170+
if (org) org->deleteLater ();
171+
if (!btn) return;
172+
d->setWidgetAt (WindowBarPrivate::PinButton, btn);
173+
connect (btn, &QAbstractButton::clicked, this, &WindowBar::pinRequested);
174+
}
175+
176+
void
177+
WindowBar::setMinButton (QAbstractButton* btn) {
178+
Q_D (WindowBar);
179+
auto org= takeMinButton ();
180+
if (org) org->deleteLater ();
181+
if (!btn) return;
182+
d->setWidgetAt (WindowBarPrivate::MinimizeButton, btn);
183+
connect (btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested);
184+
}
185+
186+
void
187+
WindowBar::setMaxButton (QAbstractButton* btn) {
188+
Q_D (WindowBar);
189+
auto org= takeMaxButton ();
190+
if (org) org->deleteLater ();
191+
if (!btn) return;
192+
d->setWidgetAt (WindowBarPrivate::MaximizeButton, btn);
193+
connect (btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested);
194+
}
195+
196+
void
197+
WindowBar::setCloseButton (QAbstractButton* btn) {
198+
Q_D (WindowBar);
199+
auto org= takeCloseButton ();
200+
if (org) org->deleteLater ();
201+
if (!btn) return;
202+
d->setWidgetAt (WindowBarPrivate::CloseButton, btn);
203+
connect (btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested);
204+
}
205+
206+
QMenuBar*
207+
WindowBar::takeMenuBar () {
208+
Q_D (WindowBar);
209+
return static_cast<QMenuBar*> (
210+
d->takeWidgetAt (WindowBarPrivate::MenuWidget));
211+
}
212+
213+
QLabel*
214+
WindowBar::takeTitleLabel () {
215+
Q_D (WindowBar);
216+
return static_cast<QLabel*> (d->takeWidgetAt (WindowBarPrivate::TitleLabel));
217+
}
218+
219+
QWidget*
220+
WindowBar::takeTitleWidget () {
221+
Q_D (WindowBar);
222+
return d->takeWidgetAt (WindowBarPrivate::TitleLabel);
223+
}
224+
225+
QAbstractButton*
226+
WindowBar::takeIconButton () {
227+
Q_D (WindowBar);
228+
return static_cast<QAbstractButton*> (
229+
d->takeWidgetAt (WindowBarPrivate::IconButton));
230+
}
231+
232+
QAbstractButton*
233+
WindowBar::takePinButton () {
234+
Q_D (WindowBar);
235+
auto btn= static_cast<QAbstractButton*> (
236+
d->takeWidgetAt (WindowBarPrivate::PinButton));
237+
if (!btn) {
238+
return nullptr;
239+
}
240+
disconnect (btn, &QAbstractButton::clicked, this, &WindowBar::pinRequested);
241+
return btn;
242+
}
243+
244+
QAbstractButton*
245+
WindowBar::takeMinButton () {
246+
Q_D (WindowBar);
247+
auto btn= static_cast<QAbstractButton*> (
248+
d->takeWidgetAt (WindowBarPrivate::MinimizeButton));
249+
if (!btn) {
250+
return nullptr;
251+
}
252+
disconnect (btn, &QAbstractButton::clicked, this,
253+
&WindowBar::minimizeRequested);
254+
return btn;
255+
}
256+
257+
QAbstractButton*
258+
WindowBar::takeMaxButton () {
259+
Q_D (WindowBar);
260+
auto btn= static_cast<QAbstractButton*> (
261+
d->takeWidgetAt (WindowBarPrivate::MaximizeButton));
262+
if (!btn) {
263+
return nullptr;
264+
}
265+
disconnect (btn, &QAbstractButton::clicked, this,
266+
&WindowBar::maximizeRequested);
267+
return btn;
268+
}
269+
270+
QAbstractButton*
271+
WindowBar::takeCloseButton () {
272+
Q_D (WindowBar);
273+
auto btn= static_cast<QAbstractButton*> (
274+
d->takeWidgetAt (WindowBarPrivate::CloseButton));
275+
if (!btn) {
276+
return nullptr;
277+
}
278+
disconnect (btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested);
279+
return btn;
280+
}
281+
282+
QWidget*
283+
WindowBar::hostWidget () const {
284+
Q_D (const WindowBar);
285+
return d->w;
286+
}
287+
288+
void
289+
WindowBar::setHostWidget (QWidget* w) {
290+
Q_D (WindowBar);
291+
292+
QWidget* org= d->w;
293+
if (org) {
294+
org->removeEventFilter (this);
295+
}
296+
d_ptr->w= w;
297+
if (w) {
298+
w->installEventFilter (this);
299+
}
300+
}
301+
302+
bool
303+
WindowBar::titleFollowWindow () const {
304+
Q_D (const WindowBar);
305+
return d->autoTitle;
306+
}
307+
308+
void
309+
WindowBar::setTitleFollowWindow (bool value) {
310+
Q_D (WindowBar);
311+
d->autoTitle= value;
312+
}
313+
314+
bool
315+
WindowBar::iconFollowWindow () const {
316+
Q_D (const WindowBar);
317+
return d->autoIcon;
318+
}
319+
320+
void
321+
WindowBar::setIconFollowWindow (bool value) {
322+
Q_D (WindowBar);
323+
d->autoIcon= value;
324+
}
325+
326+
bool
327+
WindowBar::eventFilter (QObject* obj, QEvent* event) {
328+
Q_D (WindowBar);
329+
auto w= d->w;
330+
if (obj == w) {
331+
QAbstractButton* iconBtn = iconButton ();
332+
QWidget* titleWidget= this->titleWidget ();
333+
QLabel* label= qobject_cast<QLabel*> (titleWidget); // 检查是否为QLabel
334+
QAbstractButton* maxBtn= maxButton ();
335+
switch (event->type ()) {
336+
case QEvent::WindowIconChange: {
337+
if (d_ptr->autoIcon && iconBtn) {
338+
iconBtn->setIcon (w->windowIcon ());
339+
iconChanged (w->windowIcon ());
340+
}
341+
break;
342+
}
343+
case QEvent::WindowTitleChange: {
344+
if (d_ptr->autoTitle && label) { // 只对QLabel设置文本
345+
label->setText (w->windowTitle ());
346+
titleChanged (w->windowTitle ());
347+
}
348+
break;
349+
}
350+
case QEvent::WindowStateChange: {
351+
if (maxBtn) {
352+
maxBtn->setChecked (w->isMaximized ());
353+
}
354+
break;
355+
}
356+
default:
357+
break;
358+
}
359+
}
360+
return QWidget::eventFilter (obj, event);
361+
}
362+
363+
void
364+
WindowBar::titleChanged (const QString& text) {
365+
Q_UNUSED (text)
366+
}
367+
368+
void
369+
WindowBar::iconChanged (const QIcon& icon) {
370+
Q_UNUSED (icon)
371+
}
372+
373+
WindowBar::WindowBar (WindowBarPrivate& d, QWidget* parent)
374+
: QFrame (parent), d_ptr (&d) {
375+
d.q_ptr= this;
376+
377+
d.init ();
378+
}
379+
380+
} // namespace QWK

0 commit comments

Comments
 (0)