QT个人笔记

QT

引言:

定义

Qt是一个跨平台的C++图形用户界面应用程序框架

优势

  1. 跨平台,几乎支持所有的平台
  2. 接口简单,容易上手,学习QT框架对学习其他框架有参考意义。
  3. 一定程度上简化了内存回收机制
  4. 开发效率高,能够快速的构建应用程序。
  5. 有很好的社区氛围,市场份额在缓慢上升。
  6. 可以进行嵌入式开发。

QT默认基类

默认的基类有QMainWindow、QWidget以及QDialog三个,QWidget(类似于空窗口)

0. C + + 部分知识点 \textcolor{red}{C++部分知识点} C++部分知识点

(1)双冒号::

  • 第一种,类作用域,用来标明类的变量、函数
	Human::setName(char* name);
	&QPushButton::clicked;
  • 第二种,命名空间作用域,用来注明所使用的类、函数属于哪一个命名空间的
	std::cout << "Hello World" << std::endl;

(2)Qt中指针的用处

在Qt中使用指针是非常常见的,因为Qt是一个C++框架,而C++中使用指针是一种常用的编程模式。下面是在Qt中使用指针的主要原因:

  1. 动态内存分配:Qt中的许多对象需要在堆上进行动态内存分配,这样可以确保对象的生存期与程序逻辑相匹配,并且可以在需要时创建和销毁对象。指针提供了一种方便的方式来管理动态分配的对象。
  2. 对象生存期管理:Qt中的UI元素(如QPushButton、QLabel等)通常需要在程序的生命周期内保持活动状态。通过使用指针,可以在需要时创建这些UI元素,并在不再需要时进行销毁,从而正确地管理它们的生存期。
  3. 父子关系:在Qt中,对象之间可以建立父子关系。当一个对象被设置为另一个对象的父对象时,父对象负责管理子对象的内存,确保在父对象被销毁时同时销毁子对象。指针在这种情况下非常有用,可以轻松地指定父子关系。
  4. 信号与槽机制:Qt的信号与槽机制是一种强大的机制,用于在对象之间进行通信。指针允许轻松地连接信号和槽,从而实现对象之间的交互和响应。
  5. 多态性(Polymorphism):Qt中使用了多态性,通过基类指针指向派生类对象,可以实现对派生类的统一管理和操作。
  6. 数据共享:在Qt中,一些数据对象需要在多个类之间共享。使用指针可以避免复制数据,提高程序的性能。
  7. 函数传递:指针允许将对象传递给函数,而不会复制整个对象。这样可以提高程序的性能,特别是在处理大型对象时。

总的来说,Qt使用指针是为了更好地管理对象的生存期、构建复杂的对象关系、实现信号与槽的连接以及提供更高效的数据共享。虽然使用指针需要小心处理,以避免内存泄漏和悬挂指针等问题,但它们在Qt中是非常有用的编程工具。

(3).和->

当有一个指向对象的指针时,你可以使用 -> 来访问该对象的成员变量和成员函数。

. 运算符用于直接访问对象的成员

(4)堆和栈的生命周期

  1. 堆(Heap):
    • 堆是程序运行时动态分配的内存区域,用于存储动态分配的对象和数据结构。
    • 堆中的内存由程序员手动分配和释放,通常使用类似于 newdelete(或者 mallocfree 在C语言中)的操作来进行分配和释放。
    • 堆上分配的对象在程序的生命周期内一直存在,直到显式地由程序员释放,否则会导致内存泄漏。
    • 堆上的内存空间不会自动被回收,需要开发人员负责管理其生命周期。
    • 使用堆时需要注意避免悬挂指针和内存泄漏等问题。
  2. 栈(Stack):
    • 栈是一种自动分配和释放的内存区域,用于存储局部变量和函数调用的上下文。
    • 当函数被调用时,其局部变量会在栈上自动分配内存,当函数返回时,栈上的局部变量会自动释放。
    • 栈上的内存分配和释放是按照“先进后出”的原则进行的,因此称为“后进先出”(LIFO)数据结构。
    • 栈上的内存管理是由编译器自动处理的,程序员无需显式地分配或释放栈上的内存。
    • 由于栈上的内存自动分配和释放,因此栈上的对象生命周期通常比较短暂,仅限于函数调用的范围内。
  • 堆是手动管理内存的区域,对象在堆上分配,需要程序员负责手动释放内存。
  • 栈是自动管理内存的区域,局部变量在栈上分配,函数返回时自动释放。
  • 堆上的对象生命周期由程序员控制,栈上的局部变量生命周期由编译器控制。

(5)静态成员函数可以直接通过类名来使用

QMessageBox::critical();

(6)c++匿名函数/匿名对象

