Qt 自定义控件 - 无边框窗口(3)

该文章介绍了如何在Qt环境下创建一个无边框窗口,并添加阴影效果以及实现窗口的拖动功能。通过自定义QWidget子类,利用QGraphicsDropShadowEffect添加阴影,以及通过事件过滤器处理鼠标事件来实现窗口移动。
摘要由CSDN通过智能技术生成

1 概述

此例子是结合WPS的无边框窗口做的,在实际开发中也是时常有自定义窗口的需求。目前只有拖动功能,拉伸有需要再加。

开发环境

  • 系统:Window10
  • Qt版本:5.14.2
  • 编译器:MinGW_64/MSVC 2017

2 实现效果

在这里插入图片描述

3 具体实现

3.1 添加一个继承自QWidget的窗口类

ShadowWindow类头文件定义
首次采用 Pimpl(Pointer to Implementation)惯用法,练习下。

class MyLabel : public QLabel
{
    Q_OBJECT
public:
    explicit MyLabel(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *event) override;
    void enterEvent(QEvent *event) override;
    void leaveEvent(QEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *ev) override;

private:
    const QScopedPointer<MyLabelPrivate> d_ptr;
};

class MyButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *event) override;
    void enterEvent(QEvent *event) override;
    void leaveEvent(QEvent *event) override;

signals:
    void closeButtonClicked();

private:
    const QScopedPointer<MyButtonPrivate> d_ptr;
};

class ShadowWindow : public QWidget
{
    Q_OBJECT

public:
    explicit ShadowWindow(QWidget *parent = nullptr);
    ~ShadowWindow();

    bool eventFilter(QObject *watched, QEvent *event) override;

signals:
    void closeShadowWindow();

private:
    Ui::ShadowWindow *ui;
    const QScopedPointer<ShadowWindowPrivate> d_ptr;

private:
    Q_DECLARE_PRIVATE(ShadowWindow)
    Q_DISABLE_COPY(ShadowWindow)
};

其中,红框和蓝框分别为一个自绘的 QLabel 和 QPushbutton 控件。
在这里插入图片描述

  1. MyLabel类具体实现如下
void MyLabel::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    QPen pen;
    pen.setWidthF(1.2);
    pen.setColor(d_ptr->m_color);
    p.setPen(pen);

    qreal iconY = qreal((height() - 14) / 2) + 1;
    QRectF iconRect(1, iconY, width() * 0.3, 14);
    QPainterPath path;
    path.moveTo(2.0, iconY + 10.5);
    path.arcTo(iconRect, 210, -330);
    path.lineTo(iconRect.bottomLeft());
    path.lineTo(2.0, iconY + 10.5);
    p.drawPath(path);

    qreal x = qreal(width() * 0.3);
    p.setFont(QFont("微软雅黑", 9));
    QRectF textRect(x, 0, qreal(width() * 0.7), height());
    p.drawText(textRect, Qt::AlignCenter, "反馈");
}

在鼠标进入和离开时改变m_color的颜色值,并调用 update 函数重绘。

  1. MyButton类具体实现如下
void MyButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    QPen pen;
    pen.setWidthF(1.2);
    pen.setColor(d_ptr->m_color);
    p.setPen(pen);

    p.drawLines(d_ptr->m_lines, 2);
}

其中,m_lines是在 MyButtonPrivate 类里定义的,m_color 同理 MyLabel。

const int edge      = 16;
MyButtonPrivate::MyButtonPrivate(MyButton *q)
    : q_ptr(q)
{
    m_lines[0] = QLineF(0, 0, edge, edge);
    m_lines[1] = QLineF(edge, 0, 0, edge);
}

3.2 ShadowWindow 类添加阴影和拖动

在这里插入图片描述

  1. 添加投影和初始化
void ShadowWindowPrivate::init()
{
    Q_Q(ShadowWindow);

    q->setFixedSize(700, 600);

    QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(q);
    effect->setColor(QColor(68, 68, 68));
    effect->setBlurRadius(padding * 1.5);
    effect->setOffset(0, 0);
    q->ui->widget->setGraphicsEffect(effect);

    q->ui->bgLayout->setContentsMargins(padding, padding, padding, padding);

    q->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
    q->setAttribute(Qt::WA_TranslucentBackground);
}
  1. 添加拖动
bool ShadowWindow::eventFilter(QObject *watched, QEvent *event)
{
    QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event);
    if (watched == ui->titlebarWidget && event->type() == QEvent::MouseButtonPress) {
        if (mouseEvent->button() == Qt::LeftButton) {
            d_ptr->m_isMove = true;
            d_ptr->m_lastPos = mouseEvent->pos();
            return true;
        } else {
            return false;
        }
    } else if (watched == ui->titlebarWidget && event->type() == QEvent::MouseMove) {
        if (d_ptr->m_isMove) {
            QPoint point = mouseEvent->pos();
            int offsetX = point.x() - d_ptr->m_lastPos.x();
            int offsetY = point.y() - d_ptr->m_lastPos.y();
            move(x() + offsetX, y() + offsetY);
            return true;
        } else {
            return false;
        }
    } else if (watched == ui->titlebarWidget && event->type() == QEvent::MouseButtonRelease) {
        if (mouseEvent->button() == Qt::LeftButton) {
            d_ptr->m_isMove = false;
            d_ptr->m_lastPos = QPoint();
            if (geometry().y() < 0) {
                move(geometry().x(), 0);
            }
            return true;
        } else {
            return false;
        }
    } else {
        return QWidget::eventFilter(watched, event);
    }
}
  • 最后在主窗口中创建出来,并设置其位置显示出来就可以了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值