Qt Widget 自定义TitleBar带阴影窗口

自定义一个titlebar窗口,

不带任何资源、QSS,纯代码

1. 设置主窗口

透明背景,让central_widget透明方式显示,给后续main添加dropshadow效果,用于放置实际的业务控件。

setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
setAttribute(Qt::WA_TranslucentBackground);

    
QWidget *central_widget = new QWidget(this);
setCentralWidget(central_widget);
central_widget->setStyleSheet("background:transparent");

QVBoxLayout *central_layout = new QVBoxLayout(central_widget);
central_layout->setMargin(5);  // 这个 margin 一般为effect的 一半

QWidget *main = new QWidget(this);
central_layout->addWidget(main);

    QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(this);
    effect->setBlurRadius(10);
    effect->setColor(QColor("#373737"));
    effect->setOffset(0,0);

main->setStyleSheet("background-color: black");
main->setGraphicsEffect(effect);

QVBoxLayout *vbox_main = new QVBoxLayout(main);
vbox_main->setMargin(0);
vbox_main->setSpacing(0);

...
// 添加后续业务代码。

2. 自定义右侧的按钮组

QWidget *titlebar = new QWidget(this);
titlebar->setStyleSheet("background-color: rgb(192,192,192)");
titlebar->setMaximumHeight(28);
vbox_main->addWidget(titlebar);

QHBoxLayout *titlebar_layout = new QHBoxLayout(titlebar);
titlebar_layout->setMargin(2);
titlebar_layout->setSpacing(2);

titlebar_layout->addStretch();


QPushButton* min_button = new QPushButton(this);
min_button->setIcon(style()->standardIcon(QStyle::SP_TitleBarMinButton));
titlebar_layout->addWidget(min_button);
connect(min_button, &QPushButton::pressed, this, [=]()
{
    showMinimized();
});

QPushButton* max_button = new QPushButton(this);
max_button->setIcon(style()->standardIcon(QStyle::SP_TitleBarMaxButton));
titlebar_layout->addWidget(max_button);
connect(max_button, &QPushButton::pressed, this, [=]()
{
    showFullScreen();
});

QPushButton* normal_button = new QPushButton(this);
normal_button->setIcon(style()->standardIcon(QStyle::SP_TitleBarNormalButton));
titlebar_layout->addWidget(normal_button);
connect(normal_button, &QPushButton::pressed, this, [=]()
{
    showNormal();
});
normal_button->setVisible(false);

QPushButton* close_button = new QPushButton(this);
close_button->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
titlebar_layout->addWidget(close_button);
connect(close_button, &QPushButton::pressed, this, [=]()
{
    close();
});

其中,最小化、全屏化、正常化、关闭按钮,可以取 Qt内置的标准icon,

style()->standardIcon(QStyle::SP_TitleBarMinButton);
SP_TitleBarMaxButton
SP_TitleBarNormalButton
SP_TitleBarCloseButton

可通过QPainter来变色

QIcon changeColor(const QIcon &icon, const QSize &size, const QColor &color)
{
    QPixmap pixmap = new icon.pixmap(size);
    QPainter painter(&pixmap);
    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
    painter.fillRect(pixmap.rect(), color);
    return QIcon(pixmap);
}

通过获取topLevelWidget, 然后调用下列方法

    void showMinimized();
    void showMaximized();
    void showFullScreen();
    void showNormal();

    bool close();

3. 标题栏的拖动

void QFramelessShadowWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && event->x() < _max_button->x() - 30 && event->y() < 30)
    {
        _dragging = true;
        _mouse_position = event->globalPos();
        _window_position = geometry().topLeft();
    }
}

void QFramelessShadowWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (_dragging && !_is_fullscreen)
    {
        QPoint offset = event->globalPos() - _mouse_position;
        move( _window_position + offset);
    }
}

void QFramelessShadowWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
        _dragging = false;
}

4. 最后一个问题

当全屏后,会出现 放置实际的业务控件的区域显示不全,此时不需要显示dropshadow的阴影效果。可以响应主窗口的changeEvent事件,动态对layout的margin进行调整

void QFramelessShadowWindow::changeEvent(QEvent *event)
{
    bool from_normal = false;
    if (QEvent::WindowStateChange == event->type())
    {
        QWindowStateChangeEvent *state_event = static_cast<QWindowStateChangeEvent *>(event);
        if (Q_NULLPTR != state_event)
        {
            if (state_event->oldState() == Qt::WindowNoState)
            {
                from_normal = true;
            }
            else if (state_event->oldState() == Qt::WindowFullScreen)
            {
                _max_button->setVisible(true);
                _normal_button->setVisible(false);
                centralWidget()->layout()->setMargin(5);
                _is_fullscreen = false;
            }
        }
    }

    QMainWindow::changeEvent(event);
    Qt::WindowStates state = windowState();
    if (from_normal && state == Qt::WindowFullScreen)
    {
        _max_button->setVisible(false);
        _normal_button->setVisible(true);
        centralWidget()->layout()->setMargin(0);
        _is_fullscreen = true;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值