一个无边框带默认标题栏的widget

来源:互联网 发布:windows ce最新版本 编辑:程序博客网 时间:2024/04/30 14:10

还有一些扩展接口没有添加,有兴趣的同学可以自己添加

1.WinTitleBarWidgetBase类声明

#ifndef WINTITLEBARWIDGETBASE_H
#define WINTITLEBARWIDGETBASE_H
#include <QWidget>
class QPushButton;
#define GRADIENTICON "QWidget{background-image: url(:/gradienticon.png);}"
#define MAXLOGOSTYLE "QPushButton {background: transparent;border-image:url(:/windowmax.png)} QPushButton:hover {background: transparent;border-image:url(:/windowmaxH.png)}"
#define REDUCELOGOSTYLE "QPushButton {background: transparent;border-image:url(:/windowreduce.png)} QPushButton:hover {background: transparent;border-image:url(:/windowreduceH.png)}"
/**
* @class WinTitleBarWidgetBase
* @brief 一个可扩展工具栏,默认最大、最小、关闭三个按钮(靠右侧)
*/
class WinTitleBarWidgetBase : public QWidget
{
    Q_OBJECT
public:
    explicit WinTitleBarWidgetBase(QWidget *pParent = NULL);
    virtual ~WinTitleBarWidgetBase();
    /**
    * @brief 正常大小和最大化切换时,改变图标样式
    * @param[in] style 最新样式
    */
    void ChangeMaxIconStyle(const QString& style);
    /**
    * @brief 标题栏的可扩展区域(占据三个默认按钮剩余区域)
    * @return 可扩展区域
    */
    QWidget* getContentWidget()const;
protected:
    /**
    * @brief 重写过滤器事件
    * @param[in] pObject 监控的对象
    * @param[in] pEvent 发生的事件
    */
    virtual bool eventFilter(QObject *pObject, QEvent *pEvent);
    /**
    * @brief 重写鼠标双击事件
    * @param[in] pEvent 鼠标双击事件
    */
    virtual void mouseDoubleClickEvent(QMouseEvent *pEvent);
    virtual void mousePressEvent(QMouseEvent *e);
    virtual void mouseMoveEvent(QMouseEvent *e);
    virtual void mouseReleaseEvent(QMouseEvent *e);
signals:
    /**
    * @brief 当点击关闭按钮时发送
    */
    void sigClose();
    /**
    * @brief 当点击最小化按钮时发送
    */
    void sigShowMin();
    /**
    * @brief 当点击最大化按钮时发送
    */
    void sigShowMax();
private:
    bool m_bLeftButtonPress;
    QPoint m_ptPress;
    QPoint m_ptMove;
    QPushButton *m_pCloseBtn; ///< 关闭按钮
    QPushButton *m_pMinBtn;   ///< 最小化按钮
    QPushButton *m_pMaxBtn;   ///< 最大化按钮
    QWidget *m_pContentWidget;///< 可扩展区域
};
#endif


2.WinTitleBarWidgetBase类实现

