Do you want to know how your customers use your applications and devices? Try Qt Insight Beta.
最新版Qt 6.3已正式发布。 了解更多。
最新バージョンQt 6.3がご利用いただけます。 詳細はこちら

# Working with Models

In Qt Quick Ultralite, it is possible to create models in QML using the ListModel element. It is also possible, and a bit more interesting, to create models from C++. This lets you expose lists of data from C++ to QML and to instantiate user interface elements for each item of the list. The setup is very similar to the ordinary Qt Quick, but the base classes and interfaces are more limited.

In this chapter we will create a list of cities in Europe, listing the name of the city and the country in which the city is located. The cities will be shown in a ListView as shown below:

# The C++

To create a model in Qt Quick Ultralite, the first thing we need to do is to define a struct with the data of each list item. For this struct, we also need to provide a == operator. This is what we do with the CityData struct shown below. Notice that we use std::string rather than QString in Qt Quick Ultralite. The assumption is that UTF-8 encoding is used.

#include <string>

struct CityData
{
    std::string name;
    std::string country;
};

inline bool operator==(const CityData &l, const CityData &r)
{
    return l.name == r.name && l.country == r.country;
}

Once the data type has been prepared, we declare the CityModel struct, inheriting from Qul::ListModel. This lets us define a model that can be accessed from QML. We must implement the count and data methods, which are similar, but not identical to, the corresponding methods from the QAbstractListModel class. We also use the `CMake macro qul_target_generate_interfaces to make the types available to QML.

#include <qul/model.h>
#include <platforminterface/allocator.h>

struct CityModel : Qul::ListModel<CityData>
{
private:
    Qul::PlatformInterface::Vector<CityData> m_data;

public:
    CityModel();

    int count() const override { return m_data.size(); }
    CityData data(int index) const override { return m_data[index]; }
};

We also implement a constructor for the CityModel struct that populates the m_data vector with data.

#include "citymodel.h"

CityModel::CityModel()
{
    m_data.push_back(CityData {"Berlin", "Germany"});
    m_data.push_back(CityData {"Copenhagen", "Denmark"});
    m_data.push_back(CityData {"Helsinki", "Finland"});
    m_data.push_back(CityData {"London", "England"});
    m_data.push_back(CityData {"Oslo", "Norway"});
    m_data.push_back(CityData {"Paris", "France"});
    m_data.push_back(CityData {"Stockholm", "Sweden"});
}

# The QML

In the example, we show the model as a scrollable list, as shown below.

The QML code is shown in its entirety below:

import QtQuick 2.0

Rectangle {
    width: 480
    height: 272

    CityModel {
        id: cityModel
    }

    Component {
        id: cityDelegate

        Item {
            width: 480
            height: 45

            Column {
                spacing: 2
                Text {
                    text: model.name
                    x: 10
                    font: Qt.font({
                            pixelSize: 24,
                            unicodeCoverage: [Font.UnicodeBlock_BasicLatin]
                        })
                }
                Text {
                    text: model.country
                    x: 10
                    color: "gray"
                    font: Qt.font({
                            pixelSize: 12,
                            unicodeCoverage: [Font.UnicodeBlock_BasicLatin]
                        })
                }
                Rectangle {
                    color: "lightGreen"
                    x: 10
                    width: 460
                    height: 1
                }
            }
        }
    }

    ListView {
        anchors.fill: parent
        model: cityModel
        delegate: cityDelegate
        spacing: 5
    }
}

The example starts by instantiating the cityModel. As the model is not a singleton, it has to be instantiated from QML.

Then the delegate, cityDelegate is implemented as a Component. This means that it can be instantiated multiple times from QML. The model data is accessed via the model.name and model.country attached properties.

Finally, the ListView element joins the model and the delegate, resulting in the list shown in the screenshots in this chapter.

An interesting aspect of the QML is how the font of the Text elements is configured. The unicodeCoverage property lets us tell the Qt Quick Ultralite compiler what characters we would like to be able to render. When specifying fixed strings, the Qt Quick Ultralite tooling generates minimal fonts containing exactly the glyphs that we intend to use. However, since the model will provide us with dynamic data, we need to tell the font what characters we expect to use.

When rendering a complete font, sometimes you encounter the following style of warnings:

[2/7 8.8/sec] Generating CMakeFiles/cppmodel.dir/qul_font_engines.cpp, CMakeFiles/cppmodel.dir/qul_font_data.cpp
Warning: Glyph not found for character "\u0000"
Warning: Glyph not found for character "\u0001"
Warning: Glyph not found for character "\u0002"
Warning: Glyph not found for character "\u0003"
Warning: Glyph not found for character "\u0004"
Warning: Glyph not found for character "\u0005"
Warning: Glyph not found for character "\u0006"
Warning: Glyph not found for character "\u0007"
...

These can safely be disregarded, unless you expect to show the character in question.