Qt 基础 详细总结

文章目录

  • Qt
    • 一、创建Qt项目
      • 1.快捷键
      • 2.命名规范
    • 二、QPushButton
      • 1.按钮控件常用API
        • (1)创建
        • (2)设置父亲
        • (3)设置文本
        • (4)设置位置
        • (5)重新指定窗口大小
        • (6)设置窗口标题
        • (7)设置窗口固定大小
    • 三、对象树
        • 1. 析构问题
        • 2. 对象树
    • 四、Qt窗口坐标
    • 五、信号和槽机制(重点)
      • 1. 基本概念与函数参数解释
      • 2. 自定义信号和槽
        • (1)代码实现
        • (2)自定义信号和槽需要注意的事项
        • (3)函数重载
          • <1>当自定义信号和槽出现重载
          • <2>按钮触发槽函数
          • <3>信号连接信号
          • <4>断开信号
      • (3)拓展
      • 3.Lamba表达式
      • 4. 信号与槽总结(思维导图)
    • 六、QMainWindow
      • 1. 菜单栏
      • 2. 工具栏
      • 3.状态栏
      • 4.铆接部件(浮动窗口)
      • 5. 设置中心部件(核心部件)
      • 6. 资源文件
    • 七、对话框 QDialog
      • 1. 基本概念
      • 2.模态对话框
      • 3. 非模态对话框
      • 4.消息对话框(是 模态对话框)
        • (1)错误对话框
        • (2)信息对话框
        • (3)提问对话框
        • (4)警告对话框
        • (5)总结
      • 5. 其他标准对话框
        • (1)颜色对话框 QColorDialog::getColor
        • (2)文件对话框 QFileDialog::getOpenFileName
        • (3)字体对话框 QFontDialog::getFont
    • 八、布局管理器
      • 1. 界面布局(ui)
    • 九、控件
      • 1. 按钮组
      • 2. QListWidget 列表容器
      • 3. QTreeWidget 树控件
        • 1. 设置头 (只是在原有界面设置而已,所以不用new)
        • 2. 创建根节点(新创建的,所以需要new)
        • 3. 添加根节点 到 树控件上
        • 4. 添加子节点(创建子结点,也需要new)
      • 4. QTableWidget 表格控件
        • (1)使用QStringList() << "..."
        • (2)使用QStringList nameList;(nameList[i])
        • (3)使用QList < QString > sexList;(sexList.at[i])
      • 5. 其他控件
        • (1)stackedWidget 栈控件
          • <1>scrollArea 按钮
          • <2>toolBox 按钮
          • <3>TabWidget 按钮
        • (2) comboBox 下拉框
        • (3)QLabel 显示图片
        • (4)QLabel 显示动图 gif图片
    • 十、自定义控件
    • 十一、Qt 中的鼠标事件
    • 十二、定时器
      • 1、定时器1
      • 2、定时器2
    • 十三、event 事件分发 bool event( QEvent * e); 系统函数
    • 十四、事件过滤器
    • 十五、绘图事件
      • 1、绘图基本操作
      • 2、QPainter 高级设置
      • 3、绘图设备
    • 十六、QFile 文件读写操作
      • 1、总结:
        • (1) QFile进行读写操作
        • (2) QFile file( path 文件路径)
        • (3)读
        • (4)写
        • (5)QFileInfo 读取文件信息
      • 2、头文件
        • (1)#include < QFileDialog > 读取路径
        • (2)#include < QFile > 读取内容
        • (3)#include < QTextCodec > 编码格式
        • (4)#include< QFileInfo >
        • (5)#include< QDateTime >
      • 3、代码
    • 十七、开发注意事项

Qt

一、创建Qt项目

注意:两个路径都不能有中文

Qt 基础 详细总结_第1张图片

构建套件:
Qt 基础 详细总结_第2张图片

类信息:

其中基类有三种可以选择,他们的关系是:
Qt 基础 详细总结_第3张图片

Qt 基础 详细总结_第4张图片

1.快捷键

Qt 基础 详细总结_第5张图片

2.命名规范

在这里插入图片描述

二、QPushButton

例:btn -> show(); //show是以顶层方式弹出窗口控件

//让btn对象 依赖在 myWidget窗口中(父窗口)
btn->setParent(this);

按钮控件需要添加头文件 #include

1.按钮控件常用API

(1)创建

QPushButton * btn = new QPushButton;

(2)设置父亲

setParent(this); //当前类(当前窗口),所以this

(3)设置文本

setText(“文字”)

(4)设置位置

move(宽,高)

(5)重新指定窗口大小

resize

(6)设置窗口标题

setWindowTitle

(7)设置窗口固定大小

setFixedSize

三、对象树

