文章目录
前言
本文用三个文本输入框QLineEdit、QTextEdit、QPlainTextEdit的共性,写了一个综合例子,初步介绍它们的使用,至于它们各自的特性,会在后面的其他例程涉及到时再详细阐述。本文还通过设计一个小键盘,介绍Qt两个重要的容器类:QVector动态数组和QList可变长度数组。
本例程设计是在chatgpt的帮助下完成的,编译代码经过测试通过。
感谢朋友提供的chatgpt软件,特别是其中的gpt-box桌面工具,更是我离不开的工具。感兴趣的同仁可前往一观( www.apsuai.com)。
我们的调试环境仍然是双架构Kits
,编译调试在当前的ubuntu(qt5)中进行,重新编译后下载到目标arm设备(qt4)中运行。
我们的编程环境为:Ubuntu64位系统(22.04),目标架构:
(1) qt5 x86_64
架构;
(2)qt4 32位arm
架构。
环境配置请参见《Qt常用的按钮控件编程(一)》第1节。
3、文本编辑框例程
3.1 文本编辑框简介
QLineEdit、QTextEdit、QPlainTextEdit分别是Qt中常用的三种文本编辑框。
QLineEdit是仅支持单行文本输入的小部件,非常适合使用在需要简单文本输入的场景中,如输入标题、用户名和密码等。
QTextEdit是相对于QLineEdit更加灵活的文本编辑部件,支持大范围的多格式文本输入,同时支持添加图片、表格等富文本编辑功能。通常在需要处理较多文本的情况下使用,如编辑HTML文本、XML文本等等。
QPlainTextEdit是一种仅显示纯文本内容,不支持富文本编辑的多行文本编辑框。它适合用来在应用程序界面中显示或编辑程序输出、日志信息等文本信息。
三者的主要区别在于支持的文本格式、文本数量和使用程度等方面:QLineEdit仅支持单行文本输入,QPlainTextEdit支持多行文本输入,而QTextEdit支持多媒体(音频、视频)以及特定格式的文本(HTML、XML等)输入。
此外,QLineEdit和QPlainTextEdit的内容只能以纯文本方式导出,QTextEdit则支持丰富的导出选项包括HTML等。
在使用上,三者都可以通过继承和重载等方式添加个性化的功能,也可以通过QWidget的QSS样式设置修改样式风格。同时,根据需要,我们还可以通过Qt提供的API,支持在文本中高亮、根据关键字自动调整宽度等等。
3.2 例程功能设计
向chatgpt提问过程
- 第一次提问:
“给出一个qt c++ 程序设计:Line Edit:单行编辑框、Text Edit:文本编辑框、Plain Text Edit:纯文本编辑框, 请做这三个控件的综合例子,弹出一个可输入0~10,“.”,小写英文,大写英文的小键盘,用来向这些文本框中输入内容。”
由于chatgpt给出的程序设计小键盘中的按钮都被孤立的一个一个定义,程序显得非常繁琐,因此用下面的提问,要求重写:
- 第二次提问:
“上面的代码可不可以用数组来表示0~10,“.”,小写英文,大写英文,重新优化写一下?”
这次的答案相对满意。经过调整,得到我们程序例程。
3.3 例程执行效果
功能描述:
Line Edit:单行编辑框、Text Edit:文本编辑框、Plain Text Edit:纯文本编辑框综合例程。
在主窗口上,安放三个文本框,下部是一个包含0~10,“.”,小写英文,大写英文的小键盘。按下其中的按钮,结果被输入到三个文本框中。
3.4 生成项目
使用Qt Creator 创建一个c++例程,项目名称"_qtextedit" ,不选默认MainWindow类,选择Widget作为基类,不要勾选“Generate form”,不使用拖取控件,控件全部采用编程。将两个配置好的Kits同时选上,项目新建完成如下图。(详细的项目新建过程参见:《Qt常用的按钮控件编程(一)》)。
点击左侧的Debug选项,可以看到两个编译套件Kit,可以选择编译运行在不同平台上的可执行文件,arm-v7为arm架构的设备,使用Qt4库,而桌面则是当前ubuntu系统,使用Qt5。
3.5 代码编辑
3.5.1 修改项目文件_qtextedit.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# 根据使用的 Qt 版本设置编译条件
greaterThan(QT_MAJOR_VERSION, 4) {
# 如果使用的是 Qt 5 或者更新版本
message("使用的是 Qt 5版本")
} else {
# 如果使用的是 Qt 4 或者更早的版本
message("使用的是 Qt 4版本")
DEFINES += QT_ARM_PLATFORM
QMAKE_CXXFLAGS += -std=c++11
QMAKE_CXXFLAGS += -Wno-psabi -Wno-deprecated-declarations
LIBS += -lts
}
3.5.2 修改 main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
自动生成的程序未改变
3.5.3 修改 widget.h
#define WIDGET_H
#include <QWidget>
#include <QLineEdit>
#include <QTextEdit>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QGridLayout>
#include <vector>
#ifdef QT_ARM_PLATFORM
//Qt4 中,使用初始化列表的语法是不被支持的,需要采用将该列表中的字符串逐个加入到 QStringList 中的方式
const QStringList button_text = QStringList() << "0" << "1" << "2" << "3" << "4" << "5" << "6"
<< "7" << "8" << "9" << "." << "a" << "b" << "c" << "d" << "e" << "f" << "g" << "h"
<< "i" << "j" << "k" << "l" << "m" << "n" << "o" << "p" << "q" << "r" << "s" << "t"
<< "u" << "v" << "w" << "x" << "y" << "z" << "A" << "B" << "C" << "D" << "E" << "F"
<< "G" << "H" << "I" << "J" << "K" << "L" << "M" << "N" << "O" << "P" << "Q" << "R"
<< "S" << "T" << "U" << "V" << "W" << "X" << "Y" << "Z";
#else
//Qt5 中,支持构造函数的初始化列表,可以使用简洁的初始化语法了
const QStringList button_text = {"0", "1", "2", "3", "4","5", "6", "7", "8", "9", ".",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
"m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
"y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"};
#endif
const int num_buttons = button_text.size();
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
QLineEdit *line_edit;
QTextEdit *text_edit;
QPlainTextEdit *plain_text_edit ;
#if 0
std::vector<QPushButton*> buttons;
#endif
QVector<QPushButton*> buttons;
QGridLayout *layout;
QList<int> number_button_indices;
private slots:
void insertText();
void insertNumber();
};
#endif // WIDGET_H
3.5.4 修改 widget.cpp
#include "widget.h"
#include <QLineEdit>
#include <QTextEdit>
#include <QPlainTextEdit>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
line_edit = new QLineEdit(this);
text_edit = new QTextEdit(this);
plain_text_edit = new QPlainTextEdit(this);
layout = new QGridLayout(this);
for (int i = 0; i < num_buttons; ++i) {
buttons.push_back(new QPushButton(button_text[i]));
}
layout->addWidget(line_edit, 0, 0, 1, 10);
layout->addWidget(text_edit, 1, 0, 3, 10, Qt::AlignCenter);
layout->addWidget(plain_text_edit, 4, 0, 3, 10, Qt::AlignCenter);
// Add buttons to the layout
const int num_cols = 10;
int current_col = 0;
int current_row = 7;
for (int i = 0; i < num_buttons; ++i) {
layout->addWidget(buttons[i], current_row, current_col);
++current_col;
if (current_col == num_cols) {
current_col = 0;
++current_row;
}
}
for (int i = 0; i < num_buttons; ++i) {
//当数字按钮被按下,数字按钮的索引存入容器 number_button_indices 中,并与 insertNumber() 槽函数连接
bool is_number;
button_text[i].toDouble(&is_number);
if (is_number) {
connect(buttons[i], SIGNAL(clicked()), this, SLOT(insertNumber()));
number_button_indices.append(i);
}
// 否则使用文本
else {
connect(buttons[i], SIGNAL(clicked()), this, SLOT(insertText()));
}
}
}
Widget::~Widget()
{
}
void Widget::insertNumber()
{
int i;
QPushButton *button = qobject_cast<QPushButton *>(sender());
for (i = 0; i < 10; ++i) {
if(buttons[number_button_indices[i]] == button)
break;
}
if(i<10)
{
line_edit->insert(QString::number(i));
text_edit->insertPlainText(QString::number(i));
plain_text_edit->insertPlainText(QString::number(i));
}
}
void Widget::insertText()
{
QPushButton *button = qobject_cast<QPushButton *>(sender());
if (button) {
line_edit->insert(button->text());
text_edit->insertPlainText(button->text());
plain_text_edit->insertPlainText(button->text());
}
}
3.6 切换Kit,获得运行在不同系统中的运行的执行文件
点击窗口左边的Debug,可以选择编译运行在不同平台上的可执行文件,arm-v7为arm架构的设备,使用Qt4库,而桌面则是当前ubuntu系统,使用Qt5。(参见3.4节)
Qt5编译完成的可执行程序_qcombobox
,存放在项目目录的build-_qcombobox-unknown-Debug/
文件夹下,Qt4编译完成的同名可执行程序_qcombobox
,存放在项目目录的build-_qcombobox-arm_v7-Debug/
文件夹下。
3.7 语法分析
3.7.1 小键盘槽函数处理
在小键盘编程中,将数字与字符的处理槽函数分开,是一种常见的编程习惯。原因主要有两个:
- 处理逻辑上的不同:数字按键和字符按键的处理逻辑是不同的。数字按键一般只是简单的输入数字,而字符按键需要考虑大写小写、特殊符号等等,因此将它们分开处理可以使代码更加清晰,易于维护与调试。
- 提高代码复用性:将数字按键和字符按键分开扩展可以提高代码的复用性。例如,如果我们需要编写一个只接受数字的输入框,那么我们就可以直接使用数字处理函数,避免了代码复制粘贴的问题。另外,如果我们增加了一些文本输入框,也可以方便地重用字符处理函数,避免了代码冗余。
3.7.2 STL和 Qt 相应技术
3.7.2.1 STL简介
STL(Standard Template Library)是 C++ 的标准库之一,其基于数据结构和函数模板实现了诸多常用的算法和容器,与 C++ 语言内置容器和函数库提供的功能互补,能够大大提高 C++ 程序的开发效率和运行效率。
STL 包含着一大批常见的数据结构和算法,例如各种容器、迭代器和算法等。容器分为序列式容器(如 vector、list、deque)和关联式容器(如 map、set 和 multiset 等),迭代器是 STL 中重要的概念,迭代器负责遍历数据结构。算法使用各种迭代器完成常见操作,如排序、查找和字符串处理等。
STL 的使用需要掌握它提供的各类模板变量、类和函数的使用,例如迭代器的类型,容器的类型等,还需要了解算法、容器和迭代器之间互动的一些规则和限制。这可以谓是 C++ 编程的基本功之一,也是常见的面试考点之一。
3.7.2.2 Qt对STL的支持
Qt 提供了对 STL 的很好的支持,我们可以在 Qt 项目中自由地使用 STL,完全充分地与 STL 集成。
于此同时,Qt提供了更符合 Qt 编程的规范的容器类型,以下是一些常见的更符合Qt编程规范的容器类型:
-
QVector:动态数组,支持在任意位置插入和删除元素,可以自动扩展和收缩大小,适用于需要经常插入和删除元素的数据内存管理。
-
QList:可变长度数组,类似于QVector,但是QList可以在任意位置使用快速插入函数。
-
QLinkedList:双向链表,支持在链表任意位置变更元素,包括插入和删除元素。
-
QMap:用于键 - 值对(key-value)操作,每个键和其对应的值是一对。支持按照键的数据类型进行比较。
-
QHash:和QMap非常类似,但是没有按照键排序的特性。
-
QSet:没有重复值的列表,支持插入一个元素和检查某个元素是否在集合中。
这些容器类型是Qt内置的经过优化的实现,它们同样提供了标准接口,并且比标准C++的容器类型更适用于Qt程序的使用需求。使用这些容器类型可以方便地将Qt内置的容器与自定义的C++数据类型相结合,提高编程效率与正确性。因此,在实际项目中,应依据项目需求和项目组共识,结合工期和编程规范采取更加合适的方案。
3.7.2.3 动态数组
在我们的程序中,需要使用大量的按钮,因此声明了一个动态数组存储QPushButton类型按钮指针。
可以使用c++的
std::vector<QPushButton*> buttons;
也可以使用Qt的容器类QVector
QVector<QPushButton*> buttons;
需要注意的是,这里用动态数组来存储按钮指针是因为需要动态地创建和释放按钮。如果使用固定长度的数组,那么很难确定需要创建多少个按钮,因为不同的应用,需要创建的按钮数量会不同。
3.7.2.4 容器 QList
当数字按钮被按下,数字按钮的索引存入容器 number_button_indices 中,并与 insertNumber() 槽函数连接,定义如下:
QList<int> number_button_indices;
总结
本文用三个文本输入框QLineEdit、QTextEdit、QPlainTextEdit的共性,写了一个综合例子。本文还通过设计一个小键盘,介绍Qt两个重要的容器类:QVector动态数组和QList可变长度数组。
本例程设计是在chatgpt的帮助下完成的,编译代码经过测试通过。