建立这个贴的目的是记录自己开发项目的过程,这个贴会一直持续到整个项目全部完成。
话不多说,先看结果。左边是腾讯QQ登录界面,右边是用Qt写的企业版QQ的登录界面,咋一看都差不多吧,但是仔细看还是有区别的。
我没有使用Qt的UI类,整个界面的效果和布局都是手写的。
头文件的内容:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow> // 主窗口
#include <QLabel> // 标签/面板
#include <QLineEdit> // 行输入框
#include <QRadioButton> // 单选按钮
#include <QPushButton> // 按钮
#include <QMouseEvent> // 鼠标事件
#include <QDebug>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
// 私有函数
private:
void InitSignWindow();
void UnInitSignWindow();
void InitSignWindwAssembly();
void InitSignWindowAssemblyEvent();
void signPushButtonStyle();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
// 私有变量
private:
QLabel *backgroundLabel; // 背景面板,用于存放其他组件
QPushButton *closePushButton;// 关闭按钮
QLabel *userLogoLabel;// 用户头像面板
QLineEdit *accountLineEdit;// 账号单行编辑框
QLineEdit *passwordLineEdit;// 密码单行编辑框
QRadioButton *agreementRadioButton;// 同意协议单选框
QPushButton *signPushButton;// 登录按钮
QPushButton *loginPushButton;// 注册按钮
QPushButton *forgetPushButton;// 注册按钮
QPushButton *clear1PushButton;// 清空按钮
QPushButton *clear2PushButton;// 清空按钮
QPushButton *historyPushButton;// 历史账号按钮
bool m_bDrag;
QPoint mouseStartPoint;
QPoint windowTopLeftPoint;
};
#endif // MAINWINDOW_H
CPP文件中主要是实现的流程:
1、设置窗口的相关属性
// 初始化登录窗口:设置窗口样式,并且初始化窗口组件
void MainWindow::InitSignWindow()
{
// 设置登录界面大小 320*450
setFixedSize(322,452);// 比实际大两个像素,为了呈现悬浮的效果
// 设置登录界面为无边框:方便设置自定义样式
setWindowFlags(Qt::FramelessWindowHint);
// 设置登录界面为透明色:方便做异形窗口
setAttribute(Qt::WA_TranslucentBackground);
// 设置任务栏图标
setWindowIcon(QIcon("../QQ_Test_Demo_Images/icon.png"));
// 初始化组件
InitSignWindwAssembly();
// 初始化事件
InitSignWindowAssemblyEvent();
}
这里面设置窗口无边框和透明的主要原因是方便把窗口设置成圆角以及设置自定义的边框。
2、初始化组件以及设置组件的相关属性
// 初始化登录窗口组件:创建其组件,并且设置组件的样式和位置
void MainWindow::InitSignWindwAssembly()
{
// 创建背景面板组件
backgroundLabel = new QLabel(this);
// 设置其背景面板的位置和大小
backgroundLabel->setGeometry(0,0,width(),height());
// 设置背景面板的背景图片和样式
backgroundLabel->setObjectName("backgroundLabel");
backgroundLabel->setStyleSheet(QString("#backgroundLabel{"
"border:1px solid #9FB1BC;"
"border-radius:10px;"
"border-image:url('../QQ_Test_Demo_Images/background.png')}"));
// 创建关闭按钮组件
closePushButton = new QPushButton(backgroundLabel);
closePushButton->setGeometry(width()-30,1,30,25);
closePushButton->setObjectName("closePushButton");
closePushButton->setText("×");
closePushButton->setStyleSheet(QString("#closePushButton{"
"border-top-right-radius:10px;"
"background:rgba(255,255,255,0);"
"font-size:18px;"
"color:#253237}"
"#closePushButton:hover{"
"background-color:#D90429;"
"font-size:18px;"
"color:#ffffff}"));
// 创建头像面板组件
userLogoLabel = new QLabel(backgroundLabel);
// 设置头像面板组件样式和位置
userLogoLabel->setGeometry(width()/2-40,65,80,80);
userLogoLabel->setObjectName("userLogoLabel");
userLogoLabel->setStyleSheet(QString("#userLogoLabel{"
"border:1px solid #7C7A7A;"
"border-radius:40px;"
"border-image:url('../QQ_Test_Demo_Images/userdefaultlogo.png');}"));
// 创建账号输入框组件
accountLineEdit = new QLineEdit(backgroundLabel);
// 设置账号输入框组件样式和位置
accountLineEdit->setGeometry(width()/2-128,userLogoLabel->y()+userLogoLabel->height()+21,256,45);
accountLineEdit->setObjectName("accountLineEdit");
accountLineEdit->setAlignment(Qt::AlignCenter); // 设置文本居中
accountLineEdit->setStyleSheet(QString("#accountLineEdit:focus{"
"border:none;"
"border-radius:5px;"
"font-size:25px;"
"background:rgba(255,255,250,240);"
"color:#353535;}"
"#accountLineEdit{"
"background:rgba(255,255,250,100);"
"border:none;"
"border-radius:5px;"
"font-size:16px;"
"}"));
accountLineEdit->setPlaceholderText("输入QQ号"); // 设置提示文本
// 创建清空按钮组件
clear1PushButton = new QPushButton(accountLineEdit);
clear1PushButton->setGeometry(accountLineEdit->width()-50,10,25,25);
clear1PushButton->setText("×");
clear1PushButton->setCursor(Qt::PointingHandCursor);
clear1PushButton->setObjectName("clearPushButton");
clear1PushButton->setStyleSheet(QString("#clearPushButton{"
"background:rgba(255,255,255,0);"
"outline:none;}"));
// 创建密码输入框组件
passwordLineEdit = new QLineEdit(backgroundLabel);
// 设置密码输入框组件样式和位置
passwordLineEdit->setEchoMode(QLineEdit::Password);
passwordLineEdit->setGeometry(width()/2-128,accountLineEdit->y()+accountLineEdit->height()+14,256,45);
passwordLineEdit->setObjectName("passwordLineEdit");
passwordLineEdit->setAlignment(Qt::AlignCenter); // 设置文本居中
passwordLineEdit->setStyleSheet(QString("#passwordLineEdit:focus{"
"border:none;"
"border-radius:5px;"
"font-size:25px;"
"background:rgba(255,255,250,240);"
"color:#353535;}"
"#passwordLineEdit{"
"background:rgba(255,255,250,100);"
"border:none;"
"border-radius:5px;"
"font-size:16px;"
"}"));
passwordLineEdit->setPlaceholderText("输入QQ密码"); // 设置提示文本
// 创建历史账号按钮组件
clear2PushButton = new QPushButton(passwordLineEdit);
clear2PushButton->setGeometry(passwordLineEdit->width()-50,10,25,25);
clear2PushButton->setText("×");
clear2PushButton->setCursor(Qt::PointingHandCursor);
clear2PushButton->setObjectName("historyPushButton");
clear2PushButton->setStyleSheet(QString("#historyPushButton{"
"background:rgba(255,255,255,0);}"));
// 创建同意协议单选框组件
agreementRadioButton = new QRadioButton(backgroundLabel);
// 设置同意协议单选框组件样式和位置
agreementRadioButton->setGeometry(width()/2-120,passwordLineEdit->y()+passwordLineEdit->height()+20,240,20);
agreementRadioButton->setText("已阅读并同意服务协议和QQ隐私保护");
agreementRadioButton->setObjectName("agreementRadioButton");
agreementRadioButton->setStyleSheet(QString("#agreementRadioButton{"
"color:#5C6B73;}"
"#agreementRadioButton::indicator{"
"width:15px;"
"height:15px;}"
"#agreementRadioButton::indicator::unchecked{"
"border-image:url('../QQ_Test_Demo_Images/radiouncheck.png');}"
"#agreementRadioButton::indicator::checked{"
"border-image:url('../QQ_Test_Demo_Images/radiocheck.png');}"));
signPushButton = new QPushButton(backgroundLabel);
signPushButton->setGeometry(width()/2-128,agreementRadioButton->y()+agreementRadioButton->height()+14,256,38);
signPushButton->setText("登录");
signPushButton->setDisabled(true);
signPushButton->setObjectName("signPushButton");
signPushButton->setStyleSheet(QString("#signPushButton{"
"background-color:#61a3d7;"
"color:#ffffff;"
"border:none;"
"font-size:15px;"
"border-radius:5px;}"));
loginPushButton = new QPushButton(backgroundLabel);
loginPushButton->setGeometry(width()/2-60,height()-32-20,50,20);
loginPushButton->setObjectName("loginPushButton");
loginPushButton->setText("注册账号");
loginPushButton->setCursor(Qt::PointingHandCursor);
loginPushButton->setStyleSheet(QString("#loginPushButton{"
"background-color:rgba(255,255,255,0);"
"color:#396f97;"
"border:none;"
"font-size:12px;}"));
forgetPushButton = new QPushButton(backgroundLabel);
forgetPushButton->setGeometry(width()/2+10,height()-32-20,50,20);
forgetPushButton->setObjectName("forgetPushButton");
forgetPushButton->setText("忘记密码");
forgetPushButton->setCursor(Qt::PointingHandCursor);
forgetPushButton->setStyleSheet(QString("#forgetPushButton{"
"background-color:rgba(255,255,255,0);"
"color:#396f97;"
"border:none;"
"font-size:12px;}"));
}
界面里面的组件样式全部是在这里面设置的。
3、初始化组件的槽函数,也就是设置一些组件的点击事件和其他事件
// 初始化登录窗口组件事件
void MainWindow::InitSignWindowAssemblyEvent()
{
// 设置关闭按钮事件
connect(closePushButton,SIGNAL(clicked()),this,SLOT(close()));
// 设置登录事件
connect(signPushButton,&QPushButton::clicked,this,[this]{
// 这里写登录请求
qDebug() << "开始请求登录...";
});
// 设置账号和密码输入框事件
connect(accountLineEdit,&QLineEdit::textChanged,this,[this](){
if(accountLineEdit->text().isEmpty() == false)
accountLineEdit->setStyleSheet(QString("#accountLineEdit{"
"border:none;"
"border-radius:5px;"
"font-size:20px;"
"background:rgba(255,255,250,240);"
"color:#353535;}"));
signPushButtonStyle();
});
connect(passwordLineEdit,&QLineEdit::textChanged,this,[this](){
if(passwordLineEdit->text().isEmpty() == false)
passwordLineEdit->setStyleSheet(QString("#passwordLineEdit{"
"border:none;"
"border-radius:5px;"
"font-size:20px;"
"background:rgba(255,255,250,240);"
"color:#353535;}"));
signPushButtonStyle();
});
// 设置清空事件
connect(clear1PushButton,&QPushButton::clicked,accountLineEdit,[this]{
// 这里写清空逻辑
accountLineEdit->clear();
signPushButtonStyle();
});
// 设置清空事件
connect(clear2PushButton,&QPushButton::clicked,passwordLineEdit,[this]{
// 这里写清空逻辑
passwordLineEdit->clear();
signPushButtonStyle();
});
// 设置注册事件
connect(loginPushButton,&QPushButton::clicked,this,[this]{
// 这里写注册逻辑
qDebug() << "跳转注册界面";
});
// 设置忘记密码事件
connect(forgetPushButton,&QPushButton::clicked,this,[this]{
// 这里写忘记密码逻辑
qDebug() << "跳转忘记密码界面";
});
// 设置同意协议事件
connect(agreementRadioButton,&QRadioButton::clicked,signPushButton,[this](){
signPushButtonStyle();
});
}
在这个里面有些事件是为了实现一些界面上的操作效果实现的。
当然还预留了后面需要用到的事件操作,如:登录,注册等,后面再实现。
为了整个界面的效果和原版大差不差,我还特地定义了一个函数来切换登录按钮的效果
// 设置登录按钮样式
void MainWindow::signPushButtonStyle()
{
bool state = false;
// 协议点击逻辑
if(agreementRadioButton->isChecked() == true
&& (accountLineEdit->text().isEmpty() == false)
&& (passwordLineEdit->text().isEmpty() == false))
state =true;
if(state)
{
// 重新配置样式
signPushButton->setStyleSheet(QString("#signPushButton{"
"background-color:#00A8E8;"
"color:#ffffff;"
"border:none;"
"font-size:15px;"
"border-radius:5px;}"
"#signPushButton:hover{"
"background-color:#1B98E0;}"));
signPushButton->setDisabled(false);
}
else
{
signPushButton->setStyleSheet(QString("#signPushButton{"
"background-color:#61a3d7;"
"color:#ffffff;"
"border:none;"
"font-size:15px;"
"border-radius:5px;}"));
signPushButton->setDisabled(true);
}
}
4、设置鼠标的拖动效果
因为我们把窗口设置成了无边框的样式,我们没有办法直接拖动界面了。所以要自己写一个拖动窗口的操作。
// 鼠标按下事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
// 判断鼠标是否按下左键了
if(event->button() == Qt::LeftButton)
{
// 获取鼠标位置
m_bDrag = true;
//获得鼠标的初始位置
mouseStartPoint = event->globalPos();
//mouseStartPoint = event->pos();
//获得窗口的初始位置
windowTopLeftPoint = this->frameGeometry().topLeft();
}
}
// 鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(m_bDrag)
{
//获得鼠标移动的距离
QPoint distance = event->globalPos() - mouseStartPoint;
//改变窗口的位置
this->move(windowTopLeftPoint + distance);
}
}
// 鼠标松开事件
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
m_bDrag = false;
}
}
到此整个QQ的登录界面就算是完成了。整个界面的效果和原版来说是差不多的。可能还存在一些其他的问题,后期再一起修改了。
那就等下一个界面出来再见了。
---------------------------------------------------------------------------------------------------------------------------------
这个项目要烂尾了o(╥﹏╥)o。前面清理磁盘,一不小心给源文件删除了。没有任何备份。心凉透了~