1. 析构问题

析构的顺序与创建的顺序相反

析构函数qDebug()打印的时候的顺序与实际析构顺序相反

2. 对象树

(1)当创建的对象在堆区时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放的操作,将对象会放入到对象树中。

(2)一定程度上简化了内存回收机制(就是对象树

技巧:

以后就可以大胆的在堆区(这里指在firstwidget的构造函数中)创建对象,

并将对象myBtn -> setParent(this);设置到对象树中,即可。

到时候这个对象就会被自动析构,不用手动操作。

注意尽量在构造子类对象的时候就同时指定parent对象,这样如果先析构parent对象,这个时候就不会出现二次析构问题,就可以在析构parent对象的同时完全把子类对象析构了。

四、Qt窗口坐标

对于嵌套窗口,其坐标是相对于父窗口来说的。

Qt 基础 详细总结_第6张图片

五、信号和槽机制(重点)

1. 基本概念与函数参数解释

对象将想要处理的信号和自己的一个函数(即“槽”)绑定,来处理这个信号。

也就是说,当信号发出时,被连接的槽函数会自动被回调。

//信号与槽机制
//需求  点击我的按钮 关闭窗口
//参数1:信号的发送者;  参数2:发送的信号(函数的地址);  参数3:信号的接受者;  参数4:处理的槽函数(函数地址)

//connect(myBtn, &mypushbutton::clicked, this, &firstwidget::close);//这样写也可以(子类/父类)
connect( myBtn, &QPushButton::clicked, this, &QWidget::close  );

2. 自定义信号和槽

(1)代码实现

Qt 基础 详细总结_第7张图片

创建文件之后的默认代码,此时将自定义信号写在signals下

(2)自定义信号和槽需要注意的事项

  • ​ 发送者和接收者都需要是QObject的子类(当然,槽函数是 全局函数、Lambda 表达式等无需接收者的时候除外);

  • 信号和槽函数返回值是 void(信号和槽都可以有参数)

  • 信号只需要声明,不需要实现

  • 槽函数需要声明也需要实现(槽函数可以写到 public slot 下,也可以写在 public 下 (高低版本差异))

  • ​ 槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;

  • 使用 emit 在恰当的位置发送信号

  • ​ 使用connect()函数连接信号和槽。

  • ​ 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数

  • ​ 信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致

  • ​ 如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。

(3)函数重载

带参的和不带参的函数地址都一样,所以对于带参的函数重载需要重新写一个连接connect

<1>当自定义信号和槽出现重载
  • ​ 需要利用函数指针 明确指向函数的地址
  • void( Teacher:: * tSignal )( QString ) = &Teacher::hungry;
  • ​ QString 转成 char *
    • .ToUtf8()转为 QByteArray
    • .Data() 转为 Char *
<2>按钮触发槽函数

点击按钮,触发下课:(注意语法)

connect(btn,&QPushButton::clicked,this,&Widget::classIsOver);

注意:

click是槽

clicked是信号

<3>信号连接信号

Qt 基础 详细总结_第8张图片

<4>断开信号

断开信号 disconnect

(3)拓展

<1>信号可以连接信号

<2>一个信号可以连接多个槽函数

<3>多个信号可以连接同一个槽函数

<4>信号和槽函数的参数必须类型一一对应

<5>信号的参数个数可以多于槽函数的参数个数(但是也要保证类型一一对应,注意顺序)

(信号的参数可以比槽函数多,可以理解为,A发出信号,但是接收方B不想理。

但是反过来不行,接收方B想要的参数,发送方A必须给,否则报错)

了解:

//Qt4版本以前的信号和槽连接方式
//利用Qt4信号槽 连接无参版本
//Qt4版本 底层SIGNAL(“hungry”) SLOT( “treat”)
connect(zt,SIGNAL(hungry()) , st , SLOT(treat()));
//Qt4版本优点:参数直观,缺点 :编译器对类型不做检测
//Qt5以上 支持 Qt4的版本写法,反之不支持

3.Lamba表达式

C++11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作

(1)基本构成:

[ 函数对象参数 ](操作符重载函数参数)mutable -> 返回值 { 函数体 }

Qt 基础 详细总结_第9张图片

注意

[],标识一个Lambda的开始,这部分必须存在,不能省略

例子:

在这里插入图片描述

注意:

最后加个括号,表示 “调用”,而不是 “声明“

例子:

Qt 基础 详细总结_第10张图片

总结:

函数对象参数有以下形式:(一般使用 ”=“ 就足够了,其他都很少用)

(1)。没有使用任何函数对象参数。

(2)=====。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是***值传递方式***(相当于编译器自动为我们按值传递了所有局部变量)。

(3) &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是***引用传递方式***(相当于编译器自动为我们按引用传递了所有局部变量)。

(4) this函数体内可以使用Lambda所在类中的成员变量

(5)a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。


mutable关键字:

Qt 基础 详细总结_第11张图片


例子:

Qt 基础 详细总结_第12张图片

一个信号可以连接多个槽函数(使用lambda表达式的优势,比较方便):

Qt 基础 详细总结_第13张图片

4. 信号与槽总结(思维导图)

Qt 基础 详细总结_第14张图片

六、QMainWindow

QMainWindow是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个锚接部件(/浮动窗口)(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget),是许多应用程序的基础,如文本编辑器,图片编辑器等

Qt 基础 详细总结_第15张图片

1. 菜单栏

Qt 基础 详细总结_第16张图片

菜单栏meanBar()不用设置this,因为它是系统默认的,所以同时它也不用new(区别于工具栏)

只能有一个,所以是setMenuBar(bar),只能set一次

2. 工具栏

Qt 基础 详细总结_第17张图片

工具栏QToolBar(this) 需要设置this,同时也要new

补充:

Qt 基础 详细总结_第18张图片

工具栏可以有多个,所以是addToolBar( … ),可以add多个

3.状态栏

Qt 基础 详细总结_第19张图片

状态栏statusBar()不用设置this,因为它是系统默认的,所以同时它也不用new(区别于工具栏)

只能有一个,所以是setStatusBar(stBar),只能set一次

标签控件:

需要new(类似 ”按钮控件“),也需要设置parent,(this)

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

Qt 基础 详细总结_第20张图片

需要new,需要设置parent,(this)。因为它是部件(控件)

铆接部件可以有多个,所以是addDockWidget( … ),可以add多个

5. 设置中心部件(核心部件)

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

只能有一个,所以是seCentralWidget(edit),只能set一次

Qt 基础 详细总结_第21张图片

6. 资源文件

Qt 基础 详细总结_第22张图片

注:使用相对路径

Qt 基础 详细总结_第23张图片

1.1 将图片文件 拷贝到项目位置下

1.2 右键项目->添加新文件 –> Qt - > Qt recourse File - >给资源文件起名

1.3 res 生成 res.qrc

1.4 open in editor 编辑资源

1.5 添加前缀 添加文件

1.6 使用 “ : + 前缀名 + 文件名

七、对话框 QDialog

1. 基本概念

对话框通常会是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互

Qt 中使用QDialog类实现对话框。就像主窗口一样,我们通常会设计一个类继承QDialog

  • 顶层窗口:在任务栏会有自己的位置;

  • 非顶层窗口:则会共享其父组件的位置

下面的演示例子用到了lambda表达式

2.模态对话框

不可以对其他窗口进行操作(阻塞同一应用程序中其它窗口的输入)

  • 使用QDialog::exec()实现 应用程序级别 的模态对话框

  • 使用QDialog::open()实现 窗口级别 的模态对话框

窗口级别的模态依然允许用户与程序中其它窗口交互,窗口级别的模态尤其适用于多窗口模式

一般默认是 ” 应用程序级别的模态 “

例子:

Qt 基础 详细总结_第24张图片

exec()相当于阻塞

3. 非模态对话框

可以对其他窗口进行操作

  • 使用QDialog::show()实现 非模态对话框

例子:

Qt 基础 详细总结_第25张图片

Qt 基础 详细总结_第26张图片

注:

QDialog dialog(this)的方式,dialog是建立在上的(立刻消失)

QDialog *dialog=new QDialog;的方式,dialog是建立在上的(不会立刻消失),防止一闪而过

例子:

Qt 基础 详细总结_第27张图片

dlg2->setAttribute(Qt::WA_DeleteOnClose);//55号 属性 //避免内存泄漏

4.消息对话框(是 模态对话框)

(1)错误对话框

//消息对话框
    //错误对话框
    QMessageBox::critical(this,"critical","错误");

(2)信息对话框

//信息对话框
    QMessageBox::information(this,"info","信息");

(3)提问对话框

//提问对话框
//参数1  父亲  参数2  标题  参数3  提示内容  参数4 按键类型  参数5 默认关联回车按键
//QMessageBox::question 返回的类型是StandardButton,也是一个按键
    if (QMessageBox::Save  ==  QMessageBox::question(this,"ques","提问",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel))
    {
        qDebug() << "选择的是保存";

    }
    else
    {
        qDebug() << "选择的是取消";
    }

(4)警告对话框

//警告对话框
    QMessageBox::warning(this,"warning","警告");

(5)总结

1.1 标准对话框 – 消息对话框

​ 1.1.1 QMessageBox 静态成员函数 创建对话框

​ 1.1.2 错误、信息、提问、警告

​ 1.1.3 参数1 父亲 参数2 标题 参数3 显示内容 参数4 按键类型 参数5 默认关联回车按键

​ 1.1.4 返回值 也是StandardButton类型,利用返回值判断用户的输入

5. 其他标准对话框

(1)颜色对话框 QColorDialog::getColor

返回值QColor

//颜色对话框
//QColor color =  QColorDialog::getColor();//无参,默认(255,255,255)
QColor color =  QColorDialog::getColor(QColor(255,0,0));
qDebug() << "r = " << color.red() << " g = " << color.green() << " b  = " << color.blue() ;//打印R,G,B的值

(2)文件对话框 QFileDialog::getOpenFileName

QFileDialog::getOpenFileName(父亲,标题,默认路径,过滤文件)

返回值QString

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

(3)字体对话框 QFontDialog::getFont

返回值QFont

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

八、布局管理器

1. 界面布局(ui)

​ 1.1 实现登陆窗口

​ 1.2 利用布局方式 给窗口进行美化

​ 1.3 选取 widget 进行布局 ,水平布局、垂直布局、栅格布局

​ 1.4 给用户名、密码、登陆、退出按钮进行布局

​ 1.5 默认窗口和控件之间 有9间隙,可以调整 layoutLeftMargin

​ 1.6 利用弹簧进行布局

九、控件

1. 按钮组

常用的按钮:

  • QPushButton 常用按钮

  • QToolButton 工具按钮 用于显示图片;如图想显示文字,修改风格:toolButtonStyle,改成ToolButtonTextBesideIcon;

凸起风格autoRaise(透明状态)

  • radioButton 单选按钮,设置默认 ui->rBtnMan->setChecked(true);

  • checkbox 多选按钮,监听状态,2 选中 1 半选 0 未选中

例子:

(1)界面:

Qt 基础 详细总结_第28张图片

(2)代码:

Qt 基础 详细总结_第29张图片

2. QListWidget 列表容器

//利用listWidget写诗
//	QListWidgetItem * item = new QListWidgetItem("锄禾日当午");
//将一行诗放入到listWidget控件中
//	ui->listWidget->addItem(item);
//	item->setTextAlignment(Qt::AlignHCenter);//水平居中


//QStringList   QList
    QStringList list ;
//左移拼接
    list << "锄禾日当午" << "旱地和下土" << "谁知盘中餐"<< "粒粒皆辛苦";
    ui->listWidget->addItems(list);

总结:

1.1.1 QListWidgetItem * item 一行内容

1.1.2 ui->listWidget ->addItem ( item )

1.1.3 设置居中方式item->setTextAlignment(Qt::AlignHCenter);

1.1.4 可以利用addItems一次性添加整个诗内容

3. QTreeWidget 树控件

treeWidget树控件使用

//设置水平头
ui->treeWidget->setHeaderLabels(QStringList()<< "英雄"<< "英雄介绍");

QTreeWidgetItem * liItem = new QTreeWidgetItem(QStringList()<< "力量");
QTreeWidgetItem * minItem = new QTreeWidgetItem(QStringList()<< "敏捷");
QTreeWidgetItem * zhiItem = new QTreeWidgetItem(QStringList()<< "智力");
//加载顶层的节点
ui->treeWidget->addTopLevelItem(liItem);
ui->treeWidget->addTopLevelItem(minItem);
ui->treeWidget->addTopLevelItem(zhiItem);

//追加子节点
QStringList heroL1;
heroL1 << "AAA" << "aaaaaaaaaaaaaaaaa";
QTreeWidgetItem * l1 = new QTreeWidgetItem(heroL1);
liItem->addChild(l1);

总结:

1. 设置头 (只是在原有界面设置而已,所以不用new)

​ 1.1.1.1 ui->treeWidget->setHeaderLabels(QStringList()<< "英雄"<< "英雄介绍");

2. 创建根节点(新创建的,所以需要new)

​ 1.1.2.1 QTreeWidgetItem * liItem = new QTreeWidgetItem(QStringList()<< "力量");

3. 添加根节点 到 树控件上

​ 1.1.3.1 ui->treeWidget->addTopLevelItem(liItem);

4. 添加子节点(创建子结点,也需要new)

liItem->addChild(l1);

利用QStringList()<<"…" 左移实现添加字符串到List列表

4. QTableWidget 表格控件

//TableWidget控件

//设置列数
ui->tableWidget->setColumnCount(3);

//设置水平表头
ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"姓名"<< "性别"<< "年龄");

