qt实现自定义标题栏的widget

本文档展示了如何创建一个自定义的窗口类MyWidget,该窗口无边框,具备标题栏、图标、最小化、最大化和关闭按钮功能。用户可以通过鼠标操作实现窗口的移动、缩放和最大化/还原。代码中详细实现了各个功能的响应事件处理,如鼠标点击、双击和移动等。此外,还提供了设置窗口标题、图标和颜色的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现思路:新建类MyWidget,继承Widget。

新建两个widget,titilewidget、centerwidget分别用于放置标题栏和其他内容。

在titlewidget里边添加图标、标题、最小化、最大化、关闭按钮

........

效果

MyWidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H
#pragma execution_character_set("UTF-8")
#include <QWidget>
#include <QIcon>
#include <QPushButton>
#include <QLabel>
#include <QMouseEvent>
#include <QLayout>
#include <QRect>
#include <QApplication>
#include <QDesktopWidget>
#include <QPalette>
#include <QStyle>
#include <QToolButton>


class MyWidget: public QWidget
{
    Q_OBJECT
private:
    QWidget *titleWidget;//标题栏Widget
    QToolButton *iconButton;//图标
    QPushButton *closeButton;//关闭按钮
    QPushButton *maxButton;//最大化按钮
    QPushButton *minButton;//最小化按钮
    QLabel *titleLabel;//标题label
    QRect winRect;//窗口位置
    bool m_ismaxed;//窗口是否最大化
    QPoint m_leftDownp;//左键按下的位置
    QPoint m_leftDownMapp;//左键按下时全局位置
    bool m_isleftClicked;//左键是否按下
    enum
    {
        Left,
        Right,
        Up,
        Bottom,
        LeftUp,
        RightUp,
        LeftBottom,
        RightBottom,
        Center
    };
    bool ApproximatelyEqual(const int a, const int b, int persion)
    {
        return abs(a-b) < persion ? true : false;
    }

protected:
    void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    bool event(QEvent *event) Q_DECL_OVERRIDE;
    int GetMouseWidgetPos(QPoint p);//获取鼠标所在位置
    void setCursorShape(int CalPos);//设置鼠标样式

private:
    void InitializationWidget();//窗口初始化
    void ShowMaxSize();//窗口最大化
    void ShowNormalSize();//窗口非最大化

private slots:
    void WinNormalMaxChange();//窗口最大化最小化改变函数

public:
    QWidget *centerWidget;//中心widget,可操作空间
    MyWidget(QWidget *parent = nullptr);
    void SetWinTitle(QString title);//设置窗口标题
    void SetWinIcon(QIcon icon);//设置窗口图标
    void SetWinIcon(QImage img);
    void SetColor(uint r, uint g, uint b);//设置窗口颜色
};

#endif // MYWIDGET_H

MyWidget.cpp

#include "MyWidget.h"
#include <QDebug>

MyWidget::MyWidget(QWidget *parent)
{
    setWindowFlags (Qt::FramelessWindowHint);
    this->resize(1200, 1000);
    m_ismaxed = 0;
    m_isleftClicked = 0;
    InitializationWidget();
    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(minButton, SIGNAL(clicked()), this, SLOT(showMinimized()));
    connect(maxButton, SIGNAL(clicked()), this, SLOT(WinNormalMaxChange()));
    setAttribute(Qt::WA_Hover, true);
}