#include <QEvent>
#include <QMouseEvent>
#include <QPushButton>
#include <QHBoxLayout>
#include "wintitlebarwidgetbase.h"
#define MINLOGOSTYLE "QPushButton {background: transparent;border-image:url(:/windowmin.png)} QPushButton:hover {background: transparent;border-image:url(:/windowminH.png)}"
#define CLOSELOGOSTYLE "QPushButton {background: transparent;border-image:url(:/windowclose.png)} QPushButton:hover {background: transparent;border-image:url(:/windowcloseH.png)}"
WinTitleBarWidgetBase::WinTitleBarWidgetBase(QWidget *pParent):
    QWidget(pParent)
{
    //大小策略,水平方向优先,垂直方向固定高度
    setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    setFixedHeight(25);
    //通过点击获取焦点
    setFocusPolicy(Qt::ClickFocus);
    //背景色自动填充
    setAutoFillBackground(true);
    //鼠标形状箭头
    setCursor(QCursor(Qt::ArrowCursor));
    //跟踪鼠标移动事件
    setMouseTracking(true);
    //关闭按钮
    m_pCloseBtn = new QPushButton(this);
    m_pCloseBtn->setFixedSize(25,25);
    m_pCloseBtn->setCursor(Qt::PointingHandCursor);
    m_pCloseBtn->setStyleSheet(CLOSELOGOSTYLE);
    m_pCloseBtn->installEventFilter(this);
    //最小化按钮
    m_pMinBtn = new QPushButton(this);
    m_pMinBtn->setFixedSize(25,25);
    m_pMinBtn->setCursor(Qt::PointingHandCursor);
    m_pMinBtn->setStyleSheet(MINLOGOSTYLE);
    m_pMinBtn->installEventFilter(this);
    //最大化按钮
    m_pMaxBtn = new QPushButton(this);
    m_pMaxBtn->setFixedSize(25,25);
    m_pMaxBtn->setCursor(Qt::PointingHandCursor);
    m_pMaxBtn->setStyleSheet(MAXLOGOSTYLE);
    m_pMaxBtn->installEventFilter(this);
    //扩展区
    m_pContentWidget = new QWidget(this);
    m_pContentWidget->setAutoFillBackground(true);
    m_pContentWidget->setStyleSheet("QWidget{background: transparent;}");
    QHBoxLayout *pMainLayout = new QHBoxLayout(this);
    pMainLayout->addWidget(m_pContentWidget);
    pMainLayout->addWidget(m_pMinBtn);
    pMainLayout->addWidget(m_pMaxBtn);
    pMainLayout->addWidget(m_pCloseBtn);
    pMainLayout->setSpacing(0);
    pMainLayout->setContentsMargins(0,0,0,2);
    m_ptPress = QPoint(0,0);
    m_ptMove =  QPoint(0,0);
    m_bLeftButtonPress = false;
}
WinTitleBarWidgetBase::~WinTitleBarWidgetBase()
{
}
void WinTitleBarWidgetBase::ChangeMaxIconStyle(const QString &style)
{
    m_pMaxBtn->setStyleSheet(style);
}
QWidget *WinTitleBarWidgetBase::getContentWidget() const
{
    return m_pContentWidget;
}
bool WinTitleBarWidgetBase::eventFilter(QObject *pObject, QEvent *pEvent)
{
    if(pEvent->type() == QEvent::MouseButtonPress)
    {
        if(pObject == m_pCloseBtn)
        {
            emit sigClose();
        }
        if(pObject == m_pMinBtn)
        {
            emit sigShowMin();
        }
        if(pObject == m_pMaxBtn)
        {
            emit sigShowMax();
        }
    }
    return QWidget::eventFilter(pObject,pEvent);
}
void WinTitleBarWidgetBase::mouseDoubleClickEvent(QMouseEvent *pEvent)
{
    emit sigShowMax();
    QWidget::mouseDoubleClickEvent(pEvent);
}
void WinTitleBarWidgetBase::mousePressEvent(QMouseEvent *e)
{
    const int expand = 5; //鼠标指针误差范围
    if(e->button() == Qt::LeftButton)
    {
        if(e->y() <= expand ||
           e->x() <= expand ||
           rect().width()-(e->x()) <= expand)
        {
            e->ignore();
            return;
        }
        m_ptPress = e->globalPos();
        m_bLeftButtonPress = true;
    }
    e->ignore();
}
void WinTitleBarWidgetBase::mouseMoveEvent(QMouseEvent *e)
{
    QWidget *pMainWidget = qobject_cast<QWidget *>(parent());
    if(m_bLeftButtonPress && pMainWidget && !(pMainWidget->isMaximized()))
    {
        m_ptMove = e->globalPos();
        pMainWidget->move(pMainWidget->pos()+m_ptMove-m_ptPress);
        //重新设置m_ptPress;
        m_ptPress = m_ptMove;
    }
    e->ignore();
}
void WinTitleBarWidgetBase::mouseReleaseEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton)
    {
        m_bLeftButtonPress = false;
    }
    e->ignore();
}