//设置行数
ui->tableWidget->setRowCount(5);

//设置正文
//ui->tableWidget->setItem(0,0, new QTableWidgetItem("亚瑟"));	//在这里new,创建匿名对象
QStringList nameList;
nameList<< "亚瑟"<< "赵云"<< "张飞"<< "关羽" << "花木兰";

QList<QString> sexList;
sexList << "男"<< "男"<< "男"<< "男"<< "女";

for(int i = 0 ; i < 5 ;i ++)
{
    int col = 0;
    ui->tableWidget->setItem(i,col++, new QTableWidgetItem(nameList[i]));
    ui->tableWidget->setItem(i,col++, new QTableWidgetItem(sexList.at(i)));
    //int 转 QString
    ui->tableWidget->setItem(i,col++, new QTableWidgetItem( QString::number(i+18)));
}

(1)使用QStringList() << “…”

(2)使用QStringList nameList;(nameList[i])

(3)使用QList < QString > sexList;(sexList.at[i])

运行截图:
Qt 基础 详细总结_第30张图片

5. 其他控件

(1)stackedWidget 栈控件

  • ui->stackedWidget->setCurrentIndex(0);
<1>scrollArea 按钮
<2>toolBox 按钮
<3>TabWidget 按钮

(2) comboBox 下拉框

  • ui->comboBox->addItem("奔驰");

