三,左侧界面搭建
一,导入
先把MainWidget类做成“单例类”
采用的是单例模式,让某一个类,在指定进程中只有唯一的实例
先看一下MainWidget的框架
QWidget//这部分是头文件保护宏,确保该头文件只被包含一次,防止因重复包含导致的编译错误。
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
//引入 Qt 的 QWidget 类,这个类是所有用户界面对象的基类。
#include <QWidget>
//这段代码使用 Qt 的命名空间机制。
//它定义了一个名为 Ui 的命名空间,里面声明了一个名为 mainWidget 的类。
//这个类通常是通过 Qt Designer 生成的,用于管理 UI 元素。
QT_BEGIN_NAMESPACE
namespace Ui {
class mainWidget;
}
QT_END_NAMESPACE
//这里定义了一个名为 mainWidget 的类,它继承自 QWidget。Q_OBJECT
class mainWidget : public QWidget
{
Q_OBJECT
public:
mainWidget(QWidget *parent = nullptr);
~mainWidget();
private:
Ui::mainWidget *ui;
};
#endif // MAINWIDGET_H
//包含了之前定义的 mainWidget 类的头文件。
#include "mainwidget.h"
//包含了由 Qt Designer 生成的 UI 代码的头文件,通常负责设置 UI 元素。
#include "./ui_mainwidget.h"
//这行代码定义了一个静态指针成员变量 instance,初始化为 nullptr。这通常用于实现单例模式,确保 mainWidget 类只有一个实例
mainWidget* mainWidget::instance=nullptr;
//构造函数,接受一个可选的父窗口部件指针
mainWidget::mainWidget(QWidget *parent)
: QWidget(parent) //调用基类 QWidget 的构造函数,并将父部件传递给它
, ui(new Ui::mainWidget) //创建一个新的 Ui::mainWidget 对象,负责设置 UI。
{
ui->setupUi(this); //调用 setupUi 方法,将 UI 组件设置到当前 mainWidget 实例中
}
//析构函数
mainWidget::~mainWidget()
{
delete ui;
}
二,需求分析
三,代码书写
前置:设置图标,需要把图标图片,导入到项目中,通过qrc文件进行管理
在本章节大致使用了一下素材
素材网站:
https://www.aigei.com/
https://www.iconfont.cn/
一,mainWidget.h的编写
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui {
class mainWidget;
}
QT_END_NAMESPACE
class mainWidget : public QWidget
{
Q_OBJECT
private:
static mainWidget* instance;//指针指向当前的类的唯一实例
//静态指针,用于指向 mainWidget 类的唯一实例
//这是单例模式的核心,确保全局只存在一个 mainWidget 对象
//对于单例模式来说,最关键的部分,不是创建实例,而是限制别人创建实例
mainWidget(QWidget *parent = nullptr);
//他是私有的防止外部代码直接创建mainWidget实例
public:
static mainWidget* getInstance();//静态成员函数用于获取当前实例
~mainWidget();//析构函数
private:
Ui::mainWidget *ui;
//窗口最左侧部分
QWidget* windowLeft;
//窗口中间部分
QWidget* windowMid;
//窗口右侧部分
QWidget* windowRight;
//用户头像
QPushButton* userAvatar;
//会话标签页按钮
QPushButton* sessionTabBtn;
//好友标签页按钮
QPushButton* friendTabBtn;
//好友申请标签页按钮
QPushButton* applyTabBtn;
//枚举类型当前的激活的标签页是哪一个
enum ActiveTab{
SESSION_LIST,
FRIEND_LIST,
APPLY_LIST
};
ActiveTab activeTab=SESSION_LIST;//默认为会话列表
//初始化主窗口的样式布局
void initMainWindow();
//初始化左侧窗口布局
void initLeftWindow();
//初始化中间窗口布局
void initMidWindow();
//初始化右侧窗口布局
void initRightWindow();
//信号槽
void initSignalSlot();
//槽函数
void switchTabToSession();
void switchTabToFriend();
void switchTabToApply();
void loadSessionList();
void loadFriendList();
void loadApplyList();
};
#endif // MAINWIDGET_H
本头文件采用了单例模式
单例模式(Singleton Pattern)是一种设计模式,它确保一个类在程序运行期间只会创建一个实例,并且提供一个全局访问点。
到底此处的代码怎么实现的单例模式呢?
-
私有构造函数
-
静态实例指针
static mainWidget* instance;
-
静态访问接口
static mainWidget* getInstance();
回顾静态成员的特点
-
静态成员变量:属于类本身,而不是某个对象。所有类的实例共享同一个静态成员变量,它在程序运行时只会分配一块内存空间。
-
静态成员函数:同样属于类,而不是对象。它只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数(因为非静态成员是属于具体对象的)。
单例模式ABC详解
A.构造函数是私有的mainWidget(QWidget *parent = nullptr);
防止外部代码直接创建mainWidget实例
B.**static**
修饰的 **instance**
是一个静态成员变量,它属于 **mainWidget**
类本身,而不是某个特定的 mainWidget
对象.
程序整个周期只存在一份,所有访问mainWidget类的都共享一个instance指针,初始值为nullptr的时候说明还没有创建。
静态成员变量 instance
可以在 mainWidget
类的任何成员函数中访问,也可以通过 getInstance()
方法从类的外部访问。
C.提供对单例实例的访问
mainWidget* mainWidget::getInstance()
{
//此处不传入参数,以桌面为父窗口
//由于此时的窗口是整个程序的主窗口,父窗口就设定为桌面,本身就是常规设定。
if(instance==nullptr)
{
instance=new mainWidget();
}
return instance;
}
第一次调用 getInstance()
时,创建一个新的实例
第二次以后调用,直接返回instance实例;
二,逐步编写mainwidget.cpp
一,构造函数
mainWidget::mainWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::mainWidget)
{
ui->setupUi(this);
//this指向被构造的mainWidget
this->setWindowTitle("Pokemon聊天室");
this->setWindowIcon(QIcon(":/resource/image/logo.png"));
//初始化主窗口的样式布局
initMainWindow();
//初始化左侧窗口布局
initLeftWindow();
//初始化中间窗口布局
initMidWindow();
//初始化右侧窗口布局
initRightWindow();
//初始化信号槽
initSignalSlot();
}
二,initMainWindow初始化主窗口
void mainWidget::initMainWindow()
{
//创建一个水平布局管理器
QHBoxLayout* layout=new QHBoxLayout();
//处理间隔Spacing就是layout内部元素之间的间隔距离,设置为0就是紧紧挨着水平的紧紧挨着
layout->setSpacing(0);
this->setLayout(layout);//将 layout 设置为 mainWidget 窗口的布局管理器
//创建三个QWidget子部件
windowLeft=new QWidget();
windowMid=new QWidget();
windowRight=new QWidget();
//这三个部分马上添加到布局管理器中
//在设计界面的时候,会涉及到很多尺寸,间距,边框,字体相关细节。
windowLeft->setFixedWidth(60);//左侧导航栏为固定的70像素
windowMid->setFixedWidth(230);//中间
windowRight->setMinimumWidth(500);//右边聊天框 根据窗口自动化改变
//可以使用qq的截图来进行判定大小
//设计颜色qss
windowLeft->setStyleSheet("QWidget {background-color:rgb(23,23,23)}");//左侧导航栏为固定的70像素
windowMid->setStyleSheet("QWidget {background-color:rgb(46,46,46)}");
windowRight->setStyleSheet("QWidget {background-color:rgb(255,255,255)}");
//子窗口添加到布局管理器中
layout->addWidget(windowLeft);
layout->addWidget(windowMid);
layout->addWidget(windowRight);
}
三,initLeftWindow()
//H 代表 Horizontal(水平),V 代表 Vertical(垂直)
void mainWidget::initLeftWindow()
{
QVBoxLayout* layout =new QVBoxLayout();
layout->setSpacing(20);//设置按钮的间距
layout->setContentsMargins(0,70,0,0);//设置左上右下的间距
windowLeft->setLayout(layout);
//添加用户头像
userAvatar =new QPushButton();
userAvatar->setFixedSize(45,45);//按钮本身的尺寸
userAvatar->setIconSize(QSize(45,45));//按钮自身的尺寸
userAvatar->setIcon(QIcon(":/resource/image/userAvatar.jpg"));
userAvatar->setStyleSheet("QPushButton{ background-color:transparent;}");
layout->addWidget(userAvatar,1,Qt::AlignTop | Qt::AlignCenter);//1是占据空间的权重,靠上对齐,水平居中
layout->addStretch(5);//添加空白处
//添加会话标签按钮
sessionTabBtn=new QPushButton();
sessionTabBtn->setFixedSize(45,45);//按钮本身的尺寸
sessionTabBtn->setIconSize(QSize(45,45));//按钮自身的尺寸
sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
sessionTabBtn->setStyleSheet("QPushButton{ background-color:transparent;}");
layout->addWidget(sessionTabBtn,1,Qt::AlignTop | Qt::AlignCenter);
//添加好友标签页按钮
friendTabBtn=new QPushButton();
friendTabBtn->setFixedSize(45,45);//按钮本身的尺寸
friendTabBtn->setIconSize(QSize(45,45));//按钮自身的尺寸
friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
friendTabBtn->setStyleSheet("QPushButton{ background-color:transparent;}");
layout->addWidget(friendTabBtn,1,Qt::AlignTop | Qt::AlignCenter);
//添加好友申请标签页按钮
applyTabBtn=new QPushButton();
applyTabBtn->setFixedSize(45,45);//按钮本身的尺寸
applyTabBtn->setIconSize(QSize(45,45));//按钮自身的尺寸
applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
applyTabBtn->setStyleSheet("QPushButton{ background-color:transparent;}");
layout->addWidget(applyTabBtn,1,Qt::AlignTop | Qt::AlignCenter);;
layout->addStretch(20);//添加下面的空白处
//连接信号槽,处理标签页按钮切换的问题
}
四,initSignalSlot()
void mainWidget::initSignalSlot()
{
/
///连接信号槽,处理标签页按钮切换的问题
/
connect(sessionTabBtn,&QPushButton::clicked,this,&mainWidget::switchTabToSession);
//连接的信号来自sessionTabBtn这个指向 QPushButton 对象的指针
//&QPushButton::clicked 表示 QPushButton 类中的 clicked 信号,clicked 信号在 QPushButton 被点击时触发
//槽(slot)函数所属对象的指针,指的是 mainWidget 类的一个实例对象,槽函数是在当前对象(即 mainWidget 类的实例)中定义的
//最后一个位置是槽函数:每当 sessionTabBtn 发出 clicked 信号时,这个槽函数就会被调用
connect(friendTabBtn,&QPushButton::clicked,this,&mainWidget::switchTabToFriend);
connect(applyTabBtn,&QPushButton::clicked,this,&mainWidget::switchTabToApply);
}
addWidget的参数中1的作用
拉伸系数的作用:它决定了当布局空间发生变化(如窗口大小改变时),该部件在布局中占据的比例。如果拉伸系数为 1,那么它在布局中将获得与其他拉伸系数为 1 的部件相同的空间份额。如果拉伸系数为 0,则该部件的大小不会随布局的空间变化而变化(即固定大小)
五,槽函数
void mainWidget::switchTabToSession()
{
//1.记录当前切换到了哪一个标签页
activeTab=SESSION_LIST;
//2.调整当前图片显示情况,把会话的按钮图标设为active,另两个图标设为inactive
sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
//3.在主窗口中间部分,加载会话列表数据
this->loadSessionList();
}
void mainWidget::switchTabToFriend()
{
//1.记录当前切换到了哪一个标签页
activeTab=FRIEND_LIST;
//2.调整当前图片显示情况,把会话的按钮图标设为active,另两个图标设为inactive
sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
friendTabBtn->setIcon(QIcon(":/resource/image/friend_active.png"));
applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
//3.在主窗口中间部分,加载会话列表数据
this->loadFriendList();
}
void mainWidget::switchTabToApply()
{
//1.记录当前切换到了哪一个标签页
activeTab=APPLY_LIST;
//2.调整当前图片显示情况,把会话的按钮图标设为active,另两个图标设为inactive
sessionTabBtn->setIcon(QIcon(":/resource/image/session_inactive.png"));
friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
applyTabBtn->setIcon(QIcon(":/resource/image/apply_active.png"));
//3.在主窗口中间部分,加载会话列表数据
this->loadApplyList();
}