3.WinMainWidgetBase类声明

#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class WinTitleBarWidgetBase;
/**
* @class WinMainWidgetBase
* @brief 无边框带默认标题栏的widget控件
*/
class WinMainWidgetBase : public QWidget
{
    Q_OBJECT
public:
    /**
    * @enum Direction
    * @brief 鼠标改变控件大小时拖动方向
    */
    enum Direction
    {
        UP=0,       ///< 向上
        DOWN=1,     ///< 向下
        LEFT,       ///< 向左
        RIGHT,      ///< 向右
        LEFTTOP,    ///< 左上
        LEFTBOTTOM, ///< 左下
        RIGHTBOTTOM,///< 右下
        RIGHTTOP,   ///< 右上
        NONE        ///< 无方向
    };
    explicit WinMainWidgetBase(QWidget *pParent = NULL);
    virtual ~WinMainWidgetBase();
    /**
    * @brief 设置四周边框宽度
    * @param[in] left 左边框宽度
    * @param[in] top 上边框宽度
    * @param[in] right 右边框宽度
    * @param[in] bottom 下边框宽度
    */
    void SetFrameWidth(int left, int top, int right, int bottom);
    /**
    * @brief 可扩展区域
    */
    QWidget* GetContentWidget() const;
protected:
    /**
    * @brief 重写基类鼠标释放事件
    * @param[in] event 鼠标释放事件
    */
    virtual void mouseReleaseEvent(QMouseEvent *event);
    /**
    * @brief 重写基类鼠标移动事件
    * @param[in] event 鼠标移动事件
    */
    virtual void mouseMoveEvent(QMouseEvent *event);
    /**
    * @brief 重写基类鼠标按压事件
    * @param[in] event 鼠标按压事件
    */
    virtual void mousePressEvent(QMouseEvent *event);
    /**
    * @brief 确定拖拽方向和鼠标形状
    * @param[in] cursorGlobalPoint 鼠标全局位置
    */
    void region(const QPoint &cursorGlobalPoint);
private slots:
    /**
    * @brief 窗口正常和最大化显示
    */
    void showMaxOrNormal();
private:
    int m_leftBorderWidth;    ///< 左边框宽度
    int m_TopBorderWidth;     ///< 上边框宽度
    int m_rightBorderWidth;   ///< 右边框宽度
    int m_bottomBorderWidth;  ///< 下边框宽度
    bool m_isLeftPressDown;   ///< 判断左键是否按下
    Direction m_direction;    ///< 窗口大小改变时,记录改变方向
    QRect m_rectRestoreWindow;///< 储存窗口大小
    QWidget *m_pContentWidget;///< 可扩展区域
    WinTitleBarWidgetBase *m_pTitleBar;///< 默认标题栏
};
#endif // WIDGET_H

4.WinMainWidgetBase类实现