(3)QLabel 显示图片

  • ui->lbl_Image->setPixmap(QPixmap(":/Image/butterfly.png"))

(4)QLabel 显示动图 gif图片

  • ui->lbl_movie->setMovie(movie);

  • movie->start();


//栈控件使用
        //设置默认定位 scrollArea
        ui->stackedWidget->setCurrentIndex(0);

        //scrollArea按钮
        connect(ui->btn_scrollArea,&QPushButton::clicked,[=](){
            ui->stackedWidget->setCurrentIndex(1);
        });

        //toolBox按钮
        connect(ui->btn_ToolBox,&QPushButton::clicked,[=](){
            ui->stackedWidget->setCurrentIndex(2);
        });

        //TabWidget按钮
        connect(ui->btn_TabWidget,&QPushButton::clicked,[=](){
            ui->stackedWidget->setCurrentIndex(0);
        });

效果:

Qt 基础 详细总结_第31张图片


//下拉框
        ui->comboBox->addItem("奔驰");
        ui->comboBox->addItem("宝马");
        ui->comboBox->addItem("拖拉机");

        //点击按钮 选中拖拉机选项
        connect(ui->btn_select,&QPushButton::clicked,[=](){
            //ui->comboBox->setCurrentIndex(2);
            ui->comboBox->setCurrentText("拖拉机");
        });

