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 控件。
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 函数重绘。
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 类添加阴影和拖动
- 添加投影和初始化
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);
}
- 添加拖动
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);
}
}
- 最后在主窗口中创建出来,并设置其位置显示出来就可以了。