什么是类和对象:
1.C++中的类是一种构造类型,与C语言的结构体类似(数据类型),但进行了一些扩展,类的成员不但可以是变量还可以是函数,通过类定义出来的变量也有特定的称呼叫做对象;
2.类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量,创建对象的过程也叫做类的实例化;
类的定义:
class 类名(首写字母是大写)
{
public: //如果不写关键字,默认类成员为public类型
公有的数据;
protected:
保护的数据;
private:
私有的数据;
};
cpp
#include <iostream>
using namespace std;
class Dog
{
public:
string name;
int age;
void run(){
cout<<"小狗的名字是:"<<name<<","<<"年龄是"<<age<<endl;
}
};
int main()
{
Dog dog1;
//从栈中实例化对象
dog1.name = "王才";
dog1.age = 2;
dog1.run();
//从堆中实例化对象
//从堆中实例化的对象必须使用delete关键字删除,否则会造成内存泄漏
Dog *dog2 = new Dog; //定义指向Dog类型的指针,使用new关键字在堆中分配空间,在堆内存中创建一个Dog类的对象
dog2->age = 3;
cout << dog2->age <<endl;
//delete dog2; //需要手动删除
return 0;
}
/*执行结果
小狗的名字是:王才,年龄是2
3
*/
构造函数与析构函数:
构造函数:定义了一个名称和类名相同但没有返回值的函数,构造函数在类被实例化的时候调用;
class Dog
{
public:
Dog();//构造函数
};
析构函数:对象实例化的时候,会调用构造函数,对象销毁时,会调用析构函数;
class Dog
{
public:
~Dog();//析构函数
};
在类实例化对象的时候,如果没有定义构造函数,则编译器会合成一个默认的构造函数。当有了对象后,如果没有定义析构函数,则编译器会合成一个默认的析构函数;
cpp
#include <iostream>
using namespace std;
class Dog
{
public:
Dog() //构造函数定义
{
cout << "构造函数被执行" << endl;
};
~Dog();
};
/* 作用域解析运算符 :: 在这里用于明确指出~Dog()这个析构函数属于Dog类,它将析构函数的定义与Dog类关联起来 */
Dog::~Dog() //析构函数定义,可以在类定义外定义析构函数
{
cout << "析构函数被执行" << endl;
}
int main()
{
/* 会先调用构造函数,接着调用析构函数 */
//Dog dog1; //在栈中实例化类
/* 在堆中实例化类,如果没有手动delete对象,则不会调用析构函数,只会调用构造函数 */
Dog *dog2 = new Dog; //在堆中实例化类
delete dog2; //执行了该语句后才会调用析构函数
return 0;
}
/*执行结果
构造函数被执行
析构函数被执行
*/
类的继承:
创建类的时候,并不需要创建全新的数据和成员函数,我们可以指明这个新类继承现有类的成员;
继承类的对象与成员对基类成员的访问权限:
1.共有继承时基类各成员属性保持不变,基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected,而不能访问private成员,派生类的对象只能访问基类中的public成员;
2.保护继承时基类各成员属性均变成protected,基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected,而不能访问private成员,派生类的对象不能访问基类中的任何成员;
3.私有继承时基类各成员属性均变成private,基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected,而不能访问private成员,派生类的对象不能访问基类中的任何成员;
cpp
#include <iostream>
using namespace std;
//基类,也叫父类
class Animal
{
public:
string name;
int age;
void run()
{
cout << "狗的年龄:" << age << endl;
}
};
//派生类,也叫子类
class Dog : public Animal //此时为公有继承,改变关键字public更改继承方式
{
};
int main()
{
Dog Dog1;
Dog1.age = 3;
Dog1.run();
return 0;
}
/*执行结果
狗的年龄:3
*/
函数重载:
在同一作用域内,声明几个功能类似的同名函数,并且这些同名函数的参数个数、参数类型或者参数顺序不同,或者函数返回类型不同,那么就叫函数重载;
cpp
#include <iostream>
using namespace std;
class Dog
{
public:
void getweight(int weight)
{
cout << "int类型狗的体重:" << weight << endl;
}
void getweight(double weight)
{
cout << "double类型狗的体重:" << weight << endl;
}
};
int main()
{
Dog Dog1;
Dog1.getweight(10);
Dog1.getweight(10.2);
return 0;
}
/*执行结果
int类型狗的体重:10
double类型狗的体重:10.2
*/
以上是C++基础------------------------------------------------------------------------------------
Qt中的快捷键:
头文件和源文件的切换,F4
对齐代码,ctrl + a ctrl + i
运行项目,ctrl + r
查看类型层次,ctrl + shift + T
Qt信号槽连接模型:
发送者(对象)->信号(函数)->接收者(对象)->槽(函数)
发送者连接一个动作信号作用于接收者然后执行槽函数;
例:UI上面的一个按钮(发送者)执行点击动作,作用于mainwindow(接受者)执行关闭函数(槽);
自定义信号和槽:
1.信号只需要定义不需要声明,但是槽需要定义加声明否则会报错;
2.同一个信号可以连接多个不同的槽;
在构造函数中实例化对象,this的作用:
在这个对象实例化的场景中,this就代表当前对象的内存地址;
cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
school = new School(this); //在构造函数中实例化对象
student = new Student(this); /*创建Student类的实例(student对象)时,将当前MainWindow对象的地址作为参
数传递给Student类的构造函数。this是当前正在被创建或初始化的MainWindow对象的内存地址。*/
connect(school, SIGNAL(sendMessages()), student, SLOT(ComeBackToClass())); //创建信号槽的连接
emit school->sendMessages(); //发送信号的关键字
}
样式表的使用:
在.ui文件中选中想要修改的目标,右键选择更改样式表,在帮助手册索引style,然后选择sytlesheet(小写),参考手册添加样式表内容;
.qss文件的使用:
是对应.qrc文件下创建的子文件(右键.qrc创建.qss),该文件存放所修改样式的代码,样式的修改代码可以写在源文件中,也可以写在.qss文件中;
需要在mainwindow文件中写下面的代码来找到.qss文件
cpp
QFile file(":/style.qss");
/* 判断文件是否存在 */
if (file.exists() ) {
/* 以只读的方式打开 */
file.open(QFile::ReadOnly);
/* 以字符串的方式保存读出的结果 */
QString styleSheet = QLatin1String(file.readAll());
/* 设置全局样式 */
qApp->setStyleSheet(styleSheet);
/* 关闭文件 */
file.close();
使用radioButton控件,单选按钮:
同一按钮组中的选择是互斥的,可通过选中按钮划分到不同的按钮组改变互斥的情况;
选中按钮组,取消勾选互斥选项(exclusive),使同一按钮组中可以选中多个按钮;
复选按钮:
在.ui文件中放置CheckBox控件,选中该控件在属性栏勾选三态(tristate)选项即可开启选中(checked)/未选中(unchecked)
/半选中(partiallyChecked)三种状态(不常用);
margin&padding(外边距与内边距):

样式表内容:
cpp
QPushButton{
margin:50px; //外边框50像素点宽度
background-color:#CDCDB4; //背景颜色(rgb表中的十六进制数对应的颜色)
border-width:50px; //边框宽度
border-color:#458B00 //边框颜色
border-style:solid; //固态填充边框颜色
padding:100px; //内边框宽度,即字符到外边框的距离
}
执行结果:

在help中查找stylesheet(注意是小写的)中的Qt Style Sheets Reference,在其中找到控件的属性;
margin&padding(外边距与内边距):
样式表内容:
QPushButton{
margin:50px;
background-color:#CDCDB4;
border-width:50px;
border-color:#458B00
border-style:solid;
padding:100px;
}
水平布局与垂直布局(QHBoxlayout&QVBoxlayout):
在布局属性界面调整layoutSpacing(同一布局下控件的间隔距离)和layoutStretch(同一布局下控件拉伸比例)的数值,在控件属性界面调整sizePolicy(内容可在帮助文档中查看)的数值;
若想要Widget内的控件随Widget的拉伸同步变化,需在Widget的源文件中添加 this->setLatout(ui->horizontalLayout);
分裂器(QSplitter):
在Containers中选择两个Widget控件,放置在一个分裂器中,在分裂器的属性中调整下面的内容,
1.orientation:设置方向,可设置水平方向和垂直方向;
2.opaqueResize:为false(不勾选)时,在拖动的时候会显示一条灰色的线条(可通过在样式表中改变分裂器背景颜色改变线条颜色),在拖动到位并释放鼠标后再显示分割线。默认为true,实时更新子控件大小;
3.childrenCollapsible:为true时,用户可以将子部件的大小调整为;
注意:只调整了.ui 文件的控件布局、属性,未修改任何.cpp/.h 代码,且右键.ui文件执行 "Compile" 无效,需要手动构建(Build)。
由于嵌入式屏幕有限,很少用到这个;
手动构建(小锤子)(Build):
手动构建的核心使用场景:自动构建失效、需要清除缓存、切换构建环境、排查构建错误。自动构建是运行的一部分;
隔离弹簧(QSpacerltem):
在QSpacerltem的属性:
orientation:方向属性,可设置水平或垂直方向;
sizeType:大小属性,如fixed、expanding;
sizeHint:缺省大小,也就是默认大小;
注意:隔离弹簧是放置在布局Latouts控件中的;
QLineEdit(可输入文本的对话框):
可输入文本,例如密码的输入GUI,通过改变ecohModee属性可以将输入的文本隐藏;
创建Dialog项目如何变成圆角矩形:
由于QDialog没有radius的属性,可以在Dialog上面加一个有radius属性的比如Frame,将Dialog改为
//无边框
setWindowFlag(Qt::FramelessWindowHint);
//透明属性
setAttribute(Qt::WA_TranslucentBackground);
将Frame改为圆角矩形,将二者大小改为相同即可。
滚动视觉效果:
scorllArea控件,样式表如何更改参考stylesheet中的Reference中的内容,包括水平滑块、垂直滑块、滑块两端的箭头的样式;
面板切换效果(QTabWidget + ListView):
两个控件通过槽联系ui->tabWidget->setCurrentIndex(currentRow),QTabWidget的Tabposition属性改变标签的位置,ListView的focusPolicy属性是否显示item的上的边框;
QTabWidget stylesheet:
QTabWidget{border:none} //无边框
QTabBar::tab{width:0px;heigh:0px} //隐藏标签
ListView stylesheet:
QListView{background-color:#dddddd;border:none}
QListView::item{height:50px} //点击框的高度
QListView::selected{background-color:white;color:black} //点击框中背景颜色和文字颜色
listWidget控件:
在.ui文件中双击该控件添加item或在源文件中执行下面操作,
ui->listWidget->addItem("张三"); //在widget源文件中添加item,
ui->listWidget->takeItem(0); //移除项
ui->listWidget->insertItem(0,"张三"); //插入项,从所选项的前面插入
对Ui::Dialog *ui;的解释:
Dialog是在创建项目时由用户选择的基类,编译器会生成对应的初始化相应控件代码;
ui是指向Ui::Dialog这个类的指针,在Dialog的构造函数中会进行ui的初始化,即 ui = new Ui::Dialog; 这一步骤通过ui指针,就可以调用Ui::Dialog类的setupUi函数来完成用户界面的设置,以及访问其中与各个控件对应的成员变量,进而实现对用户界面控件的操作。
在调用函数时将当前对象作为参数传递给setupUi函数 ui->setupUi(this);
对于Ui::Dialog这个类,随着对dialog.ui文件进行添加控件操作,Ui::Dialog这个类会增加相应控件的成员变量和相关设置代码:
在Forms文件夹下创建多个类时注意:
ui->setupUi(this);在哪个类的源文件中注释掉这句,在运行后才能单独显示没有注释这句的类的控件;
例如:
创建Widget和QQitem(类名)这两个类,想要在widget的源文件下调用qqitem,首先要在widget的源文件中声明 class QQItem;
创建这个类的指针 QQItem *qqItem = new QQItem(QIcon(":/on.png"), "在线", "张三"); 才是合法的,同时还要包含头文件 #include "qqitem.h",指针保存 QQItem 对象的内存地址,方便后续操作该对象;
执行 QQItem *qqItem = new QQItem(QIcon(":/on.png"), "在线", "张三");
↓
步骤1:new 关键字在堆上为 QQItem 对象分配足够的内存空间(大小由 QQItem 类定义决定)
↓
步骤2:new 关键字调用 QQItem 对应的带参构造函数,将传入的图标、文字等参数赋值给对象的成员变量,完成对象初始化(保留配置成果)
↓
步骤3:new 关键字将堆上 QQItem 对象的内存起始地址作为返回值
↓
步骤4:将该内存地址赋值给指针 qqItem(指针保存地址,方便后续操作对象)
↓
步骤5:构造函数执行完毕,完成使命并"退场",后续无法访问
↓
后续操作:通过 qqItem 保存的地址,找到堆上已初始化完成的 QQItem 对象,使用它的配置成果(如绑定到 QListWidget、修改属性等)
文本读写流程:
1.打开文件->打开文本QFileDialog::getOpenFileName返回的时一个字符串,包括路径+文件名,使用open()方法打开文本;
2.读写文本
readAll(),readLine(),write()
3.关闭文本
close()
对于this->update()的解释:
非常重要
this->update() 通常用于请求重绘当前的 QWidget 或其子类对象所代表的区域。例如在文字轮播的ui设计中,每次文字偏移量的改变都需要调用这句代码对当前区域进行重绘;
.ui文件对控件的提升(promot to):
"提升" 是指将 Qt Designer 中从标准控件库拖放的普通控件,替换为用户自定义的控件类。替换包括名称的替换和控件功能的改变,是一种自定义行为。
比如想在.ui文件中放置QChartView,但是没有这个控件,但是QChartView这个类继承GraphicsView这个类,.ui中有GraphicsView这个控件,就可以放置GraphicsView这个控件然后右键对这个控件提升为QChartView;
Qt中的命名空间:
是一种分组机制,避免不同类成员中存在相同的命名而冲突。
QT_CHARTS_USE_NAMESPACE是一个预处理宏,用于简化在使用Qt Charts模块时对命名空间的引用,就可以直接使用Qt Charts 模块中的类,而无需显式写出QtCharts命名空间前缀;
tcpSocket = new QTcpSocket(this);
在构建对象时向所构建对象的构造函数传入this这个参数,表示当前类对象作为所构建对象的父对象,因为当父对象被销毁时,它会递归销毁所有子对象。这样可以避免内存泄漏,不需要你手动调用 delete tcpSocket。
程序异常:
存在有些指针还在使用但立刻被删除的情况导致程序异常,可以使用deleteLater()方法(Schedules this object for deletion);
TCP通信:
客户端和服务端的socket是用来收发数据的,服务端的server是用来监听是否有客户端需要连接的;
I.MX6U交叉编译Qt项目(使用命令行):
1.在交叉编译前要在虚拟机上执行下面的指令,配置好针对 ARM Cortex-A7 架构的交叉编译环境,让你能直接编译出可在 NXP i.MX 开发板上运行的程序;
source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
2.先在.pro目录下执行 qmake 命令(该命令是Qt专属的Makefile生成器),然后在该目录下执行 make 命令(该命令基于Makefile文件工作);make clean 命令删除 make 命令生成的可执行文件;
3.拷贝文件到开发板,在虚拟机上执行:
scp 文件 用户名@ip地址:路径
拷贝文件夹:
scp -r 文件夹 用户名@ip地址:路径
Qt使用开发板上的按键:
开发板的内核驱动会给开发板上的按键编码(在内核设备树的源码中查看编码),而在Qt平台也对键盘上的按键进行编码,在Qt的编程中去操作与内核驱动相同编码的键盘按键,再烧写到开发板之后就会操作编码相同的开发板上的按键;
在nat网络模式下不同的网络段实现主机与虚拟机的tcp通信:
在虚拟机的Nat设置中添加主机的端口号2222,在Winscp的登录页面主机名填写主机的回环ip127.0.0.1,端口号写2222,利用主机回环 IP + 端口转发,让主机通过 NAT 间接访问虚拟机;