效果:

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


//利用QLabel显示图片
        ui->lbl_Image->setPixmap(QPixmap(":/Image/butterfly.png"));

        //利用QLabel显示 gif动态图片
        QMovie * movie = new QMovie(":/Image/mario.gif");
        ui->lbl_movie->setMovie(movie);
        //播放动图
        movie->start();

效果:

Qt 基础 详细总结_第32张图片

十、自定义控件

创建一个QT设计师界面类(.h .c .ui ),然后在这个新生成的 .ui 文件 里面自定义控件

(自定义控件 需要加载到主窗口中才能生效)

(在主窗口 widget.ui 里面点击“提升为”,粘贴“自定义控件对应的类名”)

(注意类型一致才可以提升成功)

(实际显示的窗口大小根据 widget.ui 设置的 widget 的大小决定,而不是 “自定义控件.ui” 里面的大小决定)

设置 自定义控件之间的联系,就是设置A控件发出的信号被B控件捕获,然后处理

(1)两个控件关联:

部分代码:

smallwidget.cpp:

	//QSpinBox移动,QSlider跟着移动
    //因为发出信号者的函数有重载,所以要写成函数指针形式
    void (QSpinBox::*spSignal)(int)=&QSpinBox::valueChanged;
    connect(ui->spinBox,spSignal,ui->horizontalSlider,&QSlider::setValue);

    //QSlider滑动  QSpinBox数字跟着改变
    //这个发出信号者没有重载,所以不用写函数指针
    connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);

效果:

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


(2)设置、获取(部分代码):

smallwidget.h:

void setnum(int num);//设置为50
    int getnum();//获取当前值

smallwidget.cpp:

//设置为50
//记得设置作用域
void smallwidget::setnum(int num){
    ui->spinBox->setValue(num);

}

