当前位置: 首页 > news >正文

C++(week16): C++提高:(六) Qt提高

文章目录

  • 四、Qt的元对象系统
    • 1.元对象和MOC
      • (1)自省 和 反射
      • (2)Qt是怎样支持元对象系统的?
      • (3)支持元对象系统的三个要求
      • (4)元对象系统的功能
      • (5)动态属性
    • 2.信号和槽机制
      • (1)信号与槽机制的基本原理
      • (2)自定义信号、自定义槽函数
        • ①自定义信号
        • ②自定义槽
        • 关联 connect
      • (3)信号与槽的特点
        • ①槽函数的调用是同步的
        • 让信号携带参数
        • 处理重载的函数:qOverload
        • 如果重复connect
        • 交换信号和槽的地位
      • (4)减少重复槽函数
      • (5)信号与槽的优缺点:信号槽 vs 回调
    • 3.对象树
      • (1)基础复习:四种指针
      • (2)依赖注入
      • (3)组合模式
      • (4)Qt中的内存申请
    • 4.事件系统
      • (1)事件和事件循环
      • (2)事件到达,处理事件的三个步骤
        • ①事件过滤器
        • ②event函数
        • ③事件处理函数 event handler
          • 同时使用event和event handler
          • 人造按钮
          • 同时使用event filter、event、event handler
      • (3)多个对象之间的事件传递
        • 事件传递的过程
        • 事件系统 + 信号槽,让两个组件互动
  • 五、Qt_Widgets模块
    • 1.QWidget类的概念
      • paintEvent
      • 小项目3:打蚊子
    • 2.窗口
      • (1)定义
      • (2)成为窗口的条件
      • (3)QWidget当中和窗口相关的属性和方法
    • 3.对话框 QDialog
      • (1)模态
      • (2)自定义方式
      • (3)子类:标准对话框
        • ①QColorDialog:颜色选择对话框
        • QFileDialog:文件选择对话框
        • ③QFontDialog:字体选择对话框
        • ④QMessageBox:信息框
    • 4.主窗口 QMainWindow
      • (1)菜单栏:QMenubar
      • (2)工具栏:QToolbar
      • (3)状态栏:QStatusBar
    • 5.常见的简单组件
      • (1)用来显示的组件:Display Widgets
        • Label
      • (2)Buttons:按钮
      • (3)QComboBox:下拉框
      • (4)QLineEdit:单行输入
      • (5)容器:containers
    • 6.组合组件和界面布局
      • (1)布局
    • 7.model/view模型:MVC模型
      • (1)如何描述一个复杂的界面:分层
      • (2)Qt中的MVC:model/view architecture
        • ①model
        • ②view 视图
        • 使用model和view
  • 六、Qt的其他模块
    • 1.QTimer 定时器
    • 2.Qt文件操作:文件IO
    • 3.Qt网络编程:网络IO
    • 4.Qt多线程

四、Qt的元对象系统

为了实现信号槽 (目的),所以才设计了元对象系统 (手段)。

元数据:不是对象本身的主要内容,而是对象的额外信息(如文件名、文件路径、修改时间)。

元对象系统(Meta-Object System,简称MOS)是一种编程语言特性,用于支持反射(reflection)和元编程(metaprogramming)。它允许程序在运行时获取关于自身结构和行为的信息,甚至能够动态地修改自己的结构和行为。

在这里插入图片描述


1.元对象和MOC

元对象:保存了对象的额外信息。额外分配了内存。
在这里插入图片描述


(1)自省 和 反射

1.自省
在这里插入图片描述

2.反射
反射:为了实现间接访问。运行时,传入字符串,根据字符串调用函数。
反射:在运行时,可以获取并修改对象的结构


(2)Qt是怎样支持元对象系统的?

标准C++不支持元对象

MOC:元对象编译。

Qt需要两次编译:先

在这里插入图片描述


(3)支持元对象系统的三个要求

1.继承QObject类,且将QObject作为继承的第一个基类。 以确保内存位置是在第一个。
2.使用Q_OBJECT宏 (Q_OBJECT宏添加了一些函数的定义)
在这里插入图片描述

3.使用元对象的类,需要单独使用一个头文件,不能放在main.cpp中
在这里插入图片描述

在这里插入图片描述


(4)元对象系统的功能

1.支持反射,运行时获取和调整对象的结构
2.信号和槽
3.运行时类型转换
4.对象树


(5)动态属性

反射带来的好处:反射没有带来效率,但带来了更好的灵活性、可维护性。 lose函数不需要修改。
可以在运行的过程中,动态地修改。

在这里插入图片描述

反射在工作中的应用场景:
(1)游戏开发:导表工具,转化为python或lua代码
(2)互联网开发:路径路由,根据服务器网页路径调用不同的函数


2.信号和槽机制

信号和槽机制的目的:真正实现对象间的通信。并且是松耦合

通过connect函数实现耦合。slots、signals、emit是Qt的伪关键字,会通过MOC编译转换为标准C++。
而面向对象的标准C++,实现对象间通信的方式还是函数调用:直接调用 或 回调函数。


(1)信号与槽机制的基本原理

一读一写的流式通信很痛苦,收发错位就有bug。想办法把发和收封装为原子操作。

在这里插入图片描述
HTTP协议把四步合为一个事务。发明者参考了函数调用。
在这里插入图片描述

A与B之间进行通信
在这里插入图片描述
当B的数量很多的时候,这样写起来并不优雅。
在这里插入图片描述
在这里插入图片描述


A执行发送信息的代码,不要出现任何B的信息。

发送方,发射信号。接收方,调用槽函数。


(2)自定义信号、自定义槽函数

总结:回调函数、观察者模式

A发,B收
自定义信号、自定义槽、在发射信号之前关联信号和槽

