复制粘贴自
https://github.com/0voice/qt_interview_reference.git
1、讲述Qt信号槽机制与优势与不足
优点: ①类型安全。需要关联的信号槽的签名必须是等同的。即信号的参数类型和参数个数同接受该信号的槽的参数类型和参数个数相同。若信号和槽签名不一致,编译器会报错。
②松散耦合。信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是那个对象的那个信号槽接收它发出的信号,它只需在适当的时间发送适当的信号即可,而不需要关心是否被接受和那个对象接受了。Qt就保证了适当的槽得到了调用,即使关联的对象在运行时被删除。程序也不会奔溃。
③灵活性。一个信号可以关联多个槽,或多个信号关联同一个槽。
**不足:**速度较慢。与回调函数相比,信号和槽机制运行速度比直接调用非虚函数慢10倍。
原因:①需要定位接收信号的对象。②安全地遍历所有关联槽。③编组、解组传递参数。④多线程的时候,信号需要排队等待。(然而,与创建对象的new操作及删除对象的delete操作相比,信号和槽的运行代价只是他们很少的一部分。信号和槽机制导致的这点性能损耗,对实时应用程序是可以忽略的。)
2、Qt信号和槽的本质是什么
Qt信号和槽是一种用于实现对象间通信的机制。其本质是一种事件驱动的机制,通过信号和槽的连接,当信号被触发时,槽函数会被自动调用,从而实现对象间的通信和交互。 信号是一种特殊的函数,用于表示某种事件的发生,当事件发生时,信号会被自动发送出去,通知所有连接到该信号的槽函数。 槽是一种特殊的函数,用于处理信号的触发事件,当槽函数被连接到某个信号时,当该信号被触发时,槽函数会自动被调用,从而实现对信号的响应。 信号和槽的连接是通过Qt的元对象系统实现的,每个QObject派生类都有一个元对象,用于存储该类的属性、方法和信号槽信息。通过元对象系统,可以在运行时动态地连接信号和槽,从而实现对象间的通信。 总之,Qt信号和槽是一种事件驱动的机制,通过信号和槽的连接,实现了对象间的通信和交互。
3、描述Qt中的文件流(QTextStream)和数据流(QDataStream)的区别
在Qt中,QTextStream和QDataStream都是用于读写数据的类,但它们的使用场景和读写的数据类型不同。 QTextStream是用于读写文本数据的类,可以将QString、QByteArray等文本数据以类似于流的方式读写到文件、套接字等设备中。QTextStream提供了一系列方便的方法,如readLine()、readAll()、operator<<()、operator>>()等,可以方便地读写文本文件和套接字等设备。 QDataStream是用于读写二进制数据的类,可以将各种类型的二进制数据(如int、float、double、QString等)以二进制方式读写到文件、套接字等设备中。QDataStream通过内部的序列化机制实现了数据的高效读写,可以保证在不同平台上的数据兼容性。QDataStream提供了一系列方便的方法,如writeRawData()、writeInt()、readRawData()、readInt()等,可以方便地读写二进制文件和套接字等设备。 因此,QTextStream和QDataStream的主要区别在于它们所处理的数据类型不同,QTextStream主要处理文本数据,而QDataStream主要处理二进制数据。在使用时,需要根据实际情况选择合适的类进行读写操作。
4、描述Qt的TCP通讯流程
服务端:(QTcpServer)
①创建QTcpServer对象
②监听list需要的参数是地址和端口号
③当有新的客户端连接成功回发送newConnect信号
④在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象
⑤连接QTcpSocket对象的readRead信号
⑥在readRead信号的槽函数使用read接收数据
⑦调用write成员函数发送数据
客户端:(QTcpSocket)
①创建QTcpSocket对象
②当对象与Server连接成功时会发送connected 信号
③调用成员函数connectToHost连接服务器,需要的参数是地址和端口号
④connected信号的槽函数开启发送数据
⑤使用write发送数据,read接收数据
5、 描述UDP 之 UdpSocket通讯
UDP(User Datagram Protocol即用户数据报协议)是一个轻量级的,不可靠的,面向数据报的无连接协议。在网络质量令人十分不满意的环境下,UDP协议数据包丢失严重。由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。所以QQ这种对保密要求并不太高的聊天程序就是使用的UDP协议。
在Qt中提供了QUdpSocket 类来进行UDP数据报(datagrams)的发送和接收。Socket简单地说,就是一个IP地址加一个port端口 。
流程:①创建QUdpSocket套接字对象 ②如果需要接收数据,必须绑定端口 ③发送数据用writeDatagram,接收数据用 readDatagram 。
6、多线程使用使用方法
方法一:①创建一个类从QThread类派生②在子线程类中重写 run 函数, 将处理操作写入该函数中 ③在主线程中创建子线程对象, 启动子线程, 调用start()函数
方法二:①将业务处理抽象成一个业务类, 在该类中创建一个业务处理函数②在主线程中创建一QThread类对象 ③在主线程中创建一个业务类对象 ④将业务类对象移动到子线程中 ⑤在主线程中启动子线程 ⑥通过信号槽的方式, 执行业务类中的业务处理函数
多线程使用注意事项:
* 1. 业务对象, 构造的时候不能指定父对象
* 2. 子线程中不能处理ui窗口(ui相关的类)
* 3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口
7、多线程下,信号槽分别在什么线程中执行,如何控制
可以通过connect的第五个参数进行控制信号槽执行时所在的线程
connect有几种连接方式,直接连接和队列连接、自动连接
直接连接(Qt::DirectConnection):信号槽在信号发出者所在的线程中执行
队列连接 (Qt::QueuedConnection):信号在信号发出者所在的线程中执行,槽函数在信号接收者所在的线程中执行
自动连接 (Qt::AutoConnection):多线程时为队列连接函数,单线程时为直接连接函数。
8、自定义控件流程
继承需要自定义的控件类,如QPushButton;从外观设计上:QSS、继承绘制函数重绘、继承QStyle相关类重绘、组合拼装等等;从功能行为上:重写事件函数、添加或者修改信号和槽等等。
9、对QObject的理解
QObject 类是Qt 所有类的基类。
QObject是Qt对象模型的核心。这个模型的中心要素就是一种强大的叫做信号与槽无缝对象沟通机制。你可以用 connect() 函数来把一个信号连接到槽,也可以用disconnect() 函数来破坏这个连接。为了避免永无止境的通知循环,你可以用blockSignal() 函数来暂时阻塞信号。保护函数 connectNotify() 和 disconnectNotify() 可以用来跟踪连接。
对象树都是通过QObject 组织起来的,当以一个对象作为父类创建一个新的对象时,这个新对象会被自动加入到父类的 children() 队列中。这个父类有子类的所有权。能够在父类的析构函数中自动删除子类。可以通过findChild()和findChildren() 函数来寻找子类。
每个对象都一个对象名称objectName() ,而且它的类名也可以通过metaObject()函数。你可以通过inherits() 函数来决定一个类是否继承其他的类。当一个对象被删除时,它会发射destory() 信号,你可以抓住这个信号避免某些事情。
对象可以通过event() 函数来接收事情以及过滤来自其他对象的事件。就好比installEventFiter() 函数和eventFilter() 函数。childEvent() 函数能够重载实现子对象的事件。
QObject还提供了基本的时间支持,QTimer类 提高了更高层次的时间支持。
任何对象要实现信号与槽机制,Q_OBJECT 宏都是强制的。你也需要在源原件上运行元对象编译器。不管是否真正用到信号与槽机制,最好在所有QObject子类使用Q_OBJECT宏,以避免出现一些不必要的错误。
所有的Qt widgets 都是基础QObject。如果一个对象是widget,那么isWidgetType()函数就能判断出。
10、Qt自定义一个信号槽,触发这个信号,Qt多个信号如何关联一并处理
第一种方法:
在发送信号时,也发送一个int类型数字,或者说标志,这样在槽函数触发是可以知道是哪个信号发出的;
第二种方法:
在槽函数内有获取发送信号的函数,通过sender()函数获取发送信号;
11、Qt如果一个信号的处理方法一直未被执行有哪些可能性
1.断开了
2.连接的时候失败了
3.多线程的时候在排队或者启动锁死了。
12、在Qt5的信号处理中如何使用lambda机制(可以代码示例)
信号定义了,但是不写对应槽函数,直接将函数写到槽的位置。
connect(musicPlayer,SIGNAL(positionChanged(qint64)),this,SLOT(slotReflushStartTime(qint64)));
connect(musicPlayer,SIGNAL(positionChanged(qint64)),slotReflushStartTime(qint64));
直接就是将对象都不写了,直接写个函数。
15、Qt 三大核心机制
信号槽
信号槽的五种连接方式(图略)
connect(信号发出者,信号,信号接收者,槽,连接方式(隐藏默认自动连接))//五个参数
元对象系统
元对象系统分为三大类:QObject类、Q_OBJECT宏和元对象编译器moc
Qt的类包含Q_OBJECT宏 moc编译器会对该类编译成标准的C++代码
事件模型
事件的创建
鼠标事件,键盘事件,窗口调整事件,模拟事件
事件的交付
Qt通过调用虚函数QObject::event()来交付事件。
事件循环模型
主事件循环通过调用QCoreApplication::exec()启动,
随着QCoreApplication::exit()结束,
本地的事件循环可用利用QEventLoop构建。
一般来说,事件是由触发当前的窗口系统产生的,但也可以通过使用 QCoreApplication::sendEvent()和
QCoreApplication::postEvent()来手工产生事件。需要说明的是QCoreApplication::sendEvent()会立即发送事件, QCoreApplication::postEvent()则会将事件放在事件队列中分发。
自定义事件
16、Qt对象树
QT提供了对象树机制,能够自动、有效的组织和管理继承自QObject的对象。
每个继承自QObject类的对象通过它的对象链表(QObjectList)来管理子类对象,当用户创建一个子对象时,其对象链表相应更新子类对象的信息,对象链表可通过children()获取。
当父类对象析构的时候,其对象链表中的所有(子类)对象也会被析构,父对象会自动,将其从父对象列表中删除,QT保证没有对象会被delete两次。开发中手动回收资源时建议使用deleteLater代替delete,因为deleteLater多次是安全的。
17、描述QTextStream(文件流)和QDataStram(数据流)的区别
文本流用来操作轻量级的数据,比如内置的int、QString等,写入文件后以文本的方式呈现
数据流,可以操作各种类型数据
总之,两者都可以进行操作磁盘文件以及内存数据。
18、信号槽的四种写法和五种连接方式?
connect(信号发出者,信号,信号接收者,槽,连接方式(隐藏默认自动连接))//五个参数
四种写法:
1.用宏: connect(this,SIGNAL(clicked()),this,SLOT(colse())); //连接方式(隐藏默认自动连接))
2.用函数指针: connect(this,&mainwindow::my_signal,this,&mainwindow::my_slot);
3.用重载函数指针Qoverload connect(this,Qoverload<参数>::of(&mainwindow::my_signal),this,Qoverload<参数>::of(&mainwindow::my_slot));
4.lambda表达式(匿名函数) 匿名函数代替槽 connect(this,&mainwindow::my_signal,this,[=]{qDebug()<<100;}); 连接方式:自动连接(默认连接方式) 直接连接(用于单线程,自动匹配) 队列(用于多线程也可用于单线程,自动匹配) 阻塞队列(跨线程,多线程) 唯一连接(跨线程,多线程)
40、Qt程序是事件驱动的,事件到处都可以遇到。能说说平时经常使用到哪些事件吗?
常见的QT事件类型如下:
键盘事件: 按键按下和松开 鼠标事件: 鼠标移动,鼠标按键的按下和松开
拖放事件: 用鼠标进行拖放 滚轮事件: 鼠标滚轮滚动
绘屏事件: 重绘屏幕的某些部分 定时事件: 定时器到时
焦点事件: 键盘焦点移动 进入和离开事件: 鼠标移入widget之内,或是移出
移动事件: widget的位置改变 大小改变事件: widget的大小改变
显示和隐藏事件: widget显示和隐藏 窗口事件: 窗口是否为当前窗口
114、Qt如何操作数据库
Qt操作数据库主要是使用Qt的QSqlDatabase类,它提供了一系列的函数来连接、操作、查询和管理数据库。在Qt中,可以使用QSqlQuery类来查询数据库,QSqlTableModel类来操作数据库表,QSqlRelationalTableModel类来管理关系数据库表,QSqlError类来检测错误,QSqlDriver类来检查数据库驱动程序,QSqlIndex类来创建索引,QSqlRecord类来操作数据库记录,QSqlResult类来执行查询等等。
151、Qt信号槽机制的优点及缺点?
Qt信号槽机制是一种事件驱动的编程模型,它的优点和缺点如下:
优点:
松耦合:信号槽机制可以实现组件之间的松耦合,组件之间不需要直接相互调用,只需要通过信号和槽进行通信即可,这样可以降低组件之间的耦合度,提高代码的复用性和可维护性。
灵活性:信号槽机制可以实现非常灵活的事件处理,可以动态的连接和断开信号和槽,可以在运行时动态修改信号和槽的参数等。
易于扩展:信号槽机制可以非常容易地扩展新的事件和处理逻辑,只需要定义新的信号和槽即可,无需修改原有代码。
跨线程:信号槽机制可以支持跨线程的事件处理,可以将信号和槽连接在不同的线程中,这样可以实现线程之间的通信。
缺点:
性能:信号槽机制的性能相对于直接调用函数来说会有一定的开销,因为它需要进行信号的发射和槽的执行,而且还需要维护信号槽的连接关系。
调试:由于信号槽机制是基于事件驱动的编程模型,因此调试起来可能会比较困难,特别是在信号和槽之间存在多层嵌套的情况下。
安全性:由于信号槽机制可以动态连接和断开信号和槽,因此在使用时需要注意安全性问题,避免出现槽函数被误调用的情况。 总的来说,Qt信号槽机制是一种非常灵活和方便的事件驱动编程模型,它的优点在于松耦合、灵活性、易于扩展和跨线程等方面,但是在性能、调试和安全性等方面需要注意一些问题。
160、 QString与基本数据类型如何转换?
在Qt中,QString与基本数据类型之间可以进行方便的相互转换。下面是常见的转换方法:
-
将QString转换为基本数据类型 通过QString的各种转换函数,可以将QString转换为int、float、double等基本数据类型。例如:
QString str = "123"; int num = str.toInt(); // 将QString转换为int类型 float f = str.toFloat(); // 将QString转换为float类型 double d = str.toDouble(); // 将QString转换为double类型
2.将基本数据类型转换为QString 通过QString的静态函数,可以将int、float、double等基本数据类型转换为QString。例如:
1. int num = 123; QString str = QString::number(num); // 将int类型转换为QString float f = 3.14; QString str2 = QString::number(f); // 将float类型转换为QString
需要注意的是,QString和基本数据类型之间的转换可能会存在精度和数据溢出等问题,需要根据实际情况进行选择和处理。
168、Qt当中如何读写文件?
在Qt中,可以使用QFile类和QTextStream类来读写文件。
-
读文件:
QFile file("test.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
// 处理每一行数据
}
file.close();
上述代码中,首先使用QFile类打开要读取的文件,然后使用QTextStream类对文件进行读取。通过while循环,每次读取一行数据,然后进行处理。最后关闭文件。
-
写文件:
QFile file("test.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << "Hello world" << endl;
out << "Qt is awesome" << endl;
file.close();
上述代码中,首先使用QFile类打开要写入的文件,然后使用QTextStream类对文件进行写入。通过向QTextStream对象中写入数据,可以将数据写入文件中。最后关闭文件。 需要注意的是,在进行文件读写操作时,需要确保文件路径正确,并且文件权限足够。同时,需要根据具体情况使用不同的打开模式,例如只读模式、只写模式、追加模式等。
172、QtChart?
QtChart是Qt自带的图表库,用于绘制各种类型的图表,例如曲线图、饼状图、柱形图、折线图等。使用QtChart可以方便地将数据可视化,并支持用户交互和定制化设置。下面介绍QtChart中常用的几种图表类型及其使用方法。
- 曲线图 曲线图用于展示一段时间内某个变量的变化趋势,例如温度、湿度、压力等。使用QtChart绘制曲线图的步骤如下:
-
创建QChart对象,并设置标题和坐标轴。
-
创建QLineSeries对象,设置曲线的名称和数据。
-
将QLineSeries对象添加到QChart对象中。
-
创建一个QChartView对象,并将QChart对象设置为其父对象。
-
将QChartView对象添加到布局中。 以下是一个简单的曲线图绘制示例:
QChart *chart = new QChart();
chart->setTitle("Temperature");
chart->legend()->hide();
chart->createDefaultAxes();
QLineSeries *series = new QLineSeries();
series->setName("Temperature");
series->append(0, 20);
series->append(1, 22);
series->append(2, 24);
series->append(3, 26);
chart->addSeries(series);
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
ui->chartLayout->addWidget(chartView);