//获取当前值
int smallwidget::getnum(){
    return ui->spinBox->value();

widget.cpp 连接(信号和槽)(将按钮和自定义控件关联):

    connect(ui->btn_set,&QPushButton::clicked,[=](){
       ui->widget->setnum(50); //同时设置QSpinBox和QSlider为50
    });

    connect(ui->btn_get,&QPushButton::clicked,[=](){
       qDebug()<<ui->widget->getnum();
    });

效果:

Qt 基础 详细总结_第33张图片

总结:

Qt 基础 详细总结_第34张图片

十一、Qt 中的鼠标事件

1.1 鼠标事件

1.2 鼠标进入事件 enterEvent

1.3 鼠标离开事件 leaveEvent

1.4 鼠标按下 mousePressEvent ( QMouseEvent ev)

1.5 鼠标释放 mouseReleaseEvent

1.6 鼠标移动 mouseMoveEvent

1.7 ev->x() x坐标 ev->y()y坐标

1.8 ev->button()可以判断所有按键 Qt::LeftButton Qt::RightButton

1.9 ev->buttons()判断组合按键 判断move时候的左右键 结合 & 操作符

1.10 格式化字符串 QString( “ %1 %2 ” ).arg( 111 ).arg(222)

1.11 设置鼠标追踪 setMouseTracking(true);

自定义控件 提升:类型一致才可以提升成功

自定义函数时注意加作用域

Qt 基础 详细总结_第35张图片

注意:

一定要将 ui 文件中的 Label 控件 从widget提升为QLabel,才能使鼠标事件与Label空间相关联。

mylabel.h:

#include
//记得这里改成public QLabel
class mylable : public QLabel
{
    Q_OBJECT
public:
    explicit mylable(QWidget *parent = nullptr);

    //鼠标进入事件
    void enterEvent(QEvent *event);

    //鼠标离开事件
    void leaveEvent(QEvent *);

    //鼠标按下(virtual 不写也行)
    virtual void mousePressEvent(QMouseEvent *ev);

    //鼠标释放
    virtual void mouseReleaseEvent(QMouseEvent *ev);

    //鼠标移动
    virtual void mouseMoveEvent(QMouseEvent *ev);

注:记得继承那里要改成public QLabel

mylabel.c:

#include
//记得这里改成QLabel(parent)
mylable::mylable(QWidget *parent) : QLabel(parent)
{

}
//鼠标进入事件
//记得设置作用域
void mylable::enterEvent(QEvent *event){
    qDebug()<<"鼠标进入了";
}

//鼠标离开事件
void mylable::leaveEvent(QEvent *){
    qDebug() << "鼠标离开了";
 }

//鼠标按下(实现时 virtual 不写)
//mousePressEvent是系统类
void mylable::mousePressEvent(QMouseEvent *ev){

    //当鼠标左键按下,提示信息
    if(ev->button()==Qt::LeftButton){
        QString str=QString("鼠标按下了 x=%1 , y=%2 ,global=%3 , global=%4 ").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug()<<str;
    }

}


//鼠标释放
//是系统类
void mylable::mouseReleaseEvent(QMouseEvent *ev){

        if( ev->button() ==  Qt::LeftButton)
        {
        QString str = QString( "鼠标释放了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());

        qDebug() << str;
        }

    }

//鼠标移动
//是系统类
void mylable::mouseMoveEvent(QMouseEvent *ev){
    if( ev->buttons() &   Qt::LeftButton )
    {
    QString str = QString( "鼠标移动了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());

    qDebug() << str;
   }
}

注:记得继承那里要改成QLabel(parent)

注:

因为有设置“提升为”,所以在自定义的类mylabel.c mylabel.h 里面设置就ok了,不用在去widget.c那里再设置信号和槽连接了。

十二、定时器

1、定时器1

(1)利用事件 void timerEvent ( QTimerEvent * ev) (系统函数)

(2)启动定时器 startTimer( 1000)毫秒单位

(3)timerEvent 的返回值是定时器的唯一标示 可以和 ev->timerId 做比较

widget.h

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    
//重写定时器的事件
void timerEvent(QTimerEvent *);

int id1; //定时器1的唯一标示
int id2; //定时器2的唯一标示

widget.c

// #include  //定时器类       在这个例子中用不到
#include 
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //第一种方式(不推荐)
    //启动定时器     (注意:启动定时器与获取id写在构造函数)
    id1 = startTimer(1000); //参数1  间隔  单位 毫秒

    id2 = startTimer(2000);

}

//专门处理定时器的函数(系统函数)
void Widget::timerEvent(QTimerEvent * ev)
{
    if(ev->timerId() == id1)
    {
        static int num = 1;
        
	//label2 每隔1秒+1
    ui->label_2->setText(  QString::number(num++));
	}

    if(ev->timerId() == id2)
    {
        //label3  每隔2秒 +1
        static int num2 = 1;
        ui->label_3->setText(  QString::number(num2++));
    }
}

2、定时器2

(1)利用定时器类 QTimer

(2)创建定时器对象 QTimer * timer = new QTimer(this)

(3)启动定时器 timer->start(毫秒)

(4)每隔一定毫秒,发送信号 timeout ,进行监听

(5)暂停 timer->stop

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include  //定时器类   (用于创建定时器对象)
#include 
#include 
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);


    //定时器第二种方式(使用 QTime 类)
    QTimer * timer = new QTimer(this);
    //启动定时器
    timer->start(500);//500ms

    connect(timer,&QTimer::timeout,[=](){
        static int num = 1;

        //label4 每隔0.5秒+1
        ui->label_4->setText(QString::number(num++));
    });


    //点击暂停按钮 实现停止定时器
    connect(ui->btn,&QPushButton::clicked,[=](){
        timer->stop();
    });

}

十三、event 事件分发 bool event( QEvent * e); 系统函数

Qt 基础 详细总结_第36张图片

mylabel.h

    //通过event事件分发器 拦截 鼠标按下事件
    bool event(QEvent *e);	//系统函数(但是也需要在 .h 文件声明,在.cpp中的实现相当于重写)

bool event(QEvent *e); //系统函数(但是也需要在 .h 文件声明,在.cpp中的实现相当于重写)

mylabel.cpp

bool myLabel::event(QEvent *e)
{
    //如果是鼠标按下 ,在event事件分发中做拦截操作
    if(e->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent * ev  = static_cast<QMouseEvent *>(e);
        
        QString str = QString( "Event函数中::鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug() << str;


        return true; //true代表用户自己处理这个事件,不向下分发
    }


    //其他事件 交给父类处理  默认处理方式
    return QLabel::event(e);//交给父类处理,mylabel的父类是QLabel
}

return QLabel::event(e);//交给父类处理,mylabel的父类是QLabel

(1)用途:用于事件的分发

(2)也可以做拦截操作,不建议

(3)bool event( QEvent * e);

(4)返回值 如果是true 代表用户处理这个事件,不向下分发了

(5)e->type() == 鼠标按下

十四、事件过滤器

(1) 在程序将时间分发到事件分发器前,可以利用过滤器做拦截

(2)步骤

  • 控件安装事件过滤器 (注意:在构造函数里面写)

  • 重写 eventFilter函数 (obj , ev)

widget.h

//重写事件过滤器的事件
    bool eventFilter(QObject *, QEvent *);

widget.cpp

#include //需要包含这个头文件
#include

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
 
    //给label1 安装事件过滤器
    // 步骤1  安装事件过滤器
    ui->label->installEventFilter(this);	//在构造函数中写


}



// 步骤2  重写 eventfilter事件
// 注意写作用域
//参数1:哪一个控件
//参数2:该控件的什么事件操作
bool Widget::eventFilter(QObject * obj , QEvent * e)
{
    if(obj == ui->label)
    {
        if(e->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent * ev  = static_cast<QMouseEvent *>(e);
            QString str = QString( "事件过滤器中::鼠标按下了 x = %1   y = %2  globalX = %3 globalY = %4 " ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
            qDebug() << str;
            return true; //true代表用户自己处理这个事件,不向下分发
        }
    }

    //其他默认处理
    return QWidget::eventFilter(obj,e);//交给父类处理,Widget的父类是Qwidget
}

return QWidget::eventFilter(obj,e);//交给父类处理,Widget的父类是Qwidget

十五、绘图事件

1、绘图基本操作

(1)绘图事件 void paintEvent()该函数是系统自动调用,如果没有重写该函数,系统则调用的该函数是空函数

(2)声明一个画家对象 QPainter painter(this) this指定绘图设备(不是指绘图窗口)

(3)画线、画圆、画矩形、画文字

(4)设置画笔 QPen 设置画笔宽度 、风格

(5)设置画刷 QBrush 设置画刷 风格

2、QPainter 高级设置

1.1 抗锯齿 效率低

​ 1.1.1 painter.setRenderHint(QPainter::Antialiasing);

1.2 对画家进行移动

​ 1.2.1 painter.translate(100,0);

​ 1.2.2 保存状态 save

​ 1.2.3 还原状态 restore

1.3 如果想手动调用绘图事件 利用update()

1.4 利用画家画图片 painter.drawPixmap( x,y,QPixmap( 图片路径 ) )

3、绘图设备

1 QPaintDevice绘图设备

​ 1.1 QPixmapQImageQBitmap(黑白色)QPictureQWidget

1.2 QPixmap 对不同平台做了显示的优化

​ 1.2.1 QPixmap pix( 300,300)

​ 1.2.2 pix.fill( 填充颜色 )

​ 1.2.3 利用画家 往pix上画画 QPainter painter( & pix)

​ 1.2.4 保存 pix.save( “路径”)

1.3 Qimage 可以对像素进行访问

​ 1.3.1 使用和QPixmap差不多 QImage img(300,300,****QImage::Format_RGB32****);

​ 1.3.2 其他流程和QPixmap一样

​ 1.3.3 可以对像素进行修改 img.setPixel(i,j,value);

1.4 QPicture 记录和重现 绘图指令

​ 1.4.1 QPicture pic

​ 1.4.2 painter.begin(&pic);

​ 1.4.3 保存 pic.save( 任意后缀名 )

​ 1.4.4 重现 利用画家可以重现painter.drawPicture(0,0,pic);

十六、QFile 文件读写操作

1、总结:

(1) QFile进行读写操作

(2) QFile file( path 文件路径)

(3)读

​ 1.3.1 file.open(打开方式) QIODevice::readOnly

​ 1.3.2 全部读取 file.readAll()按行读 file.readLine()atend()判断是否读到文件尾

​ 1.3.3 默认支持编码格式 utf-8

​ 1.3.4 利用编码格式类 指定格式 QTextCodeC

​ 1.3.5 QTextCodec * codec = QTextCodec::codecForName("gbk");

​ 1.3.6 ui->textEdit->setText( codec->toUnicode(array) ); //gbk

​ 1.3.7 文件对象关闭 close

(4)写

​ 1.4.1 file.open( QIODevice::writeOnly / Append)

​ 1.4.2 file.write(内容)

​ 1.4.3 file.close关闭

(5)QFileInfo 读取文件信息

​ 1.1 QFileInfo info(路径)

​ 1.2 qDebug() << “大小:” << info.size() << " 后缀名:" << info.suffix()<< " 文件名称:"<

​ 1.3 qDebug() << "创建日期:" << info.created().toString("yyyy/MM/dd hh:mm:ss");

​ 1.4 qDebug() << "最后修改日期:"<

2、头文件

(1)#include < QFileDialog > 读取路径

(2)#include < QFile > 读取内容

(3)#include < QTextCodec > 编码格式

(4)#include< QFileInfo >

(5)#include< QDateTime >

3、代码

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 
#include 
#include 
#include 
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击选取文件按钮,弹出文件对话框

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

        QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\w1396\\Desktop");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //编码格式类
        //QTextCodec * codec = QTextCodec::codecForName("gbk");

        //读取内容 放入到 textEdit中
        // QFile默认支持的格式是 utf-8
        QFile file(path); //参数就是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

        //QByteArray array = file.readAll();

        QByteArray array;
        while( !file.atEnd())//文件尾
        {
            array += file.readLine(); //按行读
        }

        //将读取到的数据 放入textEdit中
        ui->textEdit->setText(array);//utf-8
        //ui->textEdit->setText( codec->toUnicode(array)  );//gbk

        //对文件对象进行关闭
        file.close();


        //进行写文件
//        file.open(QIODevice::Append); //用追加方式进行写
//        file.write("啊啊啊啊啊");
//        file.close();



        //QFileInfo 文件信息类
        QFileInfo info(path);

        qDebug() << "大小:" << info.size() << " 后缀名:" << info.suffix() << " 文件名称:"<<info.fileName() << " 文件路径:"<< info.filePath();
        qDebug() << "创建日期:" << info.created().toString("yyyy/MM/dd hh:mm:ss");
        qDebug() << "最后修改日期:"<<info.lastModified().toString("yyyy-MM-dd hh:mm:ss");
    });

}