void MyWidget::InitializationWidget()
{
    titleWidget = new QWidget();
    titleWidget->setStyleSheet("background-color:white;");
    titleWidget->resize(1200, 40);
    centerWidget = new QWidget();
    iconButton = new QToolButton();
    iconButton->setFixedSize(40, 40);
    iconButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
    enum QStyle::StandardPixmap Icon = (enum QStyle::StandardPixmap) 0;
    iconButton->setIcon(QApplication::style()->standardIcon(Icon));
    iconButton->setStyleSheet("background:transparent");
    titleLabel = new QLabel("MyWidget");
    titleLabel->setStyleSheet("background:transparent;font-size:18px;border-width:0px");
    closeButton = new QPushButton("🗙");
    maxButton = new QPushButton("🗖");
    minButton = new QPushButton("⎯");
    closeButton->setFixedSize(60, 40);
    minButton->setFixedSize(60, 40);
    maxButton->setFixedSize(60, 40);
    minButton->setStyleSheet("QPushButton{border-style:none;background:transparent;font-size:20px;border-width:0px;text-align:center;}"
                             "QPushButton:hover{background-color:rgb(229, 229, 229);}");
    closeButton->setStyleSheet("QPushButton{border-style:none;background:transparent;font-size:20px;border-width:0px;text-align:center;}"
                               "QPushButton:hover{background-color:rgb(232, 17, 35);color:white;}");
    maxButton->setStyleSheet("QPushButton{border-style:none;background:transparent;font-size:20px;border-width:0px;text-align:center;}"
                             "QPushButton:hover{background-color:rgb(229, 229, 229);}");
    //标题widget里边加东西
    QSpacerItem *verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
    QHBoxLayout *hboxlayout = new QHBoxLayout();
    hboxlayout->addWidget(iconButton);
    hboxlayout->addWidget(titleLabel);
    hboxlayout->addItem(verticalSpacer);
    hboxlayout->addWidget(minButton);
    hboxlayout->addWidget(maxButton);
    hboxlayout->addWidget(closeButton);
    hboxlayout->setSpacing(0);
    hboxlayout->setContentsMargins(0,0,0,0);
    titleWidget->setLayout(hboxlayout);
    //设置标题widget与中心widget布局
    QVBoxLayout *vboxlayout = new QVBoxLayout();
    vboxlayout->addWidget(titleWidget, 1);
    vboxlayout->addWidget(centerWidget, 100);
    vboxlayout->setSpacing(0);
    vboxlayout->setContentsMargins(0,0,0,0);
    this->setLayout(vboxlayout);
}


void MyWidget::WinNormalMaxChange()
{
    if (m_ismaxed)
    {
        ShowNormalSize();
    }
    else
    {
        ShowMaxSize();
    }
}


void MyWidget::ShowMaxSize()
{
    winRect = this->geometry();
    QRect trect = QApplication::desktop()->screenGeometry();
    this->setGeometry(trect);
    maxButton->setText("🗗");
    m_ismaxed = 1;
}


void MyWidget::ShowNormalSize()
{
    this->setGeometry(winRect);
    maxButton->setText("🗖");
    m_ismaxed = 0;
}


void MyWidget::mousePressEvent(QMouseEvent *event)
{
    //左键拖动窗口移动、左键控制移动
    if (event->button() == Qt::LeftButton)
    {
        //为了拖动
        m_leftDownp = event->globalPos()-pos();
        //为了缩放
        m_leftDownMapp = event->globalPos();
        m_isleftClicked = 1;
    }
    QWidget::mousePressEvent(event);
}


void MyWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    // 左键双击最大化
    if (event->button() == Qt::LeftButton && titleWidget->geometry().contains(this->mapFromGlobal(QCursor::pos())))
    {
        if (m_ismaxed)
        {
            ShowNormalSize();
        }
        else
        {
            ShowMaxSize();
        }
    }
    QWidget::mouseDoubleClickEvent(event);
}


void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_isleftClicked = 0;
    }
}


void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (m_isleftClicked)
    {
        if (titleWidget->geometry().contains(this->mapFromGlobal(QCursor::pos())))
        {
            //执行移动
            this->move(event->globalPos() - m_leftDownp);
        }
        else
        {
            //执行缩放
            QPoint ptMoveSize = event->globalPos() - m_leftDownMapp;
            int CalPos = GetMouseWidgetPos(event->globalPos());
            QRect rect = geometry();
            switch(CalPos)
            {
            case LeftUp:
                rect.setTopLeft(winRect.topLeft()+ptMoveSize);
                break;
            case Up:
                rect.setTop(winRect.top()+ptMoveSize.y());
                break;
            case RightUp:
                rect.setTopRight(winRect.topRight()+ptMoveSize);
                break;
            case Left:
                rect.setLeft(winRect.left()+ptMoveSize.x());
                break;
            case Right:
                rect.setRight(winRect.right()+ptMoveSize.x());
                break;
            case LeftBottom:
                rect.setBottomLeft(winRect.bottomLeft()+ptMoveSize);
                break;
            case Bottom:
                rect.setBottom(winRect.bottom()+ptMoveSize.y());
                break;
            case RightBottom:
                rect.setBottomRight(winRect.bottomRight()+ptMoveSize);
                break;
            default:
                break;
            }
            setGeometry(rect);
        }
        if (!m_ismaxed)
            winRect = this->geometry();
    }
    QWidget::mouseMoveEvent(event);
}


