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;
}
}