①自定义信号
//自定义信号
signals:  void signalA();  

(1)signals:Qt的伪关键字
(2)自定义信号的设计,就是一个普通的成员函数声明
①放在signals访问权限控制符下面
②返回值必须是void
③只写声明不写定义,信号函数的定义由MOC自动添加


②自定义槽
//自定义槽函数
public slots:void slotsB();void slotB1(int i);void slotB2(int i, int j);

(1)槽函数的访问权限控制符 public/protected/private slots
(2)槽函数的书写和普通的成员函数没有任何区别
(3)槽函数的参数和返回值应当和信号保持一致。槽函数的参数个数必须小于等于信号的参数个数,否则会报错。用SIGNAL宏关联会在运行阶段报错,用指向成员函数的指针关联会在编译阶段报错。


关联 connect

connect的两种重载形式:
1.字符串:SIGNAL宏、SLOT宏

QObject::connect(&a, SIGNAL(signalA()), &b, SLOT(slotB()));

SIGNAL():把函数名变为字符串
SLOT():把槽函数变为字符串。


2.指向成员函数的指针

QObject::connect(&a, &A::signalA, &b, &B::slotB);

第二种更好。
因为,当槽函数的参数个数大于信号的参数个数时,会报错。
第一种会在运行阶段才报错。第二种在编译阶段就报错。
当然是报错越早越好,所以第二种connect好。


3.第三种重载形式:没有接收者。三个参数是函数对象,不用继承。适合简单功能。
在这里插入图片描述

QObject::connect(ui->pushButton, &QPushButton::clicked,[=](){ui->label->setText("world");});

connect相当于在发送方和接收方之间建立了一条通信的信道。
多次connect不会去重。
发射信号,关联的槽函数会自动调用。是同步的。


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


// 字符串形参
[static] QMetaObject::Connection QObject::connect(const QObject *sender, const
char *signal, const QObject *receiver, const char *method, Qt::ConnectionType
type = Qt::AutoConnection)// 没有接收者的版本
[static] QMetaObject::Connection QObject::connect(const QObject *sender,
PointerToMemberFunction signal, Functor functor)// 函数指针形参
[static] QMetaObject::Connection QObject::connect(const QObject *sender,
PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction
method, Qt::ConnectionType type)

第一种重载形式
在这里插入图片描述

SIGNAL():把函数名变为字符串
SLOT():把槽函数变为字符串。


connect的另一种重载形式:指向成员函数的指针
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


(3)信号与槽的特点

Qt万能头文件

#include <QtWidgets/QtWidgets>

①槽函数的调用是同步的

槽函数的调用是同步的。emit 信号要等对应的槽函数执行完毕后才能返回。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


让信号携带参数

信号的参数个数要大于等于槽函数的参数个数
最好,信号的参数和槽一致。

指向成员函数的指针 (C++11)。报错在编译阶段。
SIGNAL宏和SLOT宏,报错在运行阶段。
在这里插入图片描述

处理重载的函数:qOverload

在这里插入图片描述
在这里插入图片描述


如果重复connect

connect几次,发射一次就会执行几次槽函数。
即:一次信号,多个槽函数执行。(即使绑定的完全一致)

connect是建立一条连接。

在这里插入图片描述

在这里插入图片描述
应该是可以链式调用。在槽函数中也可以发射新的信号


交换信号和槽的地位

1.槽不能当信号使用。但是槽函数里面可以发射信号。
2.信号可以当槽用。
在这里插入图片描述


支持元对象系统的类的定义
在这里插入图片描述

A信号发射,导致B信号发射,导致C的槽函数执行。链式调用。
在这里插入图片描述


不要循环关联,会栈溢出。
在这里插入图片描述


(4)减少重复槽函数

1.自定义信号,让其有参数


2.自定义槽函数,并在其中获取发射方的信息:sender() + qobject_cast
(1)用sender()获取发射信号对象的地址 QObject *
sender只能在槽函数中调用。

[protected] QObject *QObject::sender() const
//Returns a pointer to the object that sent the signal, if called in a slot activated by a signal

(2)用qobject_cast<>QObject * 向下转型为 自己需要的对应组件的指针,如QPushButtton *
【元对象系统的安全向下转型(基类指针转为派生类指针,如QObject *QPushButton*)】

//QObject *向下转型为QPushButton *
QPushButton * pbtn = qobject_cast<QPushButton *> (sender()); 

举例:

///mainwindow.h
private slots://自定义槽函数void do_btn_clicked();
//mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{ui->setupUi(this);  //setUi是创建窗口中的组件。在这之后才能进行connect关联//多个信号,关联一个槽函数QObject::connect(ui->btn1,&QPushButton::clicked,this,&MainWindow::do_btn_clicked);QObject::connect(ui->btn2,&QPushButton::clicked,this,&MainWindow::do_btn_clicked);QObject::connect(ui->btn3,&QPushButton::clicked,this,&MainWindow::do_btn_clicked);
}void MainWindow::do_btn_clicked()
{//具体实现
}

(5)信号与槽的优缺点:信号槽 vs 回调

1.优点
(1)松耦合:把发送方和接收方在代码层面上分开了。
在发送方的代码片段中,没有出现任何接收方的信息【信号槽适合复杂的场景,回调适合性能要求高的场景】
(2)类型安全:connect会检查信号的参数个数要大于等于槽的参数个数
(3)关联自由:信号可以当槽用;槽不能当信号用,但可以在槽函数体中发射信号
(4)生态好:有很多Qt框架自带的信号和槽


2.缺点
性能差。信号槽的时间开销是10倍非虚函数。【但是也就是几纳秒慢到了几十纳秒。比起IO的几十毫秒还是可以忽略的。在IO密集型的场景,可以接受。在CPU密集型场景可能不能接受,如金融量化】


