QT去除窗口边框(无边框)
ch21_TencentMeetingLogin::ch21_TencentMeetingLogin(QWidget *parent): QDialog(parent)
{ui.setupUi(this);this->setWindowFlags(Qt::FramelessWindowHint);//去除窗口边框
}
但此时窗口不能拖动且点击任务栏程序图标不能最小化!
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
上面代码设置Qt框架中窗口的属性。具体来说,它调用了一个窗口对象(假设为this
指针所指向的对象)的setWindowFlags
方法,以设置该窗口的标志(Flags)。这里设置的标志有两个:Qt::FramelessWindowHint
和Qt::WindowMinMaxButtonsHint
。
-
Qt::FramelessWindowHint
:这个标志用于创建一个无边框的窗口。通常,窗口会有一个默认的边框,包括标题栏、边缘等。设置了这个标志后,窗口将不再显示这些元素,使得窗口可以自定义外观。 -
Qt::WindowMinMaxButtonsHint
:这个标志用于在窗口的标题栏上显示最小化(Min)和最大化(Max)按钮。在设置无边框后,Qt::WindowMinMaxButtonsHint
可能不会生效,因为无边框窗口通常不会有标题栏,也就没有最小化等按钮,从而也无法显示这些按钮。所以我们需要手动设置!
当你在Qt中设置一个窗口为无边框(Qt::FramelessWindowHint)时,窗口通常会失去默认的拖动和大小调整功能,因为这些功能通常依赖于窗口的边框和标题栏。就像Qt::WindowMinMaxButtonsHint 标志可能不会在无边框窗口中生效,因为它依赖于标题栏来显示最小化和最大化按钮。
如何实现窗口移动
去掉窗口边框后,窗口无法移动,如何让窗口动起来呢?
重写鼠标按下,移动的事件
protected:void mouseMoveEvent(QMouseEvent *event) override;void mousePressEvent(QMouseEvent *event) override;
注意相对位置和绝对位置:
窗口位置:this->pos()窗口左上角相对于桌面左上角
鼠标位置:event->pos()是鼠标相对于应用程序的位置,相对位置
event->globalPos()相对于桌面原点的位置,绝对位置
private:QPoint diff_pos;//鼠标和窗口位置的距离QPoint window_pos;//鼠标位置QPoint mouse_pos;//窗口位置
void Widget::mousePressEvent(QMouseEvent *event)
{mouse_pos = event->globalPos();//鼠标绝对位置window_pos = this->pos();//窗口绝对位置diff_pos = mouse_pos - window_pos;//距离差
}void Widget::mouseMoveEvent(QMouseEvent *event)
{QPoint pos = event->globalPos();//此时鼠标的位置this->move(pos-diff_pos);//计算窗口的位置在哪里}
自定义标题栏并实现拖拽拉伸
去掉窗口边框后,没有标题栏,需要自定义标题栏。创建标题栏界面类,添加到界面上,并添加最小化,最大化,关闭按钮。
创建标题栏类CTitleBar
头文件
#ifndef CTITLEBAR_H
#define CTITLEBAR_H#include <QWidget>
#include <QLabel>
#include <QPushButton>
class CTitleBar : public QWidget//所有的窗口都需要QWidget
{Q_OBJECT
public:explicit CTitleBar(QObject *parent = nullptr);~CTitleBar();
private://m表示成员函数,p表示指针QLabel *m_pLogo;QLabel *m_ptitleTextLabel;QPushButton *m_pSetBtn;QPushButton *m_pMinBtn;QPushButton *m_pMaxBtn;QPushButton *m_pCloseBtn;private:void initUI();//UI初始化
};#endif // CTITLEBAR_H
cpp
#include "ctitlebar.h"
#include <QHBoxLayout>
CTitleBar::CTitleBar(QObject *parent)
{initUI();
}CTitleBar::~CTitleBar()
{}void CTitleBar::initUI()
{//禁止父窗口影响子窗口的样式setAttribute(Qt::WA_StyledBackground);this->setFixedHeight(32+5*2);//32+上下距离this->setStyleSheet("background-color:rgb(155,155,155)");m_pLogo = new QLabel(this);m_pLogo->setFixedSize(32,32);m_pLogo->setText("logo");m_ptitleTextLabel = new QLabel(this);m_ptitleTextLabel->setText("我是标题");m_ptitleTextLabel->setFixedWidth(120);m_pSetBtn = new QPushButton(this);m_pSetBtn->setFixedSize(32,32);m_pMinBtn = new QPushButton(this);m_pMinBtn->setFixedSize(32,32);m_pMaxBtn = new QPushButton(this);m_pMaxBtn->setFixedSize(32,32);m_pCloseBtn = new QPushButton(this);m_pCloseBtn->setFixedSize(32,32);QHBoxLayout *pHlay = new QHBoxLayout(this);pHlay->addWidget(m_pLogo);pHlay->addWidget(m_ptitleTextLabel);pHlay->addStretch();//加弹簧pHlay->addWidget(m_pSetBtn);pHlay->addWidget(m_pMinBtn);pHlay->addWidget(m_pMaxBtn);pHlay->addWidget(m_pCloseBtn);pHlay->setContentsMargins(5,5,5,5);
}
widget.h
private:void initUI();CTitleBar *m_pTitleBar = nullptr;//标题栏
widget.cpp
void Widget::initUI()
{m_pTitleBar = new CTitleBar(this);QWidget *w = new QWidget(this);w->setMinimumSize(800,600);QVBoxLayout *pVlay = new QVBoxLayout(this);pVlay->addWidget(m_pTitleBar);pVlay->addWidget(w);pVlay->setContentsMargins(0,0,0,0);
}
一个很有用的Qt属性:
//禁止父窗口影响子窗口的样式setAttribute(Qt::WA_StyledBackground);
无边框窗口拖拽移动另外一种的方法
#include <qt_windows.h>
void CTitleBar::mousePressEvent(QMouseEvent *event)
{if(ReleaseCapture()){QWidget *pWindow = this->window();if(pWindow->isTopLevel()){SendMessage(HWND(pWindow->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);}}
}
这段代码的目的是允许用户通过点击自定义的标题栏来移动整个窗口。它通过释放鼠标捕获、获取顶级窗口句柄,并发送一个模拟点击标题栏的系统命令消息来实现这一功能。
ReleaseCapture()
是一个Windows API函数,用于释放当前窗口的鼠标捕获。在Windows系统中,如果一个窗口捕获了鼠标,那么所有的鼠标输入都会发送到那个窗口,直到捕获被释放。在这里,它的目的是确保可以移动窗口,即使鼠标最初不是在这个窗口上按下的。如果ReleaseCapture()
调用成功,它会返回非零值(在Windows中通常表示成功),函数继续执行内部的代码块。
QWidget *pWindow = this->window();
: 这行代码获取CTitleBar
所属的顶级窗口(即包含这个标题栏的窗口)。this->window()
调用返回的是CTitleBar
的直接或间接父窗口,且这个父窗口必须是顶级窗口(即没有父窗口的窗口,通常是应用程序的主窗口)。
if(pWindow->isTopLevel()){...}
: 这行代码检查获取到的窗口是否是顶级窗口。这是必要的,因为只有顶级窗口才能被移动。
发送WM_SYSCOMMAND消息:
SendMessage(HWND(pWindow->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
: 这行代码是Windows API的调用,用于发送一个系统命令消息(WM_SYSCOMMAND
)到指定的窗口(在这里是pWindow
)。WM_SYSCOMMAND
消息用于执行系统命令,比如最小化、最大化、关闭窗口或移动窗口等。HWND(pWindow->winId())
将Qt的窗口句柄(winId()
返回)转换为Windows的句柄类型(HWND
)。SC_MOVE+HTCAPTION
是一个组合值,SC_MOVE
表示移动窗口的命令,HTCAPTION
是一个特殊的击中测试代码,表示标题栏区域。将这两个值相加,告诉系统像用户点击了标题栏一样移动窗口。- 最后一个参数
0
是额外的消息信息,对于WM_SYSCOMMAND
和SC_MOVE+HTCAPTION
的组合来说,这个参数通常不需要。
这代码依赖于Windows特定的API,不适用于跨平台开发!
无边窗口的拉伸改变大小
#include <qt_windows.h>
未完待续