Most Qt classes are derived from the QObject
class. It encapsulates the central concepts of Qt. But there are many more classes in the framework. Before we continue looking at QML and how to extend it, we will look at some basic Qt classes that are useful to know about.
大多数Qt类都派生自QObject类。它封装了Qt的核心概念。但框架中还有更多的类。在我们继续研究QML以及如何扩展它之前,我们将了解一些有用的基本Qt类。
The code examples shown in this section are written using the Qt Test library. This way, we can ensure that the code works, without constructing entire programs around it. The QVERIFY
and QCOMPARE
functions from the test library to assert a certain condition. We will use {}
scopes to avoid name collisions. Don't let this confuse you.
本节中显示的代码示例是使用Qt测试库编写的。通过这种方式,我们可以确保代码正常工作,而无需围绕代码构建整个程序。QVERIFY和QCOMPARE函数来自测试库,用于断言特定条件。我们将使用{}作用域来避免名称冲突。别让这件事把你搞糊涂了。
In general, text handling in Qt is Unicode based. For this, you use the QString
class. It comes with a variety of great functions which you would expect from a modern framework. For 8-bit data, you would use normally the QByteArray
class and for ASCII identifiers the QLatin1String
to preserve memory. For a list of strings you can use a QList
or simply the QStringList
class (which is derived from QList
).
一般来说,Qt中的文本处理是基于Unicode的。为此,使用QString类。它有很多功能,你可以从一个现代的框架中看到这些功能。对于8位数据,通常使用QByteArray类,对于ASCII标识符,使用QLatin1String
来保留内存。对于字符串列表,可以使用QList
Below are some examples of how to use the QString
class. QString can be created on the stack but it stores its data on the heap. Also when assigning one string to another, the data will not be copied - only a reference to the data. So this is really cheap and lets the developer concentrate on the code and not on the memory handling. QString
uses reference counters to know when the data can be safely deleted. This feature is called Implicit Sharing and it is used in many Qt classes.
下面是一些如何使用QString类的示例。QString可以在堆栈上创建,但它将其数据存储在堆上。此外,当将一个字符串分配给另一个字符串时,数据不会被复制,只会被复制为对数据的引用。所以这真的很便宜,让开发人员专注于代码,而不是内存处理。QString使用引用计数器来知道何时可以安全删除数据。这个特性被称为隐式共享,它被用于许多Qt类中。
QString data("A,B,C,D"); // create a simple string
// split it into parts
QStringList list = data.split(",");
// create a new string out of the parts
QString out = list.join(",");
// verify both are the same
QVERIFY(data == out);
// change the first character to upper case
QVERIFY(QString("A") == out[0].toUpper());
Below you can see how to convert a number to a string and back. There are also conversion functions for float or double and other types. Just look for the function in the Qt documentation used here and you will find the others.
下面您可以看到如何将数字转换为字符串并返回。还有浮点数、双精度和其他类型的转换函数。只需在这里使用的Qt文档中查找函数,就可以找到其他函数。
// create some variables
int v = 10;
int base = 10;
// convert an int to a string
QString a = QString::number(v, base);
// and back using and sets ok to true on success
bool ok(false);
int v2 = a.toInt(&ok, base);
// verify our results
QVERIFY(ok == true);
QVERIFY(v = v2);
Often in a text, you need to have parameterized text. One option could be to use QString("Hello" + name)
but a more flexible method is the arg
marker approach. It preserves the order also during translation when the order might change.
在文本中,通常需要参数化文本。一个选项可以是使用QString("Hello" + name)
,但更灵活的方法是arg标记方法。当顺序可能发生变化时,它也会在翻译过程中保留顺序。
// create a name
QString name("Joe");
// get the day of the week as string
QString weekday = QDate::currentDate().toString("dddd");
// format a text using paramters (%1, %2)
QString hello = QString("Hello %1. Today is %2.").arg(name).arg(weekday);
// This worked on Monday. Promise!
if(Qt::Monday == QDate::currentDate().dayOfWeek()) {
QCOMPARE(QString("Hello Joe. Today is Monday."), hello);
} else {
QVERIFY(QString("Hello Joe. Today is Monday.") != hello);
}
Sometimes you want to use Unicode characters directly in your code. For this, you need to remember how to mark them for the QChar
and QString
classes.
有时,您希望在代码中直接使用Unicode字符。为此,您需要记住如何为QChar和QString类标记它们。
// Create a unicode character using the unicode for smile :-)
QChar smile(0x263A);
// you should see a :-) on you console
qDebug() << smile;
// Use a unicode in a string
QChar smile2 = QString("\u263A").at(0);
QVERIFY(smile == smile2);
// Create 12 smiles in a vector
QVector smilies(12);
smilies.fill(smile);
// Can you see the smiles
qDebug() << smilies;
This gives you some examples of how to easily treat Unicode aware text in Qt. For non-Unicode, the QByteArray
class also has many helper functions for conversion. Please read the Qt documentation for QString
as it contains tons of good examples.
本文给出了一些示例,说明如何在Qt中轻松处理Unicode感知文本。对于非Unicode,QByteArray类还具有许多用于转换的帮助函数。请阅读QString的Qt文档,因为它包含大量好的示例。
A list, queue, vector or linked-list is a sequential container. The mostly used sequential container is the QList
class. It is a template based class and needs to be initialized with a type. It is also implicit shared and stores the data internally on the heap. All container classes should be created on the stack. Normally you never want to use new QList
, which means never use new
with a container.
列表、队列、向量或链表是一个连续的容器。最常用的顺序容器是QList类。它是一个基于模板的类,需要用类型初始化。它也是隐式共享的,并在堆内部存储数据。所有容器类都应该在堆栈上创建。通常情况下,您永远不想使用new QList
The QList
is as versatile as the QString
class and offers a great API to explore your data. Below is a small example of how to use and iterate over a list using some new C++ 11 features.
QList和QString类一样通用,它提供了一个很好的API来暴露您的数据。下面是如何使用一些新的C++ 11特性来使用和迭代列表的小例子。
// Create a simple list of ints using the new C++11 initialization
// for this you need to add "CONFIG += c++11" to your pro file.
QList list{1,2};
// append another int
list << 3;
// We are using scopes to avoid variable name clashes
{ // iterate through list using Qt for each
int sum(0);
foreach (int v, list) {
sum += v;
}
QVERIFY(sum == 6);
}
{ // iterate through list using C++ 11 range based loop
int sum = 0;
for(int v : list) {
sum+= v;
}
QVERIFY(sum == 6);
}
{ // iterate through list using JAVA style iterators
int sum = 0;
QListIterator i(list);
while (i.hasNext()) {
sum += i.next();
}
QVERIFY(sum == 6);
}
{ // iterate through list using STL style iterator
int sum = 0;
QList::iterator i;
for (i = list.begin(); i != list.end(); ++i) {
sum += *i;
}
QVERIFY(sum == 6);
}
// using std::sort with mutable iterator using C++11
// list will be sorted in descending order
std::sort(list.begin(), list.end(), [](int a, int b) { return a > b; });
QVERIFY(list == QList({3,2,1}));
int value = 3;
{ // using std::find with const iterator
QList::const_iterator result = std::find(list.constBegin(), list.constEnd(), value);
QVERIFY(*result == value);
}
{ // using std::find using C++ lambda and C++ 11 auto variable
auto result = std::find_if(list.constBegin(), list.constBegin(), [value](int v) { return v == value; });
QVERIFY(*result == value);
}
A map, a dictionary, or a set are examples of associative containers. They store a value using a key. They are known for their fast lookup. We demonstrate the use of the most used associative container the QHash
also demonstrating some new C++ 11 features.
地图、字典或集合都是关联容器的示例。它们使用一个键存储一个值。它们以快速查找而闻名。我们演示了使用最常用的关联容器,即QHash
,也展示了一些新的C++ 11特性。
QHash hash({{"b",2},{"c",3},{"a",1}});
qDebug() << hash.keys(); // a,b,c - unordered
qDebug() << hash.values(); // 1,2,3 - unordered but same as order as keys
QVERIFY(hash["a"] == 1);
QVERIFY(hash.value("a") == 1);
QVERIFY(hash.contains("c") == true);
{ // JAVA iterator
int sum =0;
QHashIterator i(hash);
while (i.hasNext()) {
i.next();
sum+= i.value();
qDebug() << i.key() << " = " << i.value();
}
QVERIFY(sum == 6);
}
{ // STL iterator
int sum = 0;
QHash::const_iterator i = hash.constBegin();
while (i != hash.constEnd()) {
sum += i.value();
qDebug() << i.key() << " = " << i.value();
i++;
}
QVERIFY(sum == 6);
}
hash.insert("d", 4);
QVERIFY(hash.contains("d") == true);
hash.remove("d");
QVERIFY(hash.contains("d") == false);
{ // hash find not successfull
QHash::const_iterator i = hash.find("e");
QVERIFY(i == hash.end());
}
{ // hash find successfull
QHash::const_iterator i = hash.find("c");
while (i != hash.end()) {
qDebug() << i.value() << " = " << i.key();
i++;
}
}
// QMap
QMap map({{"b",2},{"c",2},{"a",1}});
qDebug() << map.keys(); // a,b,c - ordered ascending
QVERIFY(map["a"] == 1);
QVERIFY(map.value("a") == 1);
QVERIFY(map.contains("c") == true);
// JAVA and STL iterator work same as QHash
It is often required to read and write from files. QFile
is actually a QObject
but in most cases, it is created on the stack. QFile
contains signals to inform the user when data can be read. This allows reading chunks of data asynchronously until the whole file is read. For convenience, it also allows reading data in blocking mode. This should only be used for smaller amounts of data and not large files. Luckily we only use small amounts of data in these examples.
通常需要读取和写入文件。QFile实际上是一个QObject,但在大多数情况下,它是在堆栈上创建的。QFile包含通知用户何时可以读取数据的信号。这允许异步读取数据块,直到读取整个文件。为方便起见,它还允许以阻塞模式读取数据。这应该只用于较小的数据量,而不是大文件。幸运的是,在这些示例中,我们只使用了少量数据。
Besides reading raw data from a file into a QByteArray
you can also read data types using the QDataStream
and Unicode string using the QTextStream
. We will show you how.
除了将原始数据从文件读入QByteArray之外,还可以使用QDataStream和使用QTextStream的Unicode字符串读取数据类型。我们会告诉你怎么做。
QStringList data({"a", "b", "c"});
{ // write binary files
QFile file("out.bin");
if(file.open(QIODevice::WriteOnly)) {
QDataStream stream(&file);
stream << data;
}
}
{ // read binary file
QFile file("out.bin");
if(file.open(QIODevice::ReadOnly)) {
QDataStream stream(&file);
QStringList data2;
stream >> data2;
QCOMPARE(data, data2);
}
}
{ // write text file
QFile file("out.txt");
if(file.open(QIODevice::WriteOnly)) {
QTextStream stream(&file);
QString sdata = data.join(",");
stream << sdata;
}
}
{ // read text file
QFile file("out.txt");
if(file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
QStringList data2;
QString sdata;
stream >> sdata;
data2 = sdata.split(",");
QCOMPARE(data, data2);
}
}
Qt is a rich application framework. As such it has thousands of classes. It takes some time to get used to all of these classes and how to use them. Luckily Qt has a very good documentation with many useful examples includes. Most of the time you search for a class and the most common use cases are already provided as snippets. Which means you just copy and adapt these snippets. Also, Qt’s examples in the Qt source code are a great help. Make sure you have them available and searchable to make your life more productive. Do not waste time. The Qt community is always helpful. When you ask, it is very helpful to ask exact questions and provide a simple example which displays your needs. This will drastically improve the response time of others. So invest a little bit of time to make the life of others who want to help you easier .
Qt是一个丰富的应用程序框架。因此,它有数千个类。要适应所有这些课程以及如何使用它们需要一些时间。幸运的是,Qt有一个非常好的文档,其中包含许多有用的示例。大多数情况下,您搜索一个类,最常见的用例已经作为代码片段提供。这意味着你只需复制和改编这些片段。此外,Qt源代码中的Qt示例也有很大帮助。确保你有可用的和可搜索的,以使你的工作更有效率。不要浪费时间。Qt社区总是很有帮助的。当你提问时,提出准确的问题并提供一个简单的例子来展示你的需求是非常有帮助的。这将大大提高其他人的响应时间。所以,花一点时间让那些想帮助你的人的工作更轻松.
Here some classes whose documentation the author thinks are a must read:
以下是作者认为必须阅读的一些类的文档:
That should be enough for the beginning.
这作为入门就足够了。
示例源码下载