3.对象树

对象树系统,为了内存管理
内存管理:标准C++用的是RAII,Qt用的是对象树。

所有对象之间构成树状关系。父节点被销毁,孩子结点被自动回收。

在这里插入图片描述


(1)基础复习:四种指针

对象如果一直存在,可以用引用。引用不能改变指向,指针可以改变指向
对象一开始有可能不存在,用指针。
负责创建和销毁:用智能指针。
所有权独享:unique_ptr,且效率高。共享所有权,shared_ptr (效率略低,因为有引用计数)。

在这里插入图片描述


(2)依赖注入

一种比较好的编程方式:依赖注入
(1)以前,A构造时,在初始化列表中构造B。耦合性太高。两者
(2)现在,用setB中才构造B。后面才注入依赖关系。(避免一个构造函数失败导致整体构造失败)

在这里插入图片描述


(3)组合模式

组合模式也是一种设计模式。

1.定义:
(1)所有的对象构成树结构
(2)树中的结点应该拥有公共的类型


2.好处
写一个函数,既可以适用于整棵大树,也可小树、叶子结点

3.适用场景
(1)不适合适用组合模式的场景
叶子和非叶子没有公共的类型
在这里插入图片描述

(2)适合适用组合模式的场景
目录也可以当作目录文件。叶子和非叶子有着公共类型。
公共的基类,用容器保存 vector<Base *>
在这里插入图片描述


4.对象树使用了组合模式
(1)对象树是一个树形结构
(2)对象树中的所有对象都是QObject的子类

在这里插入图片描述


(4)Qt中的内存申请

1.根结点申请在栈上
2.所有的孩子结点可以(最好)申请在堆上。
堆上的数据不需要delete,父结点析构时会自动调用子节点的析构函数。
在这里插入图片描述


4.事件系统

信号与槽:对象间通信
事件系统:外界和进程通信

在这里插入图片描述


(1)事件和事件循环

1.事件:外界发生了事情,某个fd就绪了

while(1){select/epoll_wait();switch(fd){case fd: call event_handler();...		}
}

2.事件的细节
(1)硬件:硬件产生
(2)操作系统:操作系统采集,原生窗口事件,分配给事件队列
(3)进程:Qt进程一直在执行事件循环,如果有事件到来,相当于文件描述符就绪。将原生窗口事件封装为QEvent,发送给具体的QObjet对象
(4)对象:某个QObject对象收到事件后:先eventfilter,再event,再event handler。若event handler未处理完,再交给对象树上的父亲。
在这里插入图片描述

3.QObject收到事件后:
立即调用QObject::event(),将对应的事件分配给对应的event handlers。(底层就是分支结构,switch case 或 if else,根据事件的不同,调用不同的event handlers)

在这里插入图片描述


(2)事件到达,处理事件的三个步骤

(1)event filter:事件过滤器。
①在不继承的情况下,依然可以添加事件处理的能力。
②制作一个过滤器。继承QObject,再重写eventFilter函数。
③安装过滤器到对象上面。installEventFilter。
(2)event:事件分配。继承并重写event函数,调用基类的event函数(做了switch分配,否则不执行hanler)
(3)event handler:事件处理函数。继承并重写handler。


①事件过滤器

1.定义
事件过滤器:简化事件处理的代码。在不继承的情况下,给对象增加事件处理的能力。

void installEventFilter(QObject *filterObj);

2.实现事件过滤器
写一个过滤器类,继承QObject,重写 eventFilter()

[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)//Filters events if this object has been installed as an event filter for the watched object.
class MyFilter : public QObject
{Q_OBJECT
public:explicit MyFilter(QObject *parent = nullptr);bool eventFilter(QObject *watched, QEvent *ev) override{if(ev->type() == QEvent::MouseButtonPress){qDebug() << watched << "is pressed!";}return false;}
signals:};

每个对象安装事件过滤器

filter = new MyFilter(this);
out->installEventFilter(filter);
mid->installEventFilter(filter);
in->installEventFilter(filter);

3.事件过滤器和事件处理器同时存在:
先event filter,再event,最后event handler。若三者都没有处理完,则交给父亲处理。
父亲亦是event filter、event、event handler的顺序进行处理。


4.若安装了多个过滤器,则倒序生效。最后安装的过滤器先生效。


②event函数

4.派生类中,调用基类的虚函数
在这里插入图片描述

自定义事件处理函数
在这里插入图片描述

坏处是:修改event()可能会对多个事件造成影响,不推荐。


③事件处理函数 event handler

1.event之后,再调用 event handler
2.eventhandler 不是一个函数,而是一堆函数
3.不同类型的事件对应不同的event handler。只修改一个event handler不会影响其他事件。(而修改event函数可能影响其他很多事件)


同时使用event和event handler

event handler 要求调用基类的event()
在这里插入图片描述


人造按钮

QLabel : 继承 + 重写

在这里插入图片描述
在这里插入图片描述


同时使用event filter、event、event handler

代码链接:


(3)多个对象之间的事件传递

(4)事件的传递:当某个对象没有把事件处理完,事件就传递给它对象树上的父亲。
①event filter返回false
②event 返回false
③event handler调用ignore

在这里插入图片描述

move是自己的左上顶点和父亲的左上顶点的距离。
在这里插入图片描述


event()的返回值bool,代表本对象是否完成了该事件的处理。
只要有event handler,就说明事件可以完成了,不必往上传递。
但如果event handler中有调用ignore(),事件就是未完成的,还需要向上传递。

在这里插入图片描述


事件传递的过程

1.鼠标事件先传给离用户最近的对象(z轴)
键盘事件会发给焦点所在的对象

