Qt自定义标题栏并实现拖拽

Qt自定义标题栏并实现拖拽

  很多时候,Qt自带的窗体边框不能满足我们的需求,或者我们觉得由于系统的主题影响导致界面太丑了,我们需要自行定义一个好看并和普通标题栏功能相同的控件去替代,以达到美化我们的程序界面的目的;本文简单的实现了该功能。
  下面是运行截图,由于图片选的比较丑,所以看起来不好看:
自定义标题栏
  实现了鼠标拖拽事件,没有为标题栏添加鼠标右键事件以及其他美化功能,可以自行添加。

拖拽实现详解:

  首先需要了解Qt的一些函数的意义:
  MouseEvent中的globalPos()函数返回的是相对屏幕的位置坐标,而pos()则是返回鼠标在当前控件(即捕获该鼠标事件的控件)中的位置;
  QWidget窗体的geometry().topLeft()则返回的是当前窗体的左上角在屏幕中的位置;

  其次让我们看图说话,理解下窗体移动:
Qt自定义标题栏并实现拖拽_第1张图片
  然后我们每次只要把上次的位置作为起始位置,就是一次次的拖拽了。

  最后,我们列出算式:
  startPos = event->globalPos();      // 鼠标的全局初始位置,按下时记住
  curWindowPos = geometry().topleft();  // 窗体的全局位置,移动时
  endPos = event->globalPos();      // 鼠标按下发生移动之后的位置,移动时
  move(curWindowPos+(startPos-endPos)); // 根据矢量移动方向是初始位置减去末位置,移动时
  startPos = endPos;     // 将初始位置记为上次末位置,然后执行直到释放拖拽,移动时

头文件


// WindowHeader.h
#ifndef WINDOWHEADER_H
#define WINDOWHEADER_H

#include 
#include 
#include 
#include 

#include 
#include 

// 自定义控件,可拖拽标题栏
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(mWidParent->geometry().topLeft() + event->globalPos()- mPntStart);
        // 将鼠标在屏幕中的位置替换为新的位置
        mPntStart = event->globalPos();
    }
}

// 重写mousePressEvent
void WindowHeader::mousePressEvent(QMouseEvent *event)
{
    // 鼠标左键按下事件
    if (event->button() == Qt::LeftButton)
    {
        // 记录鼠标状态
        mbKeepPressed = true;
        // 记录鼠标在屏幕中的位置
        mPntStart = event->globalPos();
    }
}

// 重写mouseReleaseEvent
void WindowHeader::mouseReleaseEvent(QMouseEvent *event)
{
    // 鼠标左键释放
    if (event->button() == Qt::LeftButton)
    {
        // 记录鼠标状态
        mbKeepPressed = false;
    }
}

原文出处:http://blog.csdn.net/motou263514/article/details/78090483

你可能感兴趣的:(Qt/C++)