#include "winmainwidgetbase.h"
#include "wintitlebarwidgetbase.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QVBoxLayout>
WinMainWidgetBase::WinMainWidgetBase(QWidget *pParent):
    QWidget(pParent)
{
    m_leftBorderWidth = 2;
    m_TopBorderWidth = 2;
    m_rightBorderWidth = 2;
    m_bottomBorderWidth = 2;
    m_isLeftPressDown = false;
    m_direction = NONE;
    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
    setMouseTracking(true);
    m_pTitleBar = new WinTitleBarWidgetBase(this);
    m_pTitleBar->setStyleSheet(GRADIENTICON);;
    connect(m_pTitleBar,&WinTitleBarWidgetBase::sigClose,this,&QWidget::close);
    connect(m_pTitleBar,&WinTitleBarWidgetBase::sigShowMin,this,&QWidget::showMinimized);
    connect(m_pTitleBar,&WinTitleBarWidgetBase::sigShowMax,this,&WinMainWidgetBase::showMaxOrNormal);
    m_pContentWidget = new QWidget(this);
    m_pContentWidget->setMouseTracking(true);
    m_pContentWidget->setAutoFillBackground(true);
    m_pContentWidget->setCursor(QCursor(Qt::ArrowCursor));
    m_pContentWidget->setPalette(QPalette(QColor("grey")));
    QVBoxLayout *pMainLayout = new QVBoxLayout(this);
    pMainLayout->setSpacing(2);
    pMainLayout->addWidget(m_pTitleBar);
    pMainLayout->addWidget(m_pContentWidget);
    //设置边框宽度
    SetFrameWidth(m_leftBorderWidth,m_TopBorderWidth,m_rightBorderWidth,m_bottomBorderWidth);
    setMinimumSize(600,500);
    m_rectRestoreWindow = geometry();
}
WinMainWidgetBase::~WinMainWidgetBase()
{
}
void WinMainWidgetBase::SetFrameWidth(int left, int top, int right, int bottom)
{
    if(0 == left && 0 == top && 0 == right && 0 == bottom)
    {
        layout()->setContentsMargins(left,top,right,bottom);
    }
    else
    {
        m_leftBorderWidth = left;
        m_TopBorderWidth = top;
        m_rightBorderWidth = right;
        m_bottomBorderWidth = bottom;
        layout()->setContentsMargins(left,top,right,bottom);
    }
}
QWidget *WinMainWidgetBase::GetContentWidget() const
{
    return m_pContentWidget;
}
void WinMainWidgetBase::region(const QPoint &cursorGlobalPoint)
{
    const int PADDING = 2;
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());
    int x = cursorGlobalPoint.x();
    int y = cursorGlobalPoint.y();
    if(tl.x() + PADDING >= x && tl.x() <= x && tl.y() + PADDING >= y && tl.y() <= y)
    {
        // 左上角
        m_direction = LEFTTOP;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }
    else if(x >= rb.x() - PADDING && x <= rb.x() && y >= rb.y() - PADDING && y <= rb.y())
    {
        // 右下角
        m_direction = RIGHTBOTTOM;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    }
    else if(x <= tl.x() + PADDING && x >= tl.x() && y >= rb.y() - PADDING && y <= rb.y())
    {
        //左下角
        m_direction = LEFTBOTTOM;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }
    else if(x <= rb.x() && x >= rb.x() - PADDING && y >= tl.y() && y <= tl.y() + PADDING)
    {
        // 右上角
        m_direction = RIGHTTOP;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    }
    else if(x <= tl.x() + PADDING && x >= tl.x())
    {
        // 左边
        m_direction = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }
    else if( x <= rb.x() && x >= rb.x() - PADDING)
    {
        // 右边
        m_direction = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }
    else if(y >= tl.y() && y <= tl.y() + PADDING)
    {
        // 上边
        m_direction = UP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }
    else if(y <= rb.y() && y >= rb.y() - PADDING)
    {
        // 下边
        m_direction = DOWN;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }
    else
    {
        // 默认
        m_direction = NONE;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}