2.对象处理事件:先event(),后event_handler()
(1)event:return true,说明处理完毕,不会调用handler,也不会传给(对象树上的)父亲
(2)event:return false,未处理完毕,不会调用handler,直接传递给父亲
(3)event:调用了基类的event。
①如果handler不存在,会传递给父亲。
②如果handler存在 / accept,不传递给父亲。
③如果handler存在 / ignore,传递给父亲。


事件系统 + 信号槽,让两个组件互动

在这里插入图片描述



五、Qt_Widgets模块

1.QWidget类的概念

1.QWidget类看得见(其上可以绘制图案,支持绘图事件)、摸得着(支持键盘鼠标事件)的组件,是一个ui元素。本质是一个矩形画布。


2.功能:容器、输入内容、显示内容
在这里插入图片描述


3.QWidget的继承关系
本质:QWidget继承:
(1)继承QObject:支持元对象系统、信号和槽、对象树
(2)QPaintDevice:画布、矩形。看得见(使用paintEvent绘制),摸得着(可以响应键鼠事件)。

class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice

4.孩子需要比父亲小,且在父亲的范围之内。否则显示不全或无法显示。

在这里插入图片描述


paintEvent

2.paintEvent是绘图事件的event handler

在这里插入图片描述

void paintEvent(QPaintEvent *event) override{qDebug() << mosquito_x << "," << mosquito_y;QPainter painter(this);  //构造画笔QPixmap pixmap(":/new/prefix1/mosquito.jpeg");   //加载图片到内存painter.drawPixmap(mosquito_x, mosquito_y, 40, 40, pixmap);  //绘图:坐标,大小,图QWidget::paintEvent(event);  //调用基类的paintEvent,以免漏掉事件
}

小项目3:打蚊子

代码链接:https://github.com/WangEdward1027/Qt/tree/main/kill_mosquitoes

两种方案:
1.QLabel:Label的Pixmap中放蚊子,每次点击移动Label
2.PaintEvent:每次点击事件,event handler之paintEvent临时重绘一次文字图片加载到新的位置。


重写了两个event handler

class MyWidget : public QWidget
{Q_OBJECT
public:explicit MyWidget(QWidget *parent = nullptr);void mousePressEvent(QMouseEvent *event) override{//srand(time(nullptr));if(event->x() - mosquito_x <= 40 && event->x() - mosquito_x >= 0&& event->y() - mosquito_y <= 40 && event->y() - mosquito_y >= 0){emit addPoint();mosquito_x = rand()%560;mosquito_y = rand()%360;update(); // 强制重绘}QWidget::mousePressEvent(event);}void paintEvent(QPaintEvent *event) override{qDebug() << mosquito_x << "," << mosquito_y;QPainter painter(this);QPixmap pixmap(":/new/prefix1/mosquito.jpeg");painter.drawPixmap(mosquito_x,mosquito_y,40,40,pixmap);QWidget::paintEvent(event);}
signals:void addPoint();
private:int mosquito_x;int mosquito_y;
};

2.窗口

(1)定义

没有嵌入到父组件中的组件被称为窗口。
窗口是最大的容器。


(2)成为窗口的条件

(1)没有父节点,调用show()
(2)有父节点,Qt::Window
(3)QDialog、QMainWindow及其子类


如果一个QWidget对象是根结点(没有父结点),调用show方法,则是独立的窗口。任务栏会有两个窗口。

QWidget w1;
QWidget w2;
w1.show();
w2.show();

如果QWidget对象有父亲,则不会是独立窗口,会显示在父窗口里面。

QWidget w1;
QWidget *w2 = new QWidget(&w1);
w1.show();
w2->show();

3.有父亲的QWidget对象,也可以是一个窗口。但任务栏只有一个图标。
父亲窗口销毁,则会将孩子窗口也销毁。

QWidget w1;
QWidget *w2 = new QWidget(&w1, Qt::Window);
w1.show();
w2->show();

4.无边框窗口

QWidget w1;
QWidget *w2 = new QWidget(&w1, Qt::Window | Qt::FramelessWindowHint);
w1.show();
w2->show();

(3)QWidget当中和窗口相关的属性和方法

一、窗口
1.窗口功能:①sho() ②hide(),隐藏为后台进程
2.顶层窗口:最大化、最小化 showMinimized、全屏显示、正常显示
3.窗口内容:update():相当于手动触发绘制事件 (强制重绘)
在这里插入图片描述


二、几何位置、大小
1.move():移动位置
2.resize():改变大小

在这里插入图片描述
在这里插入图片描述


3.对话框 QDialog

QDialog和QMainWindow以及它们的子类对象一定是窗口。

QWidget w1;
QMainWindow *w2 = new QMainWindow(&w1);
QDialog *w3 = new QDialog(&w1);

(1)模态

1.非模态对话框
用show()方法展示。上层的对话框没有退出,不会阻塞整个进程。

2.模态对话框
用exec()。上层的对话框没有退出,会阻塞整个进程。

在这里插入图片描述


QDialog一般不好用。可以选择继承QDialog
(1)ui文件
(2)标准对话

下文介绍


(2)自定义方式

addNew,设计师界面类。
在这里插入图片描述


(3)子类:标准对话框

在这里插入图片描述


①QColorDialog:颜色选择对话框

用其静态成员函数:getColor()。临时生成。
若要经常使用,还是要构建。
在这里插入图片描述


QFileDialog:文件选择对话框

获取文件路径

QString filepath = QFileDialog::getOpenFileName();
qDebug() << filepath;
QString filepath = QFileDialog::getOpenFileName(this, "title", QStrng(),"source code (*.c *.cc *.cp);; header file(*.h)");
qDebug() << filepath;
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"/home",tr("Images (*.png *.xpm *.jpg)"));

文件选择对话框
在这里插入图片描述


③QFontDialog:字体选择对话框