1)匿名函数
  1. 定义

    没有名字的函数。使用匿名函数,可以免去函数的声明和定义。这样匿名函数仅在调用函数的时候才会创建函数对象,而调用结束后立即释放,所以匿名函数比非匿名函数更节省空间。

  2. lambda 表达式可以在需要函数对象的地方使用,例如作为函数参数、存储在容器中或者在其他函数中返回。

    // 定义并使用 lambda 表达式
    auto add = [](int a, int b) -> int {
        return a + b;
    };
    int result = add(2, 3);	std::cout << "Result: " << result << std::endl;
    
2)匿名对象

也称临时对象

Cat(); —> 生成了一个匿名对象,执行完Cat( )代码后,此匿名对象就此消失。这就是匿名对象的生命周期。
Cat cc = Cat(); —>首先生成了一个匿名对象,然后将此匿名对象变为了cc对象,其生命周期就变成了cc对象的生命周期。

(7)Java中多态

  1. 多态是面向对象程序设计(OOP)的一个重要特征,指同一个实体同时具有多种形式,即同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。(同一件事情,发生在不同对象身上,就会产生不同的结果。)

    动物有很多种类,狗、猫等等,在吃这个条件下;猫吃猫粮,狗吃狗粮。这就是多态的具体体现。

  2. 多态的前提1:是继承

    多态的前提2:要有方法的重写

    父类引用指向子类对象,如:Animal a = new Cat();

    多态中,编译看左边,运行看右边

    //7.创建多态对象进行测试
    /*3.口诀1:父类引用指向子类对象
    * 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/
    Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存
    Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存
    //8.测试多态对象
     /*4.口诀2:编译看左边,运行看右边
    * 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型
    *      必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/
    a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体
    

(8)c++类型转换

1)C++层次转换规则

C++中层次类型转换中无非两种:上行转换和下行转换

C++规定自定义类型数据如果发生了继承关系,编译器允许进行类型转换(向上转型、向下转型),否则不能进行类型转换

2)静态转换(static_cast)

static_cast < T > ( expression ),该运算符把expression转换为T类型

在这里插入图片描述

进行上行转换(把派生类的指针或引用转换成基类表示)是安全的

进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的(也可以)

QMouseEvent * ev = static_cast<QMouseEvent *>(e);//QEvent的e转为子类QMouseEvent的ev
3)用于基本数据类型之间的转换,如把int转换成char,把char转换成int

在这里插入图片描述

4)动态转换(dynamic_cast)
在这里插入图片描述

在类层次间进行上行转换时(安全的转换),dynamic_cast和static_cast的效果是一样的

在进行下行转换时(不安全,子类指针可能会超出基类对象),dynamic_cast具有类型检查的功能,比static_cast更安全

dynamic_cast不能作用于基本数据类型

(9)Java与c++创建对象的区别

  1. c++

    在栈上创建对象

    QPainter painter(this);
    

    在堆上创建对象(需要手动delete)

    MyClass * obj = new MyClass();
    
  2. Java

    // 在栈上创建对象引用,并在堆上实例化对象
    MyClass obj1 = new MyClass(42);
    

    obj1 是在栈上创建的对象引用,它们分别指向堆上的不同 MyClass 对象实例。实际的 MyClass 对象实例本身是在堆上分配的,而栈上的引用仅保存了对象的地址(或者说引用)。

    总结:在 Java 中,对象本身总是在堆上分配,而对象引用(reference)可以在栈上创建。

(10)static关键字

本质就是修改了其作用域和生命周期

1.int main(int argc, char *argv[])

在C++中,特别是在控制台程序中,int main(int argc, char *argv[]) 是程序的入口点(main函数)

  1. int argc
    • argc 是一个整数(int)类型的变量,代表命令行参数的数量。
    • 当你运行一个C++控制台程序时,在命令行中输入的参数都会被传递给这个程序。argc 就是用来记录这些参数的数量。
    • 至少会有一个参数,即程序的名称本身。例如,运行命令 ./my_programargc 的值将是1。
  2. char *argv[]
    • argv 是一个指向字符指针(char pointer)的数组。
    • 每个元素 argv[i] 存储着一个命令行参数的字符串。
    • argv[0] 存储的是程序的名称(也就是可执行文件的名称)。
    • argv[1] 存储的是第一个传递给程序的参数,argv[2] 存储的是第二个参数,以此类推。

综合起来,int main(int argc, char *argv[]) 这个函数签名的作用是,当你运行程序时,可以通过命令行传递一些参数给程序。例如,假设编译并运行了一个名为my_program的C++程序,命令行输入为:./my_program arg1 arg2 arg3,那么:

  • argc 的值将是4,因为有4个参数,包括程序本身的名称。
  • argv[0] 存储的是./my_program,程序的名称。
  • argv[1] 存储的是arg1,第一个传递给程序的参数。
  • argv[2] 存储的是arg2,第二个参数。
  • argv[3] 存储的是arg3,第三个参数。

2.QT基础函数

(1)主函数

#include "mywidget.h"
#include <QApplication> //包含一个应用程序类的头文件

//argc命令行变量数量  argv[]命令行变量数组
int main(int argc, char *argv[])
{
    //a应用程序对象,Qt中应用程序对象有且仅有一个
    QApplication a(argc, argv);
    //窗口对象  myWidget父类 --> QWidget
    myWidget w;
    //窗口对象默认不会显示,需要调用show()方法来显示窗口
    w.show();
    //让应用程序对象进入消息循环(一直接受用户的操作,直到点击X才关闭,否则窗口一直存在)
    return a.exec();
}

(2)myWidget类的构造函数的声明

#ifndef MYWIDGET_H  //防止头文件重复定义
#define MYWIDGET_H

#include <QWidget>  //窗口类的头文件

class myWidget : public QWidget
{
    Q_OBJECT    //引入Qt信号和槽机制的一个宏

public:
    myWidget(QWidget *parent = nullptr);
    ~myWidget();	//析构函数
};
#endif // MYWIDGET_H

(3)myWidget类的构造函数的实现

#include "mywidget.h"
#include <QPushButton>

myWidget::myWidget(QWidget *parent) //前一个是类名,后一个是构造函数名
    : QWidget(parent)   //初始化列表
//    QWidget(parent) 表示调用 QWidget 类的构造函数,
//    并将传入的 parent 指针作为参数传递给它。
//    这样可以确保 myWidget 类的对象在初始化时,
//    也会调用 QWidget 类的构造函数,
//    以便在创建 myWidget 对象时执行父类 QWidget 的初始化操作
{
    //第一种创建按钮方法
    QPushButton* button1 = new QPushButton;
    button1->setParent(this); //this 当前对象的指针(地址),设置按钮的父亲,让按钮在窗口中
    button1->setText("开始游戏");

    //第二种创建按钮方法  弊端:按照按钮大小创建窗口 可用resize重置窗口大小
    QPushButton* button2 = new QPushButton("开始播放",this);

    //移动按钮
    button2->move(80,0);

    //重置窗口大小
    resize(600,400);
    //设置固定窗口大小
//    setFixedSize(600,400);
        
    //设置窗口标题
    setWindowTitle("MyFirstWindow");
}
myWidget::~myWidget()
{
}

3.按钮控件API(纯代码)

(1)创建按钮

QPushButton* button1 = new QPushButton; QPushButton* button2 = new QPushButton("开始播放",this);

这行代码是用C++语言创建了一个指向QPushButton对象的指针变量button1,并使用new运算符在堆上动态地分配内存来实例化一个QPushButton对象。

(2)设置父亲,让按钮在窗口里

button1->setParent(this);

(3)设置按钮文字

button1->setText("开始游戏");

(4)移动按钮

button2->move(80,0);

(5)重置窗口/按钮大小

resize(600,400); button1->resize(60,40);

(6)固定窗口大小

setFixedSize(600,400);

(7)设置窗口标题

setWindowTitle("MyFirstWindow");

4.对象树

img

当创建的对象在堆区的时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,就不需要管理释放操作,通过setParent函数将对象间确定父子关系,之后子对象会进入父对象的children列表

当析构时,会先从父对象开始,先走父对象析构函数(注意,只是析构没有真正释放),然后依旧children列表析构子对象,直到走到叶子对象后,释放叶子对象,再返回父对象释放,直到回到一开始的父对象。

5.QT坐标系

  • 左上角为(0,0)点

  • x向右为正方向

  • y向下为正方向

6. 信号和槽 \textcolor{red}{6.信号和槽} 6.信号和槽

(1)基础(点击按钮关闭窗口)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nm3KICbj-1691596113872)(C:\Users\ROG\AppData\Roaming\Typora\typora-user-images\image-20230719163551718.png)]

  • 松散耦合(点击按钮和窗口关闭本无关,connect连接后有关系)

  • 连接函数 connect

  • 参数1 信号发送者

  • 参数2 发送的信号(函数地址)

  • 参数3 信号的接收者

  • 参数4 处理的槽函数(函数地址)

connect(button2,&QPushButton::clicked,this,&QWidget::close);

(2)自定义信号和槽

自定义信号
  • 在头文件中定义

  • 返回值void

  • 需要声明,不需要实现

  • 可以有参数、重载

自定义槽函数
  • 在头文件中定义

  • 返回值void

  • 需要声明,也需要实现

  • 可以有参数,可以重载

  • emit触发自定义信号

(3)自定义信号和槽的重载

函数指针

指向函数入口地址的指针称为函数指针

一般形式 : 数据类型 (*指针变量名) (参数表);

有如下的函数:int fn1(int x, int y); int fn2(int x);

定义如下的函数指针:int (*p1)(int a, int b); int (*p2)(int a);,则

p1 = fn1; //正确

p2 = fn2; //正确

p1 = fn2; //产生编译错误
重载
//信号重载
signals:
void hungry();
void hungry(QString foodName);

//槽重载
void treat();
void treat(QString foodName);

void Student::treat()   //槽函数的实现
{
    qDebug() << "请老师吃饭";
}
void Student::treat(QString foodName)
{
    qDebug() << "打包一份" << foodName;
}

//连接
//需要使用函数指针确定到底是哪个信号 若是无参QString改为void
void (Teacher:: *teacherSignal)(QString)=&Teacher::hungry;
void (Student:: *studentSlot)(QString)=&Student::treat;
connect(teacher,teacherSignal,student,studentSlot);
**QString转char ***

.toUtf8().data()

(4)信号连接信号

在这里插入图片描述

QPushButton * btn = new QPushButton("下课",this);
void (Teacher:: *teacherSignal2)(void)=&Teacher::hungry;
void (Student:: *studentSlot2)(void)=&Student::treat;
//信号连接信号(点击的信号连接老师饿了的信号)
connect(btn,&QPushButton::clicked,teacher,teacherSignal2);
//无参信号连接槽
connect(teacher,teacherSignal2,student,studentSlot2);

(5)拓展

  1. 一个信号可以连接多个槽函数

  2. 多个信号可以连接同一个槽函数

  3. 信号和槽的参数类型必须一一对应

  4. 信号的参数个数可以多于槽的参数个数,反之不成立

7.Lambda表达式

(1)匿名函数形式

[ ]( )->返回值类型{ }; //引用该匿名函数  [ ]( )->返回值类型{ }();
  1. (1)[]标识符

    [=] 值传递(最常用) [&] 引用传递

    = &都可以使用Lambda所在范围内所有可见的局部变量

  2. (2)()参数

  3. (3){}函数体

  4. (4)->返回值类型

  5. (5)mutable关键字

用于修改传递的变量,修改的是拷贝,而不是本体

int m=10;
connect(newbtn,&QPushButton::clicked,this,[m]()mutable{m=100+10;qDebug()<<m;});//输出110
connect(newbtn1,&QPushButton::clicked,this,[=](){qDebug()<<m;});//输出10

QWidget总结

(1)newWindow->show()

假如要点击一个按钮创建一个带按钮的新窗口,必须先new新窗口和新按钮再show()

connect(btn1,&QPushButton::clicked,[=](){
        QWidget * newWindow = new QWidget;
        newWindow->setFixedSize(600,400);
        QPushButton * newbtn = new QPushButton;
        newbtn->setParent(newWindow);
        newbtn->resize(100,100);
        newWindow->show();//最后show()
    });

---------------------------------------------------

8.QMainWindow

img

(1)菜单栏 QMenuBar

1)创建菜单

菜单栏最多只有一个

QMenuBar * bar = menuBar();//创建,默认不会放在窗口中
setMenuBar(bar);//将新建的菜单放入窗口
2)添加菜单
QMenu * fileMenu = bar->addMenu("文件");
3)添加菜单项
QAction * newAction = fileMenu->addAction("新建");
4)添加分割线
fileMenu->addSeparator();
5)菜单项点击信号

&QAction::triggered

(2)工具栏 QToolBar

1)创建工具栏

工具栏可以有多个

QToolBar * toolbar = new QToolBar(this);//默认不会放入窗口,与菜单栏区别!!这需要放入this对象树中
//	  将工具栏放入窗口中
addToolBar(Qt::TopToolBarArea,toolbar);//(默认停靠位置,工具栏指针)
//    指定工具栏默认位置
//    LeftToolBarArea 左
//    RightToolBarArea 右
//    TopToolBarArea 上
//    BottomToolBarArea 下
2)设置后期停靠区域,是否浮动,是否可移动
//设置工具栏只允许停靠上下
toolbar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
//设置工具栏是true否false浮动
toolbar->setFloatable(false);
//设置工具栏是否移动
toolbar->setMovable(false);
3)添加工具栏内容,控件
//工具栏设置内容
toolbar->addAction(newAction);//上面的菜单项QAction * newAction = fileMenu->addAction("新建");
toolbar->addAction(openAction);
//工具栏中添加控件
QPushButton * button = new QPushButton("ab",this);
toolbar->addWidget(button);

(3)状态栏 QStatusBar

1)创建状态栏

最多有一个

QStatusBar * stBar = statusBar();
//设置到窗口中
setStatusBar(stBar);
2)添加标签控件(放信息)
QLabel * label = new QLabel("提示信息",this);
stBar->addWidget(label);//左侧
QLabel * label2 = new QLabel("右侧提示信息",this);
stBar->addPermanentWidget(label2);//右侧

(4)铆接部件(浮动窗口) QDockWidget

1)创建铆接部件

可以有多个

QDockWidget * dock = new QDockWidget("浮动",this);
//放入窗口
addDockWidget(Qt::BottomDockWidgetArea,dock);//(默认停靠区域,浮动窗口指针)
2)设置停靠位置
//设置允许停靠位置 只允许上下停靠
dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);

(5)中心部件

1)创建中心部件
QTextEdit * edit = new QTextEdit(this);//文本编辑器
//将中心部件放入窗口
setCentralWidget(edit);

9.资源文件

(1)步骤

  1. 将图片文件拷贝到项目目录下
  2. 右键项目 => 新建文件 => Qt => Qt Resource File => 给资源文件起名字
  3. myResource生成myResource.qrc
  4. open in editor添加文件,先添加前缀(/),再添加文件
  5. 使用Qt资源 “: + 前缀名 + 文件名”
//使用Qt资源      ": + 前缀名 + 文件名"
ui->actionNew->setIcon(QIcon(":/myPicture/bmwi7.jpeg"));
ui->actionopen->setIcon(QIcon(":/myPicture/cat.jpg"));

10.对话框

(1)分类

  1. 模态对话框(不可以对其他窗口进行操作)
  2. 非模态对话框(可以对其他窗口进行操作)

(2)创建

  1. 模态对话框创建

    QDialog dlg(this);
    dlg.resize(200,100);//设置大小不会弹出警告
    dlg.exec();//阻塞
    
  2. 非模态对话框创建

    QDialog * dlg2 = new QDialog(this);
    dlg2->resize(200,100);
    dlg2->setAttribute(Qt::WA_DeleteOnClose); //55号属性,让对话框关闭后释放对象
    dlg2->show();
    
  • 为什么模态在栈上创建,非模态在堆上创建? \textcolor{red}{为什么模态在栈上创建,非模态在堆上创建?} 为什么模态在栈上创建,非模态在堆上创建?

模态没有在堆上new出来而是在栈上创建,并且在栈上创建没有被释放是因为.exec()阻塞了,而下面非模块对话框如果不new在堆上,show()不会阻塞,匿名函数一结束就会被立马释放,就看不见对话框,为了防止一闪而过,所以非模态要在堆上创建,上面可以在栈上创建

(3)标准对话框(消息对话框)

  1. QMessageBox静态成员函数 创建对话框

    QMessageBox::warning(this,"Warning","警告");
    
  2. 错误,信息,提问,警告对话框

    参数(父亲 , 标题 , 提示内容 , 按键类型 , 默认关联回车按键)

    //错误对话框
    QMessageBox::critical(this,"Critical","妈的你错误了");
    //信息对话框
    QMessageBox::information(this,"Information","信息");
    //提问对话框
    //QMessageBox::question()和QMessageBox::Save的返回值为StandardButton,利用返回值判断用户输入,用于点击后的效果
    if(QMessageBox::Save == QMessageBox::question(this,"Question","你要走了吗",QMessageBox::Save | QMessageBox::Cancel))
    	{
        	qDebug()<<"保存成功!";
    	}else
    	{
        	qDebug()<<"取消成功!";
    	}
    //警告对话框
    QMessageBox::warning(this,"Warning","警告");
    
  3. 按键类型

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-920NfvKx-1691596113873)(C:\Users\ROG\AppData\Roaming\Typora\typora-user-images\image-20230724234836863.png)]

(4)其他对话框

  1. 颜色对话框

    QColor color = QColorDialog::getColor(QColor(255,0,0));
    qDebug() << "r=" << color.red() << "g=" << color.green() << "b=" << color.blue();
    
  2. 文件对话框

    //参数(父亲,标题,默认打开路径,过滤文件格式)
    QString str = QFileDialog::getOpenFileName(this,"打开文件","C:/Users/ROG/Desktop","(*.txt)");
    //返回值是选取的文件路径
    
  3. 字体对话框

    bool flag;
    QFont font = QFontDialog::getFont(&flag,QFont("华文彩云",36));
    qDebug()<< "字体:" << font.family().toUtf8().data() << "字号:" << font.pointSize() << "是否加粗:" << font.bold() << "是否斜体:" << font.italic();
    

11.界面布局(UI)

  1. 实现登陆窗口
  2. 利用布局方式,将窗口美化
  3. 选取 Widget 进行布局(水平布局,垂直布局,栅格布局
  4. 给用户名、密码、登录、退出按钮布局
  5. 利用弹簧布局
  6. 默认窗口与控件之间有间隙,layoutLeftMargin…改
  7. 框和控件一样大,选中框,在sizePolicy中垂直策略改为Fixed
  8. 输入密码不显示(echoMode选择password)

12.控件(UI)

(1)按钮组

  1. QPushButton常用按钮

  2. QToolButton 工具按钮 修改toolButtonStyle风格可以图片和文字一起显示,凸起风格autoRaise

  3. radioButton 单选按钮 设置默认选择 ui->rBman->setChecked(true);

  4. checkBox 多选按钮,监听状态

    //stateChanged的参数 2是选中 0是未选中
    connect(ui->bmwBox,&QCheckBox::stateChanged,[=](int state){
    	qDebug() << state;
    });
    

(2)QListWidget列表容器

  1. QListWidgetItem * item 一行内容

  2. ui->listWidget->addItem(item); 将内容放入容器

  3. item->setTextAlignment(Qt::AlignHCenter); 设置水平居中

  4. 利用addItem添加多行内容,但无法居中

    //QStringList   QString<List>
    QStringList list;//list链表
    list << "床前明月光" << "疑似地上霜" << "举头望明月" << "低头思故乡";//内容放入链表
    ui->listWidget->addItems(list);
    

QStringList使用

QStringList list;
list << "床前明月光" << "疑似地上霜" << "举头望明月" << "低头思故乡";
//等同于
QStringList() << "床前明月光" << "疑似地上霜" << "举头望明月" << "低头思故乡";//QStringList()是创建一个空的QStringList对象(匿名对象),重载了<<运算符

(3)QTreeWidget树控件

  1. 设置水平头

    ui->treeWidget->setHeaderLabels(QStringList() << "英雄" << "英雄介绍");
    
  2. 创建根节点

    QTreeWidgetItem * powerItem = new QTreeWidgetItem(QStringList() << "力量");
    
  3. 添加根节点

    ui->treeWidget->addTopLevelItem(powerItem);
    
  4. 添加子节点

    QStringList heroL1;
    heroL1 << "阿诺" << "神一般的抗药性";
    QTreeWidgetItem * L1 = new QTreeWidgetItem(heroL1);
    powerItem->addChild(L1);
    

(4)QTableWidget表格控件

  1. 设置列数

    ui->tableWidget->setColumnCount(3);
    
  2. 设置水平表头

    ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "性别" << "年龄");
    
  3. 设置行数

    ui->tableWidget->setRowCount(5);
    
  4. 设置内容

    ui->tableWidget->setItem(0,0,new QTableWidgetItem("阿诺"));
    
    QStringList nameList;
    nameList << "阿诺" << "麦寇" << "脚强" << "cBumStead" << "Nick Walker";
    QStringList sexList;
    sexList << "男" << "男" << "男" << "男" << "男";
    for(int i=0;i<5;i++)
    {
    	int col=0;
    	ui->tableWidget->setItem(i,col++,new QTableWidgetItem(nameList[i]));//第i行第0列
    	ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sexList.at(i)));//第i行第1列
    	ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(18+i)));//第i行第2列
    }
    

(5)其他控件

  1. 利用QLabel显示GIF动画

    QMovie * movie = new Qmovie("GIF路径")
    ui->my_label->setMovie(movie);
    movie->start();//必须开始
    

13.自定义控件封装

  1. 添加新文件,选择Qt-设计师界面类 (.h .cpp .ui)

  2. 新的.ui中设计,例如QSpinBox和QSlider两个控件

  3. 在widget.ui中使用自定义控件,在widget.ui拖拽一个widget,提升为SmallWidget,添加,提升

  4. 实现功能,改变SpinBox数字,Slider跟着滑动,信号槽监听

  5. 提供getNum和setNum对外接口

    //smallWidget.h中
    public:
        explicit SmallWidget(QWidget *parent = nullptr);
        ~SmallWidget();
        //设置
        void setNum(int num);
        //获取
        int getNum();
    //smallWidget.cpp中
    void SmallWidget::setNum(int num){ui->spinBox->setValue(num);}//SmallWidget::作用域
    int SmallWidget::getNum(){return ui->spinBox->value();}
    //widget.cpp中使用
    connect(ui->getv,&QPushButton::clicked,[=](){
    	qDebug() << "当前值为" << ui->widget->getNum(); 
    							//这里的widget之前被提升过,是SmallWidget实例化的一个对象
    });
    connect(ui->setv,&QPushButton::clicked,[=](){
    	ui->widget->setNum(75);
    });
    

14.Qt中的事件

(1)鼠标事件

1)鼠标进入事件

void myLabel::enterEvent(QEnterEvent *event)

2)鼠标离开事件

void myLabel::leaveEvent(QEvent *)

3)鼠标按下事件

void myLabel::mousePressEvent(QMouseEvent *ev)

4)鼠标松开事件

void myLabel::mouseReleaseEvent(QMouseEvent *ev)

5)鼠标移动事件

void myLabel::mouseMoveEvent(QMouseEvent *ev)

6)获取坐标
//获取x,y坐标
ev->x(),ev->y();
//qt格式化字符串 类似printf
QString str = QString("鼠标按下了,在 x= %1 y= %2 处").arg(ev->x()).arg(ev->y());
//globalX(),globalY()是基于电脑屏幕的坐标
7)Qt格式化字符串

%1,%2…参数1,参数2 .arg(参数1).arg(参数2)…

QString str = QString(“鼠标按下了,在 x= %1 y= %2 处”).arg(ev->x()).arg(ev->y());

8)判断按键

ev->button()

ev->button()==Qt::LeftButton 判断左键

9)判断组合按键

判断move时候的左右键,结合&运算

void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
    //按下左键并移动才输出结果
    if(ev->buttons() & Qt::LeftButton)  //Qt::LeftButton的二进制值为00...01,
    //如果按下左键00...01 & 00...01 =1 执行if,如果是别的,&出来就是0,不执行if
    {
        QString str = QString("鼠标移动了,在 x= %1 y= %2 处").arg(ev->x()).arg(ev->y());
        qDebug() << str;
    }
}
10)button和buttons区别

假设你的鼠标左键已经按下。
如果移动鼠标,会发生的move事件,button返回Qt::NoButton,buttons返回LeftButton
再按下了右键,会发生press事件,button返回RightButton,buttons返回LeftButton|RightButton
再移动鼠标,会发生move事件,button返回Qt::NoButton,buttons返回LeftButton|RightButton
再松开左键,会发生Release事件,button返回LeftButton,buttons返回RightButton
也就是说,button返回“那个按钮发生了此事件”,buttons返回"发生事件时哪些按钮还处于按下状态"

15.定时器

(1)方式1

  1. 利用事件 void timerEvent(QTimerEvent *ev);

  2. 启动定时器

    int id1 = startTimer(500);//参数:间隔ms 返回值:int定时器唯一标识
    
  3. 利用上述返回值,可以与ev->timerId()比较,判断哪个定时器执行什么操作

    if(ev->timerId()==id1)
    {
        static int num = 1;//设置static 否则一直是1
        //label_2每隔500ms加一次
        ui->label_2->setText(QString::number(num++));
    }
    

(2)方式2(常用!!!)

  1. 引入QTimer类#include <QTimer>

  2. 创建定时器对象

    QTimer * timer = new QTimer(this);
    
  3. 启动定时器,输入参数,单位为毫秒,并使用信号槽连接

    timer->start(500);//0.5s发出一个信号
    connect(timer,&QTimer::timeout,ui->label_4,[=](){
        //label_4每隔0.5s加一次
        static int num=1;
        ui->label_4->setText(QString::number(num++));
    });
    
  4. 点击按钮暂停定时

    connect(ui->pushButton,&QPushButton::clicked,[=](){
        timer->stop();
    });
    

16.Event事件分发器

9cce6032f296175beed861b7bc14eec

APP与事件分发器之间还有一个高级的事件过滤器eventfilter

  1. 用途:用于分发事件

  2. 也可以拦截操作,不建议

  3. 拦截,bool event(QEvent *ev);返回值true代表用户自己处理,不向下分发

    拦截示例:

    bool myLabel::event(QEvent *e)
    {
        //如果是鼠标按下,在event事件分发器中拦截
        if(e->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent * ev = static_cast<QMouseEvent *>(e);//QEvent类型转化为QMouseEvent
            QString str = QString("Event函数中::鼠标按下了,在 x= %1 y= %2 处").arg(ev->x()).arg(ev->y());
            qDebug() << str;
            return true;//true代表用户自己处理这个事件
        }
        //其他事件交给父类处理
        return QLabel::event(e);
    }
    

17.QPainter 绘图

(1)绘图事件

void paintEvent(QPaintEvent *ev);

重写了这个画家事件函数就会执行

(2)设置画家

//实例化画家对象
QPainter painter(this);//在当前this窗口下画画,并非设置父类

(3)设置笔

//设置画笔
QPen pen(QColor(0,255,0));
pen.setWidth(3);
pen.setStyle(Qt::DotLine);
//让画家使用这个笔
painter.setPen(pen);

(4)设置画刷

//设置画刷,给封闭图形上色
QBrush brush(Qt::cyan);//Qt::cyan也是颜色
//设置画刷风格
brush.setStyle(Qt::Dense5Pattern);
painter.setBrush(brush);

(5)绘图

//画线
painter.drawLine(QPoint(0,0),QPoint(200,300));
//画圆(椭圆)
painter.drawEllipse(QPoint(300,200),100,100);//圆心,半长轴,半短轴
//画矩形
painter.drawRect(QRect(QPoint(100,0),QPoint(200,100)));
//画文字
painter.drawText(QRect(10,300,100,50),"黄伟聪");

18.QPainter 高级设置

  1. 设置抗锯齿,效率低

    painter.setRenderHint(QPainter::Antialiasing);

  2. 对画家进行移动

    painter.translate(100,0);

  3. 保存和恢复画家状态

    save(),restore()

  4. 手动调用绘图事件 update()

  5. 利用画家画图片

    painter.drawPixmap(posX,0,QPixmap(":/myPicture/linux.jpg"));

19.QPaintDevice 绘图设备

(1)有哪些?

QPixmapQImageQPictureQBitmapQWidget

(2)QPixmap

  1. 对不同平台做了显示的优化

  2. QPixmap pix(300,300); 设置画布大小

  3. pix.fill(Qt::white); 背景颜色

  4. **QPainter painter(&pix); **利用画家,往pix上画画

  5. painter.setPen(QPen(Qt::gray));
    painter.drawEllipse(QPoint(150,150),100,100);
    
  6. pix.save("E:\\pix.png");//路径要用\\
    

(3)QImage

  1. 可以对像素进行访问

  2. QImage::Format_RGB32

    //QImage绘图设备    可以对像素访问
    QImage image(300,300,QImage::Format_RGB32);//!!!
    image.fill(Qt::white);
    QPainter painter(&image);
    painter.setPen(QPen(Qt::gray));
    painter.drawEllipse(QPoint(150,150),100,100);
    //保存在E盘
    image.save("E:\\img.png");
    
  3. 像素的访问(修改像素点颜色

    QPainter painter(this);
    QImage img;
    img.load(":/E:/myPicture/linux.jpg");
    //利用QImage修改像素点
    for(int i=1;i<50;i++){
        for(int j=1;j<50;j++){
            QRgb value = qRgb(0,0,255);//设置RGB颜色
            img.setPixel(i,j,value);//修改像素点
        }
    }
    painter.drawImage(0,0,img);
    

(4)QPicture

  1. 可以记录重现绘图指令

  2. 需要用到begin(&pix),end()组合

    QPicture pic;
    QPainter painter;
    painter.begin(&pic);
    painter.setPen(QPen(Qt::blue));
    painter.drawEllipse(QPoint(150,150),100,100);
    painter.end();
    //保存到磁盘
    pic.save("E:\\pic.hwc");//后缀名未知,无法打开,在3.中重现
    
  3. 重现

    QPainter painter(this);
    //重现QPicture绘图指令,用于打开一些后缀名未知的图片
    QPicture pic;
    pic.load("E:\\pic.hwc");
    painter.drawPicture(0,0,pic);
    

20.QFile 文件读写

  1. QFile进行读写操作,默认支持utf-8

  2. QString path = QFileDialog::getOpenFileName(this,"打开文件","C:/Users/ROG/Desktop","(*.txt)");
    QFile file(path);//参数就是要读取的文件的路径
    
  3. file.open(打开方式)

    打开方式:QIODevice::ReadOnlyQIODevice::Append

  4. 读文件

    file.readAll(); 全部读

    file.readLine(); 读一行

    file.atEnd() 判断是否到达文件尾

    //一行一行读完全部
    QByteArray arr;
    while(!file.atEnd())//只要没有到文件尾
    {
    	arr += file.readLine();//读一行
    }
    
  5. 写文件

    file.open(QIODevice::Append);//追加方式写
    file.write("君不见黄河之水天上来,奔流到海不复回!");
    
  6. 最后记得** 关闭文件对象 \textcolor{red}{关闭文件对象} 关闭文件对象**

    file.close()
    

21.QFileInfo 读取文件信息

  1. QFileInfo info(文件路径);

  2. 获取信息

    qDebug() << "文件大小:" << info.size() << "文件路径:" << info.path()
             << "文件名:" << info.fileName() << "文件后缀名:" << info.suffix()
             << "最后修改时间:" << info.lastModified().toString("yyyy-MM-dd hh:mm:ss")
             << "创建时间:" << info.birthTime().toString("yyyy-MM-dd hh:mm:ss");
    
  3. 时间信息

    常用 :yyyy-MM-dd hh:mm:ss

    表达式输出
    d天 1-31
    dd天 01-31
    ddd星期 ‘Mon’ to ‘Sun’
    dddd星期 ‘Monday’ to ‘Sunday’
    M月份 1-12
    MM月份 01-12
    MMM月 ‘Jan’ to ‘Dec’
    MMMM月 ‘January’ to ‘December’
    yyyy年份 2023

QT案例–翻金币游戏

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值