#Qt自定义标题栏并实现拖拽
【最新】修改移动时偶现bug,mousePressEvent和mouseMoveEvent修改。
很多时候,Qt自带的窗体边框不能满足我们的需求,或者我们觉得由于系统的主题影响导致界面太丑了,我们需要自行定义一个好看并和普通标题栏功能相同的控件去替代,以达到美化我们的程序界面的目的;本文简单的实现了该功能。
下面是运行截图,由于图片选的比较丑,所以看起来不好看:
实现了鼠标拖拽事件,没有为标题栏添加鼠标右键事件以及其他美化功能,可以自行添加。
##拖拽实现详解:
首先需要了解Qt的一些函数的意义:
MouseEvent中的globalPos()函数返回的是相对屏幕的位置坐标,而pos()则是返回鼠标在当前控件(即捕获该鼠标事件的控件)中的位置;
QWidget窗体的geometry().topLeft()则返回的是当前窗体的左上角在屏幕中的位置;
其次让我们看图说话,理解下窗体移动:
然后我们每次只要把上次的位置作为起始位置,就是一次次的拖拽了。
最后,我们列出算式:
startPos = event->globalPos(); // 鼠标的全局初始位置,按下时记住
curWindowPos = geometry().topleft(); // 窗体的全局位置,移动时
endPos = event->globalPos(); // 鼠标按下发生移动之后的位置,移动时
move(curWindowPos+(startPos-endPos)); // 根据矢量移动方向是初始位置减去末位置,移动时
startPos = endPos; // 将初始位置记为上次末位置,然后执行直到释放拖拽,移动时
##头文件
// WindowHeader.h
#ifndef WINDOWHEADER_H
#define WINDOWHEADER_H
#include <QLabel>
#include <QWidget>
#include <QToolButton>
#include <QHBoxLayout>
#include <QPoint>
#include <QString>
// 自定义控件,可拖拽标题栏
class WindowHeader : public QWidget
{
Q_OBJECT
public:
// 构造函数
WindowHeader(const char* appName, QWidget *parent);
// 设置关闭按钮icon
void SetCloseImage(const char* path);
// 设置最小化按钮icon
void SetMinImage(const char* path);
// 设置最大化按钮icon
void SetMaxImage(const char* path);
// 设置迷你模式按钮icon
void SetMiniImage(const char* path);
// 设置软件配置按钮icon
void SetSettingImage(const char* path);
// 设置皮肤按钮icon
void SetSkinImage(const char* path);
// 设置软件LOGO按钮icon
void SetAppLogo(const char* path,int w=20,int h=20);
// 获取软件名
QString GetAppName() { return msAppName; }
protected:
// 重写鼠标事件
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
// 将信号中转,不直接处理信号
signals:
void ClickedClose();
void ClickedMin();
void ClickedMax();
void ClickedMini();
void ClickedSetting();
void ClickedSkin();
private:
// 应用名
QString msAppName;
// 关闭按钮
QToolButton* mTlbtnClose;
// 最小化按钮
QToolButton* mTlbtnMin;
// 最大化按钮
QToolButton* mTlbtnMax;
// 迷你模式按钮
QToolButton* mTlbtnMini;
// 软件配置按钮
QToolButton* mTlbtnSetting;
// 皮肤设置按钮
QToolButton* mTlbtnSkin;
// 呈现应用名称
QLabel* mLblAppName;
// 呈现应用LOGO
QLabel* mLblAppLogo;
// 整体布局
QHBoxLayout* mLytMain;
// 鼠标上次移动开始时相对屏幕的位置
QPoint mPntStart;
// 鼠标是否持续按下
bool mbKeepPressed;
// 父窗口的指针
QWidget *mWidParent;
};
#endif // WINDOWHEADER_H
##源文件
// WindowHeader.cpp
#include "WindowHeader.h"
#include <QMouseEvent>
#include <QPixmap>
#include <QIcon>
WindowHeader::WindowHeader(const char* appName,QWidget *parent)
:QWidget(parent),msAppName(appName)
{
// 父窗口指针赋值,并设置父窗口为无边框模式
mWidParent = parent;
mWidParent->setWindowFlags(Qt::FramelessWindowHint | mWidParent->windowFlags());
// 初始化按钮
mTlbtnClose = new QToolButton(this);
mTlbtnMin = new QToolButton(this);
mTlbtnMax = new QToolButton(this);
mTlbtnMini = new QToolButton(this);
mTlbtnSetting = new QToolButton(this);
mTlbtnSkin = new QToolButton(this);
// 初始化标签
mLblAppName = new QLabel(this);
mLblAppName->setText(msAppName);
mLblAppLogo = new QLabel(this);
// 初始化布局
mLytMain = new QHBoxLayout(this);
mLytMain->setContentsMargins(2,2,2,2);
mLytMain->setSpacing(2);
// 设置布局
mLytMain->addWidget(mLblAppLogo);
mLytMain->addWidget(mLblAppName);
// 设置“弹簧”,将呈现和按钮功能分开
mLytMain->addStretch();
mLytMain->addWidget(mTlbtnSkin);
mLytMain->addWidget(mTlbtnSetting);
mLytMain->addWidget(mTlbtnMini);
mLytMain->addWidget(mTlbtnMin);
mLytMain->addWidget(mTlbtnMax);
mLytMain->addWidget(mTlbtnClose);
// 将内部按钮信号全部发送出去,内部不做业务逻辑绑定
connect(mTlbtnClose,SIGNAL(clicked(bool)),SIGNAL(ClickedClose()));
connect(mTlbtnMax,SIGNAL(clicked(bool)),SIGNAL(ClickedMax()));
connect(mTlbtnMin,SIGNAL(clicked(bool)),SIGNAL(ClickedMin()));
connect(mTlbtnMini,SIGNAL(clicked(bool)),SIGNAL(ClickedMini()));
connect(mTlbtnSetting,SIGNAL(clicked(bool)),SIGNAL(ClickedSetting()));
connect(mTlbtnSkin,SIGNAL(clicked(bool)),SIGNAL(ClickedSkin()));
}
// 设置应用LOGO
void WindowHeader::SetAppLogo(const char *path,int w,int h)
{
QPixmap newPix = QPixmap(path).scaled(w,h,Qt::KeepAspectRatio);
mLblAppLogo->setPixmap(newPix);
}
void WindowHeader::SetSkinImage(const char *path)
{
QIcon icon(path);
mTlbtnSkin->setIcon(icon);
}
void WindowHeader::SetSettingImage(const char *path)
{
QIcon icon(path);
mTlbtnSetting->setIcon(icon);
}
void WindowHeader::SetMiniImage(const char *path)
{
QIcon icon(path);
mTlbtnMini->setIcon(icon);
}
void WindowHeader::SetMaxImage(const char *path)
{
QIcon icon(path);
mTlbtnMax->setIcon(icon);
}
void WindowHeader::SetMinImage(const char *path)
{
QIcon icon(path);
mTlbtnMin->setIcon(icon);
}
void WindowHeader::SetCloseImage(const char *path)
{
QIcon icon(path);
mTlbtnClose->setIcon(icon);
}
// 重写mouseMoveEvent
void WindowHeader::mouseMoveEvent(QMouseEvent *event)
{
// 持续按住才做对应事件
if (mbKeepPressed)
{
// 将父窗体移动到父窗体之前的位置加上鼠标移动的位置【event->globalPos()- mPntStart】
mWidParent->move(mPntParentStart + event->globalPos()- mPntMouseStart);
}
QWidget::mouseMoveEvent(event);
}
// 重写mousePressEvent
void WindowHeader::mousePressEvent(QMouseEvent *event)
{
// 鼠标左键按下事件
if (event->button() == Qt::LeftButton)
{
// 记录鼠标在屏幕中的位置
mPntMouseStart = event->globalPos();
mPntParentStart = mWidParent->geometry().topLeft();
// 记录鼠标状态
mbKeepPressed = true;
}
QWidget::mousePressEvent(event);
}
// 重写mouseReleaseEvent
void WindowHeader::mouseReleaseEvent(QMouseEvent *event)
{
// 鼠标左键释放
if (event->button() == Qt::LeftButton)
{
// 记录鼠标状态
mbKeepPressed = false;
}
QWidget::mouseReleaseEvent(event);
}
原文出处:http://blog.youkuaiyun.com/motou263514/article/details/78090483