静态函数
在这里插入图片描述


④QMessageBox:信息框

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


4.主窗口 QMainWindow

标题栏、菜单栏、工具栏、中央区域、状态栏

主窗口比一般窗口多出的部分:菜单栏、工具栏、状态栏
在这里插入图片描述


(1)菜单栏:QMenubar

1.组成
菜单栏QMenubar由一个个菜单QMenu组成。
菜单由QAction组成。

在这里插入图片描述

2.QAction的信号,是triggered()

用ActionEditor进行编辑
在这里插入图片描述


3.QAction和QPushButton的区别:
QActon是一个动作,QPushButton是一个实体
同一个QAction可以出现在不同的位置(菜单栏和工具栏),而QPushButton只能出现在一个位置
【ui编辑器中的Action编辑器】


(2)工具栏:QToolbar

在这里插入图片描述

加入icon


(3)状态栏:QStatusBar


5.常见的简单组件

(1)用来显示的组件:Display Widgets

在这里插入图片描述


Label

QLabel -> QFrame(设置边框) -> Widget

1.设置边框
在这里插入图片描述
在这里插入图片描述


2.Label显示markdown格式的数据
在这里插入图片描述
在这里插入图片描述


(2)Buttons:按钮

在这里插入图片描述

①QPush Button:文字,clicked()
②QTool Button:图像,clicked()
③QRadio Buttion:单选 (同一容器中的多个Radio Buttion只能有一个被选中),toggled(bool)
④QCheck Box:复选,clicked(bool)

在这里插入图片描述
在这里插入图片描述


按钮的信号:
在这里插入图片描述

在这里插入图片描述


在centralwidget中加新的widget作为容器
在这里插入图片描述


(3)QComboBox:下拉框

#include <QComboBox>QComboBox *comboBox = new QComboBox(&w);

在这里插入图片描述

加选项
在这里插入图片描述
在这里插入图片描述

信号
在这里插入图片描述

处理重载:QOverload<>
在这里插入图片描述

设置为可编辑
在这里插入图片描述

限制用户的输入:验证器
在这里插入图片描述
在这里插入图片描述

举例:Int

#include <QIntValidator>

在这里插入图片描述

但有漏洞
在这里插入图片描述

再加强,精确验证:validator->validate()
在这里插入图片描述


(4)QLineEdit:单行输入

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

分别对应推荐和搜索

在这里插入图片描述


(5)容器:containers

容器:一个QWidget,它的对象树中的孩子是其他ui元素

带边框的容器:QGroupBox
在这里插入图片描述


6.组合组件和界面布局

(1)布局

1.定义
布局:容器里面的元素的大小位置会随着容器大小的改变而自动改变


2.分类
水平布局、垂直布局、栅格布局
在这里插入图片描述

在这里插入图片描述


3.布局的使用
(1)先创建容器和里面的元素 【给容器、元素、布局 申请内存】
(2)创建布局:new QHBoxLayout / QVBoxLayout / QGridLayout
(3)把元素加入到布局当中:addWidget
(4)把布局设置为容器的属性:setLayout
在这里插入图片描述

栅格布局:addWidget有两种重载形式。可以占多行 (2,2,4,4)

在这里插入图片描述


4.弹簧:Spacer
在这里插入图片描述
在这里插入图片描述


7.model/view模型:MVC模型

模型-视图-控制器(MVC)是一种设计模式,在构建用户界面时经常使用。

MVC由三种对象组成:
①Mode l模型:应用对象,是一个抽象的数据结构,用户无法感知
②View 视图:屏幕表示,是用户看到的界面。
③Controller 控制器:定义了用户界面对用户输入的反应。用户编辑,直接修改了model

在MVC出现之前,用户界面设计往往倾向于将这些对象合并在一起。MVC将它们解耦以增加灵活性和重用性。并降低人思考的复杂度


(1)如何描述一个复杂的界面:分层

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

为MVC提出了23种设计模式。
数据变了,视图跟着变。就是观察者模式。


(2)Qt中的MVC:model/view architecture

Qt简化了mvc,控制器controller不是常驻的,而是用户交互时临时生成,称为委托delegate


①model

model是抽象的数据结构,如:①一维数组 ②二维表格 ③树

项item:二维表格的每一个格子称为项,每个项的孩子还是一个二维表格。这样的数据结构称为表格树
在这里插入图片描述


常见的三种模型:对表格树进行限制:①每一个item不准有孩子 ②item只有一列
(1)List Model (线性表):①②
(2)Table Model (二维数组,表格):①
(3)Tree Model (树):②
在这里插入图片描述


model的具体类型:
QAbstractItemModel (所有模型的抽象基类,表格树),加限制后退化为QAbstractItemModel、QAbstractTableModel
在这里插入图片描述
在这里插入图片描述


②view 视图

用户可以看见view。
用户操作view时,会临时生成一个controller,称为委托 Delegate。

在这里插入图片描述


QAbstractItemView
在这里插入图片描述


使用model和view

1.创建model view
2.根据model设置view
3.model进行增删改,view会自动跟着变


在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


model变了,view自动跟着变