Widget::~Widget()
{
    delete ui;
}

十七、开发注意事项

1、每一个场景写一个类(.c、.h)

2、实现方法相同的控件(系统自带控件/自定义控件)写在同一个类的不同方法(定义多个成员函数)

3、自定义控件的触发需要自定义一个信号发送出去、系统控件的触发不需要自定义信号

(注意:信号只需要声明,不需要实现)

4、一些操作写在构造函数里面,然后在创建那个对象的时候直接就把构造函数里面的语句执行了。

5、设置 bool 类型的属性的时候要给个默认值,否则有可能会出错。

6、设置不同界面切换位置一致 。

在 ”跳转“ 和 ”监听返回“ 两个地方都要设置。

7、项目打包,将qt左下角的…修改为Release模式,然后编译并运行,然后去到该项目文件夹将.exe文件复制粘贴到任意一个新的文件夹中,然后在该文件夹下打开命令行窗口,输入 windeployqt 项目名称 然后回车,就可以看到刚刚创建的文件夹生成了很多配置文件之类的,将该文件夹发给其他人,其他人可以正常打开里面的.exe,运行项目。

如果想发布生成一个更美观的更完整的 ”应用程序“ ,可以使用第三方的工具进行发布。

你可能感兴趣的:(Qt 基础 详细总结)