bool MyWidget::event(QEvent *event)
{
    //更改鼠标样式
    if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverLeave || event->type() == QEvent::HoverMove)
    {
        QHoverEvent* pHoverEvent = static_cast<QHoverEvent*>(event);
        QPoint cursorPos = mapToGlobal(pHoverEvent->pos());
        if(!m_isleftClicked)
        {
            int CalPos = GetMouseWidgetPos(cursorPos);
            setCursorShape(CalPos);
        }
    }
    return QWidget::event(event);
}


int MyWidget::GetMouseWidgetPos(QPoint p)
{
    QRect rect = geometry();
    int minx = rect.x();
    int miny = rect.y();
    int maxy = rect.y()+rect.height();
    int maxx = rect.x()+rect.width();
    int x = p.x();
    int y = p.y();
    int persion = 5;
    if (ApproximatelyEqual(x, minx, persion) && ApproximatelyEqual(y, miny, persion))
        return LeftUp;
    else if (ApproximatelyEqual(x, minx, persion))
        return Left;
    else if (ApproximatelyEqual(y, miny, persion))
        return Up;
    else if (ApproximatelyEqual(x, maxx, persion) && ApproximatelyEqual(y, maxy, persion))
        return RightBottom;
    else if (ApproximatelyEqual(x, maxx, persion))
        return Right;
    else if (ApproximatelyEqual(y, maxy, persion))
        return Bottom;
    else if (ApproximatelyEqual(x, minx, persion) && ApproximatelyEqual(y, maxy, persion))
        return LeftBottom;
    else if (ApproximatelyEqual(x, maxx, persion) && ApproximatelyEqual(y, miny, persion))
        return RightUp;
    else
        return Center;
}


void MyWidget::setCursorShape(int CalPos)
{
    Qt::CursorShape cursor;
    switch(CalPos)
    {
    case LeftUp:
    case RightBottom:
        cursor = Qt::SizeFDiagCursor;
        break;
    case RightUp:
    case LeftBottom:
        cursor = Qt::SizeBDiagCursor;
        break;
    case Up:
    case Bottom:
        cursor = Qt::SizeVerCursor;
        break;
    case Left:
    case Right:
        cursor = Qt::SizeHorCursor;
        break;
    default:
        cursor = Qt::ArrowCursor;
        break;
    }
    setCursor(cursor);
}


void MyWidget::SetWinTitle(QString title)
{
    titleLabel->setText(title);
}


void MyWidget::SetWinIcon(QIcon icon)
{
    iconButton->setIcon(icon);
}


void MyWidget::SetWinIcon(QImage img)
{
    QPixmap pmap = QPixmap::fromImage(img);
    QIcon icon(pmap.scaled(iconButton->width(), iconButton->height()));
    iconButton->setIcon(icon);
}


void MyWidget::SetColor(uint r, uint g, uint b)
{
    QString str = "background-color:rgb(" +  QString::number(r) + "," + QString::number(g) + "," + QString::number(b) + ");";
    titleWidget->setStyleSheet(str);
}

调用——main.cpp

#include "MyWidget.h"
#include <QApplication>




int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MyWidget w;
    w.SetWinTitle("test");
    QImage img("D:/Postgraduate/something/QCoomapTest/QCoomapTest/gui-icon.png");
    w.SetWinIcon(img);
    w.SetColor(18, 55, 107);
    w.show();
    return a.exec();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值