初始化

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//modelmodel = new QStandardItemModel(2, 5, this);//viewview = new QTableView(this);view->setModel(model);  //接下来,view的内容,由model决定btn = new QPushButton("add row", this);layout = new QHBoxLayout;layout->addWidget(view);layout->addWidget(btn);ui->centralwidget->setLayout(layout);QStringList headers = {"birth", "name", "age", "job", "image"};model->setHorizontalHeaderLabels(headers);//第一行QStandardItem *birth= new QStandardItem("1027");QStandardItem *name = new QStandardItem("Edward");QStandardItem *age = new QStandardItem("25");QStandardItem *job = new QStandardItem("Research & Development");QStandardItem *image = new QStandardItem(QIcon(":/new/prefix1/images/photo1.jpg"), "pthot1");model->setItem(0, 0, birth);model->setItem(0, 1, name);model->setItem(0, 2, age);model->setItem(0, 3, job);model->setItem(0, 4, image);//第二行birth = new QStandardItem("1202");name = new QStandardItem("Amber");age = new QStandardItem("25");job = new QStandardItem("Product Manager");image = new QStandardItem(QIcon(":/new/prefix1/images/photo2.jpg"), "photo2");model->setItem(1, 0, birth);model->setItem(1, 1, name);model->setItem(1, 2, age);model->setItem(1, 3, job);model->setItem(1, 4, image);QObject::connect(btn ,&QPushButton::clicked, this, &MainWindow::addRow);
}

点击按钮的槽函数

void MainWindow::addRow()
{QStandardItem *birth = new QStandardItem("0811");QStandardItem *name = new QStandardItem("Sam");QStandardItem *age = new QStandardItem("25");QStandardItem *job = new QStandardItem("Quality Assurance");QStandardItem *image = new QStandardItem(QIcon(":/new/prefix1/images/photo3.jpg"),"photo3");QList<QStandardItem *> list;list << birth << name << age << job << image;model->appendRow(list);
}

效果:
在这里插入图片描述



六、Qt的其他模块

1.QTimer 定时器

1.QTimer的函数接口 (F1查看帮助手册)

//Public Functions
QTimer(QObject *parent = nullptr); //构造函数void setInterval(int msec);  //设置超时间隔//Public Slots
void start();
void stop()

2.举例:一个定时器,每3秒打印一次时间。
在这里插入图片描述

#include <QTime>MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{ui->setupUi(this);timer = new QTimer(this);timer->setInterval(3000);timer->start();QObject::connect(timer, &QTimer::timeout, this, &MainWindow::showTime);showTime(); //先手动调用一次槽函数,以在刚开始时就显示时间
}void MainWindow::showTime()
{QString text = QString("current time is %1").arg(QTime::currentTime().toString());ui->textBrowser->setText(text);
}

2.Qt文件操作:文件IO

1.文本文件:人能看懂的,ASCII码序列,数据全为字符串,内存中用string类型
二进制文件:只要数据不是全为字符串,就是二进制文件


2.文件IO的操作:将数据从磁盘读取到内存
①open
②read
③write
④close


3.磁盘IO是非阻塞的,网络IO是阻塞的 (改为非阻塞要配合while循环)。


4.QByteArray
封装char数组,避免了QString进行编码转换,会改变存储的数据。
只要数据在两个设备之间交互,用QByteArray。【内存→磁盘,内存→网卡】


5.QFile
(1)继承关系:QObject -> QIODevice -> QFileDevice -> QFile
①QIODevice:open、read、write、close
②QFile:二级功能
在这里插入图片描述


6.举例:
①读文件内容:TextBrowser
②编辑文本内容:TextEdit

void MainWindow::on_pushButton_clicked()
{QString filepath = QFileDialog::getOpenFileName(this, "open file");file = new QFile(filepath, this);file->open(QIODevice::ReadWrite);QByteArray array = file->readAll();ui->textBrowser->setText(QString(array));  //仅浏览ui->textEdit->setText(QString(array));     //可浏览,可编辑
}

3.Qt网络编程:网络IO

只介绍客户端。

1.注意:
①测试时要关代理。
②pro文件中,QT += network

QT       += core gui network

2.QTcpSocket
(1)头文件

#include <QTcpSocket>QTcpSocket *socket;
socket = new QTcpSocket(this);

(2)继承关系
QObject -> QIODevice -> QAbstractSockt -> QTcpSocket
①由于QIODevice的open/close/read/write是非阻塞的。希望在可读的时候才读。Qt框架会在可读的时候发射信号,所以将read写在槽函数里。【分离了发射和接受,不需要考虑什么时候才能接收】
在这里插入图片描述

②QAbstractSockt的connectToHost()是非阻塞的
在这里插入图片描述
在这里插入图片描述


3.举例:自己写网络客户端
代码链接:https://github.com/WangEdward1027/Qt/tree/main/QTcpSocket

socket = new QTcpSocket(this);//连接状态一改变,就打印一次
QObject::connect(socket, &QTcpSocket::stateChanged, this, &MainWindow::do_status_changed);
//连接完成,通知可以进行写操作
QObject::connect(socket, &QTcpSocket::connected, this, &MainWindow::do_connected_send);
//可读状态,调用读取的槽函数
QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::do_readyRead_show);
//on是框架生成的,do是自定义的
void MainWindow::on_pushButton_clicked()
{socket->connectToHost("www.baidu.com" ,80);
}void MainWindow::do_status_changed(QAbstractSocket::SocketState socketState)
{qDebug() << "current state = " << socketState;
}void MainWindow::do_connected_send()
{qDebug() << "send request";QByteArray request("GET / HTTP/1.1\r\n\r\n");socket->write(request);
}void MainWindow::do_readyRead_show()
{qDebug() << "show response";QByteArray response = socket->readAll();content += QString(response);ui->textBrowser->setText(content);//ui->webEngineView->setHtml(content);
}

4.Qt多线程

#include <QThread>

相关文章:

C++(week16): C++提高:(六) Qt提高

文章目录 四、Qt的元对象系统1.元对象和MOC(1)自省 和 反射(2)Qt是怎样支持元对象系统的&#xff1f;(3)支持元对象系统的三个要求(4)元对象系统的功能(5)动态属性 2.信号和槽机制(1)信号与槽机制的基本原理(2)自定义信号、自定义槽函数①自定义信号②自定义槽③关联 connect (…...

go 时间转时间戳的时区设置问题