void WinMainWidgetBase::showMaxOrNormal()
{
    if(!isMaximized()) //当前窗口化时 实现最大化
    {
        m_rectRestoreWindow = geometry();
        showMaximized();
        m_pTitleBar->ChangeMaxIconStyle(REDUCELOGOSTYLE);
        SetFrameWidth(0,0,0,0);
    }
    else //否则窗口化
    {
        showNormal();
        m_rectRestoreWindow = geometry();
        m_pTitleBar->ChangeMaxIconStyle(MAXLOGOSTYLE);
        SetFrameWidth(m_leftBorderWidth,m_TopBorderWidth,m_rightBorderWidth,m_bottomBorderWidth);
    }
}
void WinMainWidgetBase::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        m_isLeftPressDown = false;
        if(m_direction != NONE)
        {
            m_direction = NONE;
            this->releaseMouse();
            this->setCursor(QCursor(Qt::ArrowCursor));
        }
    }
}
void WinMainWidgetBase::mousePressEvent(QMouseEvent *event)
{
    switch(event->button())
    {
    case Qt::LeftButton:
        m_isLeftPressDown = true;
        if(m_direction != NONE)
        {
            this->mouseGrabber();
        }
        break;
    default:
        QWidget::mousePressEvent(event);
    }
}
void WinMainWidgetBase::mouseMoveEvent(QMouseEvent *event)
{
    QPoint gloPoint = event->globalPos();
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());
    if(!m_isLeftPressDown && !isMaximized())
    {
        this->region(gloPoint);
    }
    else
    {
        if(m_direction != NONE)
        {
            QRect rMove(tl, rb);
            switch(m_direction)
            {
            case LEFT:
            {
                if(rb.x() - gloPoint.x() <= this->minimumWidth())
                {
                    rMove.setX(tl.x());
                }
                else
                {
                    rMove.setX(gloPoint.x());
                }
            }
                break;
            case RIGHT:
            {
                rMove.setWidth(gloPoint.x() - tl.x());
            }
                break;
            case UP:
            {
                if(rb.y() - gloPoint.y() <= this->minimumHeight())
                {
                    rMove.setY(tl.y());
                }
                else
                {
                    rMove.setTop(gloPoint.y());
                }
            }
                break;
            case DOWN:
            {
                rMove.setHeight(gloPoint.y() - tl.y());
            }
                break;
            case LEFTTOP:
            {
                if(rb.x() - gloPoint.x() <= this->minimumWidth())
                {
                    rMove.setX(tl.x());
                }
                else
                {
                    rMove.setX(gloPoint.x());
                }
                if(rb.y() - gloPoint.y() <= this->minimumHeight())
                {
                    rMove.setY(tl.y());
                }
                else
                {
                    rMove.setY(gloPoint.y());
                }
            }
                break;
            case RIGHTTOP:
            {
                if(rb.y() - gloPoint.y() <= this->minimumHeight() ||
                   gloPoint.x() - tl.x() <= this->minimumWidth())
                {
                    rMove.setY(tl.y());
                }
                else
                {
                    rMove.setY(gloPoint.y());
                }
                rMove.setWidth(gloPoint.x() - tl.x());
            }
                break;
            case LEFTBOTTOM:
            {
                if(rb.x() - gloPoint.x() <= this->minimumWidth() ||
                   gloPoint.y() - tl.y() <= this->minimumHeight())
                {
                    rMove.setX(tl.x());
                }
                else
                {
                    rMove.setX(gloPoint.x());
                }
                rMove.setHeight(gloPoint.y() - tl.y());
            }
                break;
            case RIGHTBOTTOM:
            {
                rMove.setWidth(gloPoint.x() - tl.x());
                rMove.setHeight(gloPoint.y() - tl.y());
            }
                break;
            default:
                break;
            }
            setGeometry(rMove);
        }
        if(m_direction == NONE && isMaximized()&& m_isLeftPressDown && event->y() <= 25)
        {
            showNormal();
            int desktopWidth = qApp->desktop()->availableGeometry().width(); //全屏桌面宽度
            float scale = (float)event->globalX()/desktopWidth;
            int newX = event->globalX()-m_rectRestoreWindow.width()*scale;
            setGeometry(newX, 0, m_rectRestoreWindow.width(), m_rectRestoreWindow.height());
            m_pTitleBar->ChangeMaxIconStyle(MAXLOGOSTYLE);
            SetFrameWidth(m_leftBorderWidth,m_TopBorderWidth,m_rightBorderWidth,m_bottomBorderWidth);
        }
    }
    QWidget::mouseMoveEvent(event);
}

5.资源文件图片

6.pro文件

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = framelesswidget
TEMPLATE = app
DESTDIR = ./bin
SOURCES += main.cpp \
    winmainwidgetbase.cpp \
    wintitlebarwidgetbase.cpp
HEADERS  += \
    winmainwidgetbase.h \
    wintitlebarwidgetbase.h
RESOURCES += \
    resource.qrc

7.main.cpp

#include "winmainwidgetbase.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    WinMainWidgetBase w;
    w.show();
    return a.exec();
}

0 0
原创粉丝点击