本文代码效果如下:
本文代码:
代码之路
LoginTitleBar.h 自定义的透明标题栏
#ifndef LOGINTITLEBAR_H
#define LOGINTITLEBAR_H
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QTimer>
#include <QHBoxLayout>
#include <QPainter>
#include <QPainterPath>
#include <QFile>
#include <QMouseEvent>
enum ButtonType
{
MIN_BUTTON = 0, // 最小化和关闭按钮;
MIN_MAX_BUTTON , // 最小化、最大化和关闭按钮;
ONLY_CLOSE_BUTTON // 只有关闭按钮;
};
class LoginTitleBar : public QWidget
{
Q_OBJECT
public:
LoginTitleBar(QWidget *parent);
//这里parent没有给默认值NULL,保证在创建MyTitleBar对象时父指针必须得赋值;且赋值不为NULL;
~LoginTitleBar();
// 设置标题栏背景色及是否设置标题栏背景色透明;
void setBackgroundColor(int r, int g, int b , bool isTransparent = false);
// 设置标题栏图标;
void setTitleIcon(QString filePath , QSize IconSize = QSize(25 , 25));
// 设置标题内容;
void setTitleContent(QString titleContent , int titleFontSize = 9);
// 设置标题栏长度;
void setTitleWidth(int width);
// 设置标题栏上按钮类型;
void setButtonType(ButtonType buttonType);
// 设置标题栏中的标题是否会滚动;具体可以看效果;
void setTitleRoll();
// 设置窗口边框宽度;
void setWindowBorderWidth(int borderWidth);
// 保存/获取 最大化前窗口的位置及大小;
void saveRestoreInfo(const QPoint point, const QSize size);
void getRestoreInfo(QPoint& point, QSize& size);
private:
// 初始化控件;
void initControl();
// 信号槽的绑定;
void initConnections();
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
signals:
// 按钮触发的信号;
void signalButtonMinClicked();
void signalButtonRestoreClicked();
void signalButtonMaxClicked();
void signalButtonCloseClicked();
private slots:
// 按钮触发的槽;
void onButtonMinClicked();
void onButtonRestoreClicked();
void onButtonMaxClicked();
void onButtonCloseClicked();
void onRollTitle();
private:
QLabel* m_pIcon; // 标题栏图标;
QLabel* m_pTitleContent; // 标题栏内容;
QPushButton* m_pButtonMin; // 最小化按钮;
QPushButton* m_pButtonRestore; // 最大化还原按钮;
QPushButton* m_pButtonMax; // 最大化按钮;
QPushButton* m_pButtonClose; // 关闭按钮;
// 标题栏背景色;
int m_colorR;
int m_colorG;
int m_colorB;
// 最大化,最小化变量;
QPoint m_restorePos;
QSize m_restoreSize;
// 移动窗口的变量;
bool m_isPressed;
QPoint m_startMovePos;
// 标题栏跑马灯效果时钟;
QTimer m_titleRollTimer;
// 标题栏内容;
QString m_titleContent;
// 按钮类型;
ButtonType m_buttonType;
// 窗口边框宽度;
int m_windowBorderWidth;
// 标题栏是否透明;
bool m_isTransparent;
};
#endif // LOGINTITLEBAR_H
LoginTitleBar.cpp
#include "LoginTitleBar.h"
#define BUTTON_HEIGHT 40 // 按钮高度;
#define BUTTON_WIDTH 40 // 按钮宽度;
#define TITLE_HEIGHT 40 // 标题栏高度;
LoginTitleBar::LoginTitleBar(QWidget *parent)
: QWidget(parent)
, m_colorR(153)
, m_colorG(153)
, m_colorB(153)
, m_isPressed(false)
, m_buttonType(MIN_BUTTON)
, m_windowBorderWidth(0)
, m_isTransparent(true)
{
// 初始化;
initControl();
initConnections();
}
LoginTitleBar::~LoginTitleBar()
{
}
// 绘制标题栏背景色;
void LoginTitleBar::paintEvent(QPaintEvent *event)
{
// 是否设置标题透明;
if (!m_isTransparent)
{
//设置背景色;
QPainter painter(this);
QPainterPath pathBack;
pathBack.setFillRule(Qt::WindingFill);
pathBack.addRoundedRect(QRect(0, 0, this->width(), this->height()), 6, 6);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.fillPath(pathBack, QBrush(QColor(m_colorR, m_colorG, m_colorB)));
}
// 当窗口最大化或者还原后,窗口长度变了,标题栏的长度应当一起改变;
// 这里减去m_windowBorderWidth ,是因为窗口可能设置了不同宽度的边框;
// 如果窗口有边框则需要设置m_windowBorderWidth的值,否则m_windowBorderWidth默认为0;
if (this->width() != (this->parentWidget()->width() - m_windowBorderWidth))
{
this->setFixedWidth(this->parentWidget()->width() - m_windowBorderWidth);
}
QWidget::paintEvent(event);
}
// 以下通过mousePressEvent、mouseMoveEvent、mouseReleaseEvent三个事件实现了鼠标拖动标题栏移动窗口的效果;
void LoginTitleBar::mousePressEvent(QMouseEvent *event)
{
if (m_buttonType == MIN_MAX_BUTTON)
{
// 在窗口最大化时禁止拖动窗口;
if (m_pButtonMax->isVisible())
{
m_isPressed = true;
m_startMovePos = event->globalPos();
}
}
else
{
m_isPressed = true;
m_startMovePos = event->globalPos();
}
return QWidget::mousePressEvent(event);
}
void LoginTitleBar::mouseMoveEvent(QMouseEvent *event)
{
if (m_isPressed)
{
QPoint movePoint = event->globalPos() - m_startMovePos;
QPoint widgetPos = this->parentWidget()->pos();
m_startMovePos = event->globalPos();
this->parentWidget()->move(widgetPos.x() + movePoint.x(), widgetPos.y() + movePoint.y());
}
return QWidget::mouseMoveEvent(event);
}
void LoginTitleBar::mouseReleaseEvent(QMouseEvent *event)
{
m_isPressed = false;
return QWidget::mouseReleaseEvent(event);
}
// 双击响应事件,主要是实现双击标题栏进行最大化和最小化操作;
void LoginTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
// 只有存在最大化、还原按钮时双击才有效;
if (m_buttonType == MIN_MAX_BUTTON)
{
// 通过最大化按钮的状态判断当前窗口是处于最大化还是原始大小状态;
// 或者通过单独设置变量来表示当前窗口状态;
if (m_pButtonMax->isVisible())
{
onButtonMaxClicked();
}
else
{
onButtonRestoreClicked();
}
}
return QWidget::mouseDoubleClickEvent(event);
}
// 初始化控件;
void LoginTitleBar::initControl()
{
m_pIcon = new QLabel;
m_pTitleContent = new QLabel;
m_pButtonMin = new QPushButton;
m_pButtonRestore = new QPushButton;
m_pButtonMax = new QPushButton;
m_pButtonClose = new QPushButton;
m_pButtonMin->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));
m_pButtonRestore->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));
m_pButtonMax->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));
m_pButtonClose->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));
m_pTitleContent->setObjectName("TitleContent");
m_pButtonMin->setObjectName("ButtonMin");
m_pButtonRestore->setObjectName("ButtonRestore");
m_pButtonMax->setObjectName("ButtonMax");
m_pButtonClose->setObjectName("ButtonClose");
m_pButtonMin->setToolTip(tr("最小化"));
m_pButtonRestore->setToolTip(tr("还原"));
m_pButtonMax->setToolTip(tr("最大化"));
m_pButtonClose->setToolTip(tr("关闭"));
m_pButtonMin->setStyleSheet("QPushButton{border-image:url(:/Image/zuixiaohua.png);}\
QPushButton:hover{border-image:url(:/Image/zuixiaohua_hover.png);}");
m_pButtonClose->setStyleSheet("QPushButton{border-image:url(:/Image/guanbi.png);}\
QPushButton:hover{border-image:url(:/Image/guanbi_hover.png);}\
QPushButton:pressed{border-image:url(:/Image/guanbi_pressed.png);}");
QHBoxLayout* mylayout = new QHBoxLayout(this);
mylayout->addWidget(m_pIcon);
mylayout->addWidget(m_pTitleContent);
mylayout->addWidget(m_pButtonMin);
mylayout->addWidget(m_pButtonRestore);
mylayout->addWidget(m_pButtonMax);
mylayout->addWidget(m_pButtonClose);
mylayout->setContentsMargins(5, 0, 0, 0);
mylayout->setSpacing(0);
m_pTitleContent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
this->setFixedHeight(TITLE_HEIGHT);
this->setWindowFlags(Qt::FramelessWindowHint);
}
// 信号槽的绑定;
void LoginTitleBar::initConnections()
{
connect(m_pButtonMin, SIGNAL(clicked()), this, SLOT(onButtonMinClicked()));
connect(m_pButtonRestore, SIGNAL(clicked()), this, SLOT(onButtonRestoreClicked()));
connect(m_pButtonMax, SIGNAL(clicked()), this, SLOT(onButtonMaxClicked()));
connect(m_pButtonClose, SIGNAL(clicked()), this, SLOT(onButtonCloseClicked()));
}
// 设置标题栏背景色,在paintEvent事件中进行绘制标题栏背景色;
// 在构造函数中给了默认值,可以外部设置颜色值改变标题栏背景色;
void LoginTitleBar::setBackgroundColor(int r, int g, int b, bool isTransparent)
{
m_colorR = r;
m_colorG = g;
m_colorB = b;
m_isTransparent = isTransparent;
// 重新绘制(调用paintEvent事件);
update();
}
// 设置标题栏图标;
void LoginTitleBar::setTitleIcon(QString filePath, QSize IconSize)
{
QPixmap titleIcon(filePath);
m_pIcon->setPixmap(titleIcon.scaled(IconSize));
}
// 设置标题内容;
void LoginTitleBar::setTitleContent(QString titleContent, int titleFontSize)
{
// 设置标题字体大小;
QFont font = m_pTitleContent->font();
font.setPointSize(titleFontSize);
m_pTitleContent->setFont(font);
// 设置标题内容;
m_pTitleContent->setText(titleContent);
m_titleContent = titleContent;
}
// 设置标题栏长度;
void LoginTitleBar::setTitleWidth(int width)
{
this->setFixedWidth(width);
}
// 设置标题栏上按钮类型;
// 由于不同窗口标题栏上的按钮都不一样,所以可以自定义标题栏中的按钮;
// 这里提供了四个按钮,分别为最小化、还原、最大化、关闭按钮,如果需要其他按钮可自行添加设置;
void LoginTitleBar::setButtonType(ButtonType buttonType)
{
m_buttonType = buttonType;
switch (buttonType)
{
case MIN_BUTTON:
{
m_pButtonRestore->setVisible(false);
m_pButtonMax->setVisible(false);
}
break;
case MIN_MAX_BUTTON:
{
m_pButtonRestore->setVisible(false);
}
break;
case ONLY_CLOSE_BUTTON:
{
m_pButtonMin->setVisible(false);
m_pButtonRestore->setVisible(false);
m_pButtonMax->setVisible(false);
}
break;
default:
break;
}
}
// 设置标题栏中的标题是否会自动滚动,跑马灯的效果;
void LoginTitleBar::setTitleRoll()
{
connect(&m_titleRollTimer, SIGNAL(timeout()), this, SLOT(onRollTitle()));
m_titleRollTimer.start(200);
}
// 设置窗口边框宽度;
void LoginTitleBar::setWindowBorderWidth(int borderWidth)
{
m_windowBorderWidth = borderWidth;
}
// 保存窗口最大化前窗口的位置以及大小;
void LoginTitleBar::saveRestoreInfo(const QPoint point, const QSize size)
{
m_restorePos = point;
m_restoreSize = size;
}
// 获取窗口最大化前窗口的位置以及大小;
void LoginTitleBar::getRestoreInfo(QPoint& point, QSize& size)
{
point = m_restorePos;
size = m_restoreSize;
}
// 以下为按钮操作响应的槽;
void LoginTitleBar::onButtonMinClicked()
{
emit signalButtonMinClicked();
}
void LoginTitleBar::onButtonRestoreClicked()
{
m_pButtonRestore->setVisible(false);
m_pButtonMax->setVisible(true);
emit signalButtonRestoreClicked();
}
void LoginTitleBar::onButtonMaxClicked()
{
m_pButtonMax->setVisible(false);
m_pButtonRestore->setVisible(true);
emit signalButtonMaxClicked();
}
void LoginTitleBar::onButtonCloseClicked()
{
emit signalButtonCloseClicked();
}
// 该方法主要是让标题栏中的标题显示为滚动的效果;
void LoginTitleBar::onRollTitle()
{
static int nPos = 0;
QString titleContent = m_titleContent;
// 当截取的位置比字符串长时,从头开始;
if (nPos > titleContent.length())
nPos = 0;
m_pTitleContent->setText(titleContent.mid(nPos));
nPos++;
}
Login.h
#ifndef LOGIN_H
#define LOGIN_H
#include "LoginTitleBar.h"
#include <QDialog>
#include <QLineEdit>
#include <QMovie>
#include <QDesktopWidget>
#include <QGraphicsDropShadowEffect>
QT_BEGIN_NAMESPACE
namespace Ui { class Login; }
QT_END_NAMESPACE
//重写lineedit类
class LoginLineEdit : public QLineEdit
{
Q_OBJECT
public:
LoginLineEdit(QWidget* parent = NULL)
: QLineEdit(parent)
{
}
void setPlaceholderText(const QString &text)
{
m_placeHolderText = text;
QLineEdit::setPlaceholderText(text);
}
private:
void focusInEvent(QFocusEvent *event)
{
if (this->text().isEmpty())
{
QLineEdit::setPlaceholderText("");
}
emit signalIsMouseIn(true);
return QLineEdit::focusInEvent(event);
}
void focusOutEvent(QFocusEvent *event)
{
if (this->text().isEmpty())
{
this->setPlaceholderText(m_placeHolderText);
}
emit signalIsMouseIn(false);
return QLineEdit::focusOutEvent(event);
}
signals:
// 鼠标是否点击进行编辑;
void signalIsMouseIn(bool isFocusIn);
private:
QString m_placeHolderText;
};
class Login : public QDialog
{
Q_OBJECT
public:
Login(QWidget *parent = nullptr);
~Login();
private:
void initWidget(); //初始化界面
void initTitleBar(); //初始化窗口标题栏
void paintEvent(QPaintEvent *event);
private slots:
void onButtonMinClicked();
void onButtonCloseClicked();
private:
Ui::Login *ui;
LoginTitleBar *m_titleBar;
};
#endif // LOGIN_H
Login.cpp
#include "Login.h"
#include "ui_login.h"
Login::Login(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Login)
{
ui->setupUi(this);
// 设置窗口背景透明
this->setAttribute(Qt::WA_TranslucentBackground);
// FramelessWindowHint属性设置窗口去除边框;
// WindowMinimizeButtonHint 属性设置在窗口最小化时,点击任务栏窗口可以显示出原窗口;
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
// 注意!!!如果是主窗口不要设置WA_DeleteOnClose属性;
// 关闭窗口时释放资源;
setAttribute(Qt::WA_DeleteOnClose);
// 初始化标题栏和界面
initWidget();
initTitleBar();
//设置阴影边框;
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(this);
shadowEffect->setOffset(0, 0);
shadowEffect->setColor(Qt::black);
shadowEffect->setBlurRadius(10);
this->setGraphicsEffect(shadowEffect);
}
Login::~Login()
{
delete ui;
}
void Login::initWidget()
{
// 设置两个输入框前后的图标及按钮;
QLabel* m_labelUser = new QLabel;
m_labelUser->setFixedSize(QSize(20, 24));
m_labelUser->setPixmap(QIcon(":/Image/user.png").pixmap(m_labelUser->size()));
QLabel* m_labelPassWord = new QLabel;
m_labelPassWord->setFixedSize(QSize(26, 26));
m_labelPassWord->setPixmap(QIcon(":/Image/password.png").pixmap(m_labelPassWord->size()));
QPushButton* m_pButtonPullDown = new QPushButton;
m_pButtonPullDown->setCursor(Qt::ArrowCursor);
m_pButtonPullDown->setFixedSize(QSize(24, 24));
m_pButtonPullDown->setStyleSheet("QPushButton{border-image:url(:/Image/down.png);}\
QPushButton:hover{border-image:url(:/Image/down_hover.png);}");
QPushButton* m_pButtonKeyborad = new QPushButton;
m_pButtonKeyborad->setCursor(Qt::PointingHandCursor);
m_pButtonKeyborad->setFixedSize(QSize(24, 24));
m_pButtonKeyborad->setStyleSheet("QPushButton{border-image:url(:/Image/jianpan.png);}\
QPushButton:hover{border-image:url(:/Image/jianpan_hover.png);}\
QPushButton:pressed{border-image:url(:/Image/jianpan.png) 0 0 0 80;}");
ui->Btn_login->setStyleSheet("QPushButton{border-image:url(:/Image/login.png);}\
QPushButton:hover{border-image:url(:/Image/login_hover.png);}\
QPushButton:pressed{border-image:url(:/Image/login_pressed.png);}");
ui->lineEdit_Account->setPlaceholderText(QString::fromUtf8("请输入用户名"));
ui->lineEdit_Account->setTextMargins(25, 0, 25, 0);
// 这里通过signalIsMouseIn信号进行图标切换;
connect(ui->lineEdit_Account, &LoginLineEdit::signalIsMouseIn, this, [=](bool isMouseIn) {
if (isMouseIn)
{
m_labelUser->setPixmap(QIcon(":/Image/user_hover.png").pixmap(m_labelUser->size()));
}
else
{
m_labelUser->setPixmap(QIcon(":/Image/user.png").pixmap(m_labelUser->size()));
}
});
QHBoxLayout* hAccountLayout = new QHBoxLayout(ui->lineEdit_Account);
hAccountLayout->addWidget(m_labelUser);
hAccountLayout->addStretch();
hAccountLayout->addWidget(m_pButtonPullDown);
hAccountLayout->setMargin(0);
ui->lineEdit_PassWord->setPlaceholderText("密码");
ui->lineEdit_PassWord->setTextMargins(25, 0, 25, 0);
connect(ui->lineEdit_PassWord, &LoginLineEdit::signalIsMouseIn, this, [=](bool isMouseIn) {
if (isMouseIn)
{
m_labelPassWord->setPixmap(QIcon(":/Image/password_hover.png").pixmap(m_labelPassWord->size()));
}
else
{
m_labelPassWord->setPixmap(QIcon(":/Image/password.png").pixmap(m_labelPassWord->size()));
}
});
this->setStyleSheet("*{font-family:Microsoft YaHei;font-size:12px;}\
QLineEdit{font-size:20px;background:transparent;border:none;border-bottom:1px solid rgb(229, 229, 229);}\
QLineEdit:hover{border-bottom:1px solid rgb(193,193, 193);}\
QLineEdit:focus{border-bottom:1px solid rgb(18, 183, 245);}");
QHBoxLayout* hPswLayout = new QHBoxLayout(ui->lineEdit_PassWord);
hPswLayout->addWidget(m_labelPassWord);
hPswLayout->addStretch();
hPswLayout->addWidget(m_pButtonKeyborad);
hPswLayout->setMargin(0);
//背景GIF图;
QMovie *movie = new QMovie();
movie->setFileName(":/Image/GIF.gif");
ui->label->setMovie(movie);
movie->start();
QLabel *logo = new QLabel(this);
logo->setGeometry(QRect(0, 0, 540, 200));
logo->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
logo->setText("Title");
logo->setStyleSheet("background:transparent;font-size:36px;font:bold;color:white;");
logo->move(0, 0);
}
void Login::initTitleBar()
{
m_titleBar = new LoginTitleBar(this);
m_titleBar->move(6, 6);
connect(m_titleBar, SIGNAL(signalButtonMinClicked()), this, SLOT(onButtonMinClicked()));
connect(m_titleBar, SIGNAL(signalButtonCloseClicked()), this, SLOT(onButtonCloseClicked()));
m_titleBar->setButtonType(MIN_BUTTON);
m_titleBar->setWindowBorderWidth(12);
}
void Login::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPainterPath pathBack;
pathBack.setFillRule(Qt::WindingFill);
pathBack.addRoundedRect(QRect(6, 6, this->width() - 12, this->height() - 12), 6, 6);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.fillPath(pathBack, QBrush(QColor(225, 240, 245)));
return QWidget::paintEvent(event);
}
void Login::onButtonMinClicked()
{
showMinimized();
}
void Login::onButtonCloseClicked()
{
close();
}