昨天遇到一个问题&#xff0c;在完成时间转换时间戳&#xff0c;在后续测试中发现转换后的时间戳转成时间后&#xff0c;时间发生错误&#xff0c;时间和转换时间不一致问题 如下&#xff1a; package mainimport ("fmt""time" )func main() {Start : &q…...

MySQL 常见日志清理策略

前言&#xff1a; MySQL 数据库服务器使用多种类型的日志来记录操作和事件&#xff0c;这对于故障诊断、审计和性能分析非常重要。然而&#xff0c;这些日志文件会随着时间的推移而不断增长&#xff0c;可能会占用大量的磁盘空间。因此&#xff0c;定期清理这些日志是必要的&a…...

3大管人绝招让你的手下心服口服

3大管人绝招让你的手下心服口服 一&#xff1a;差异化管理&#xff0c;玩弄人性 谁赞成&#xff0c;谁反对&#xff0c;看清楚谁顺从自己&#xff0c;谁反对自己之后&#xff0c;接下来要做的便是区别对待。 给听话的下属最好的资源、最轻松简单的工作、最高的待遇&#xf…...

useImperativeHandle 是什么?你可以理解为 vue3 的 expose

useImperativeHandle 确实类似于 Vue 3 的 expose&#xff0c;两者都用于控制子组件向父组件暴露的接口。 在 React 中&#xff0c;useImperativeHandle 需要与 forwardRef 一起使用&#xff0c;原因如下&#xff1a; 转发引用&#xff1a;forwardRef 允许父组件将 ref 传递给…...

《Techporters架构搭建》-Day05 属性校验

属性校验 前言Validated基础用法集合校验分组校验嵌套校验自定义校验器 源码地址 前言 在项目开发过程中&#xff0c;经常遇到需要对传递的参数进行校验&#xff0c;比如某个参数字段是否为空、值的取值是否在约定范围、格式是否合法等等&#xff0c;最原始的写法&#xff0c;…...

HTTP的场景实践

HTTP的场景实践&#xff1a;任选一个浏览器&#xff0c;对于其涉及的请求中的缓存策略展开具体分析 1. 强缓存&#xff1a; Cache-Control用于指定缓存的最长有效时间。 Expires用于指定资源过期的日期。 2. 协商缓存&#xff1a; ETag用于标识资源的唯一标识符&#xff0c;…...

MySQL:表的设计原则和聚合函数

所属专栏&#xff1a;MySQL学习 &#x1f48e;1. 表的设计原则 1. 从需求中找到类&#xff0c;类对应到数据库中的实体&#xff0c;实体在数据库中表现为一张一张的表&#xff0c;类中的属性对应着表中的字段 2. 确定类与类的对应关系 3. 使用SQL去创建具体的表 范式&#xff1…...

介绍springmvc-水文

Spring MVC 是一个基于 Java 的开源 Web 框架&#xff0c;它是 Spring Framework 的一部分。Spring MVC 提供了一个架构&#xff0c;用于开发灵活、可扩展的 Web 应用程序。 Spring MVC 的主要特点包括&#xff1a; 基于模型-视图-控制器&#xff08;MVC&#xff09;的架构&am…...

uni-app学习笔记

一、下载HBuilder https://www.dcloud.io/hbuilderx.html 上述网址下载对应版本&#xff0c;下载完成后进行解压&#xff0c;不需要安装&#xff0c;解压完成后&#xff0c;点击HBuilder X.exe文件进行运行程序 二、创建uni-app项目 此处我是按照文档创建的uni-ui项目模板…...

Windows Server修改远程桌面端口

新建入站规则 填写端口 允许连接 修改远程桌面端口 winR打开注册表 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp修改PortNumber为新端口 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wi…...

界面组件Kendo UI for Vue 2024 Q2亮点 - 发布一系列新组件

随着最新的2024年第二季度发布&#xff0c;Kendo UI for Vue为应用程序开发设定了标准&#xff0c;包括生成式AI集成、增强的设计系统功能和可访问的数据可视化。新的2024年第二季度版本为应用程序界面提供了人工智能(AI)提示&#xff0c;从设计到代码的生产力增强、可访问性改…...

达梦数据库 逻辑备份还原

达梦的逻辑备份还原 1.背景2.要求3.实验步骤3.1 相关术语3.2 dexp逻辑导出3.2.1 使用dexp工具3.2.2 dexp相关参数含义3.2.3 四种级别导出3.2.3.1 FULL3.2.3.2 OWNER3.2.3.3 SCHEMAS3.2.3.4 TABLES 3.2.4 使用范例3.2.4.1 环境准备3.2.4.2 dexp逻辑导出 3.3 dimp逻辑导入3.3.1 使…...

Stable Diffusion绘画 | 图生图-上传重绘蒙版

上传重绘蒙版&#xff0c;可以弥补局部重绘的缺点&#xff0c;能够更精细的修改画面中的指定区域 使用PS制作的蒙版图片为耳朵下方区域&#xff0c;可以为图片中的女生带上不同款式的耳环。 参数配置&#xff1a; 调整提示词&#xff1a; 生成图片如下所示&#xff1a; 调整提…...

打开Office(word、excel、ppt)显示操作系统当前的配置不能运行此应用程序最全解决方案!

我以前用过分区助手把office从c盘挪到d盘了&#xff0c;从那以后office就用不了了&#xff0c;然后我就删了&#xff08;貌似没删干净&#xff09;。 最近由于有使用word的需求&#xff0c;所以我从学校官网找到正版软件的安装包&#xff0c;按照步骤重新卸载电脑中office残留…...

猫头虎 分享已解决Bug || TypeError: Cannot read property ‘map‘ of undefined 解决方案

&#x1f42f; 猫头虎 分享已解决Bug || TypeError: Cannot read property map of undefined 解决方案 摘要&#xff1a; 今天猫头虎带大家深入探讨在前端开发中常见的一个令人头疼的问题&#xff1a;TypeError: Cannot read property map of undefined。这个错误通常出现在我…...

大模型快速部署,以浪潮源2.0为例

step1: 申请PAI-DSW试用 step2&#xff1a;魔塔社区授权 由于本地授权一直失败&#xff0c;于是采用了魔塔免费平台实例进行学习。 搭建好之后&#xff0c;打开就有相关页面了&#xff1a; demo搭建&#xff1a; 按照官方提示的步骤进行搭建&#xff0c;内容如下&#xff1a;…...

Python知识点:使用FastAI进行快速深度学习模型构建

使用FastAI构建深度学习模型非常方便&#xff0c;尤其是对于快速原型开发和实验。以下是一个使用FastAI构建深度学习模型的完整示例&#xff0c;涵盖数据准备、模型训练和评估。 安装依赖 首先&#xff0c;确保你安装了FastAI库和其他必要的库&#xff1a; pip install fast…...

Nginx配置全局https

Nginx配置全局https 要在 Nginx 中配置将 HTTP (80 端口) 请求重定向到 HTTPS (443 端口)&#xff0c;可以在 Nginx 的配置文件中添加以下配置。假设你已经配置好了 HTTPS 相关的证书和密钥。 打开你的 Nginx 配置文件&#xff0c;通常是 /etc/nginx/nginx.conf。 在配置文件…...

DBAPI 如何对SQL查询出的日期字段进行统一格式转换

DBAPI 如何对SQL查询出的日期字段进行统一格式转换 mysql有一张订单表&#xff0c;有两个datetime类型的字段create_time update_time 新建一个API&#xff0c;SQL内容是查询所有数据 访问API发现日期字段默认返回时间戳格式 如果修改成自己想要的年月日格式&#xff0c;就要使…...

C:每日一题:字符串左旋

题目&#xff1a;实现一个函数&#xff0c;可以实现字符串的左旋 例如&#xff1a;ABCD左旋一个字符就是BCDA&#xff1b;ABCD左旋两个字符就是CDAB&#xff1b; 1、解题思路&#xff1a; 1.确定目标旋转k个字符&#xff0c;我们要获取字符串的长度 len&#xff0c;目的是根…...

深兰科技荣获2024年度金势奖“AI出海先锋品牌”金奖

近日&#xff0c;由金势奖组委会、凤凰网、营销国际协会等国内外知名机构、集团共同主办的“第四届未来营销大会暨锐品牌盛典”在上海举行。大会揭晓了第四届“金势奖锐品牌大赏”奖项的评选结果&#xff0c;深兰科技凭借自身在机器人产品出口和海外市场开拓等出海全球化发展方…...

服务器启动jar包的时候报”no main manifest attribute“异常(快捷解决)

所以,哥们,又出现问题咯.没事,我也出现了,哈哈哈哈哈,csdn感觉太麻烦了,所以搞了一篇这个. 没得事,往下看,包解决的. 希望可以帮助到各位&#xff0c;感谢阅览&#xff01; 小手点个赞&#xff0c;作者会乐烂哈哈哈哈哈哈&#x1f606;&#x1f606;&#x1f606;&#x1f606…...

部分控件的setText文案没有出现在retranslateUi()中,多语言切换不生效问题

问题&#xff1a;在designer中设计UI&#xff0c;我从其他ui文件copy了部分控件&#xff0c;新ui文件重新编译生成后&#xff0c;setText&#xff08;&#xff09;并没有出现在新文件的retranslateUi()函数中&#xff0c;导致多语言切换不生效。 void retranslateUi(QWidget * …...

ubuntu系统下安装LNMP集成环境的详细步骤(保姆级教程)

php开发中集成环境的安装是必不可少的技能,而LNMP代表的是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构。今天就给大家分享下LNMP的安装步骤。 1 Nginx安装 在安装Nginx前先执行下更新命令: sudo apt-get update 接下来开始安装Nginx, 提示:Could not get lock /v…...

化繁为简:揭秘中介者模式在Java设计中的魅力与力量

中介者模式是一种行为型设计模式&#xff0c;它通过引入一个中介者对象来简化多个对象之间的交互&#xff0c;从而降低它们之间的耦合度。在Java设计模式中&#xff0c;中介者模式扮演着重要的角色&#xff0c;特别是在处理复杂系统模块间的交互时。下面对Java设计模式之中介者…...

Postgresql导入矢量数据

前期准备 工具&#xff1a;PgAdmin&#xff0c;postgis-bundle Postgres安装和postgis安装可以百度别的教程。 创建数据库添加扩展 如图&#xff0c;使用PgAdmin创建名为shp的数据库&#xff0c;并在扩展item中添加postgis扩展。 添加扩展方法可以用查询工具输入以下sql语句&…...

二叉树拙见

1.树的概念及结构 1.1树的概念&#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 &#xff0…...

APT 组织 Kimsuky 瞄准大学研究人员

执行摘要 Kimsuky 是一个朝鲜 APT 组织&#xff0c;其任务是执行符合朝鲜政府利益的全球情报收集行动。该组织自 2012 年以来一直活跃&#xff0c;对韩国智库和政府实体特别感兴趣&#xff1b;然而&#xff0c;它也针对美国、英国和其他欧洲国家。Kimsuky 擅长进行有针对性的网…...

Golang | Leetcode Golang题解之第327题区间和的个数

题目&#xff1a; 题解&#xff1a; import "math/rand" // 默认导入的 rand 不是这个库&#xff0c;需要显式指明type node struct {ch [2]*nodepriority intkey intdupCnt intsz int }func (o *node) cmp(b int) int {switch {case b < o.k…...