Qt Quick and QML

repository·dev·Indexed 43 days ago

https://github.com/qt/qtdeclarative

Framework and modules for building declarative, hardware-accelerated user interfaces in Qt. Includes the QML language, Qt Quick components, and tooling such as qmllint, qmlls, and the Qml Static Analysis (QmlSA) system for creating custom linting plugins.

Tokens
17.6K
Snippets
39
Records
72
Agent score
46%

What's inside Qt Quick

  1. Overview of qtdeclarative modules

    dev
    The qtdeclarative repository contains the core technologies for building modern, fluid user interfaces in Qt. It primarily consists of QML, Qt Quick, and various specialized modules for UI components, data modeling, and animations. Developers use these modules to create declarative user interfaces that are highly performant and visually rich.
  2. Understand the Universal Style in Quick Controls

    dev

    The Universal Style for Qt Quick Controls is based on the Microsoft Universal Design Guidelines. It uses colors and metrics derived from the Windows 10 SDK to provide a look and feel consistent with Windows applications.

    The design specifications (colors and metrics) are sourced from the generic.xaml and themeresources.xml files found within the Windows SDK installation directory.

  3. Overview of the V4 Garbage Collector

    dev

    Since Qt 6.8, the V4 ECMAScript engine used in Qt (qtdeclarative) employs an incremental, precise mark-and-sweep garbage collection (GC) algorithm.

    Key Characteristics

    • Incremental: The collector and mutator (user application) run in the same thread, but the collector executes in chunks, pausing the mutator at specific intervals.
    • Precise: The GC can accurately distinguish between pointers to heap objects and other pointer-sized values.
    • Non-generational: It does not divide objects into generations based on survival.
    • Non-moving: It does not relocate objects in memory.

    Marking States

    During the mark phase, every heap item exists in one of three states:

    1. White (unvisited): The GC has not encountered this item.
    2. Grey (seen): The item has been discovered, but its reachable children have not necessarily been visited. Grey items are tracked in a MarkStack.
    3. Black (finished): The item and all its directly reachable children have been visited. Black items are tracked via a black-object bitmap.

    Root Set

    The GC starts its process from a set of 'roots', which include:

    • Engine-global objects (JS globals).
    • All strings and symbols in the identifier table.
    • All actively linked compilation units.
    • Values on the JS stack (treated as 'fast roots').
    • Persistent Values: Everything stored in a QJSValue and all bound functions of QQmlBindings.
    • QObjectWrappers: QObjects with C++ ownership, or those parented to/rooted in a QObject with C++ ownership.
  4. How Persistent Values are handled during GC

    dev

    The V4 engine allows marking of Persistent Values (values in QJSValue or QQmlBindings) to be interruptible. This is achieved by storing a PersistentValueStorage::Iterator within the GC state machine.

    Safety Mechanisms

    • Iterator Validity: The PersistentValueStorage is a forward-list of ref-counted Pages. Iterators increase the ref-count of the page, ensuring that even if values within a page are freed, the pointer to the page remains valid during iteration.
    • New Values: Any new persistent or weak values added during a GC cycle are automatically handled because the engine marks them as they are added, and the sweep phase only targets unmarked values.
    • Optimization Adjustment: To prevent the marking phase from skipping pages, the optimization that moves the first page with empty slots to the front of the list is disabled during GC cycles.
  5. Structure of a QML Element description in MOC JSON

    dev

    When describing QML Elements in the MOC JSON, each class object contains metadata about its identity, location, and members.

    Key fields include:

    • className: The C++ class name (e.g., MyClass).
    • qualifiedClassName: The fully-qualified C++ name (e.g., MyNamespace::MyClass).
    • lineNumber: The line number where the class is defined (used by qmlls for navigation).
    • object: true if the type is an object, false if it is a gadget or namespace.
    • gadget: true if the type is a gadget, false if it is an object or namespace.
    • namespace: true if the type is a namespace.
    • superClasses: A list of base types. Note that multiple superclasses are not supported; use the interfaces field for multiple inheritance.
    • interfaces: A list of interface names implemented by the type (corresponds to Q_INTERFACES or QML_IMPLEMENTS_INTERFACES in C++).

    Members include:

    • properties: A list of properties (see Property fields).
    • enums: A list of enums (see Enum fields).
    • methods, signals, slots, constructors: Lists of functional members (all share similar field structures).
    {
        "classInfos": [
            {
                "name": "QML.Element",
                "value": "myGadget"
            }
        ],
        "className": "MyGadget",
        "gadget": true,
        "lineNumber": 6,
        "properties": [
            {
                "constant": false,
                "designable": true,
                "final": false,
                "index": 0,
                "lineNumber": 10,
                "member": "m_myInt",
                "name": "myInt",
                "required": false,
                "scriptable": true,
                "stored": true,
                "type": "int",
                "user": false
            }
        ],
        "qualifiedClassName": "MyGadget"
    }
  6. Implement an Element Pass (QQmlSA::ElementPass)

    dev

    An ElementPass runs for every QML element in the scope being linted. It uses two primary methods:

    1. shouldRun(const QQmlSA::Element &element): Returns true if the element is relevant to the pass. Performance Warning: Do not perform expensive computations here, as this is called for every single element in the document. Resolve types in the constructor instead.
    2. run(const QQmlSA::Element &element): Performs the actual linting logic and emits warnings.

    Use emitWarning within run to report issues.

  7. Markdown support in Text, TextEdit, and TextArea

    dev

    The Text, TextEdit, and TextArea items in Qt Quick support Markdown formatting. Since Qt 5.14, these items support two dialects:

    1. CommonMark Specification: The conservative formal specification.
    2. GitHub Flavored Markdown: Adds extra features such as task lists and tables.

    To use Markdown, you can provide the Markdown string to the text property of these items. Note that these items also support standard HTML rich text.

  8. Implement a Property Pass (QQmlSA::PropertyPass)

    dev

    A PropertyPass runs whenever a property is read, written, or has a binding created. Because property access is more frequent than element instantiation, you should specify the target type and property name during registration to maintain performance.

    Registration

    You can omit the type name to target all properties with a specific name (e.g., width), or omit the property name to target all properties of a specific type.

    Methods

    • onBinding(element, propertyName, bindingScope, location, binding, value): Called when a binding is created. binding provides type information, and value is a QQmlSA::Element (useful for object bindings).
    • onRead(element, propertyName, readScope, location): Called when a property is read (via binding or script).
    • onWrite(element, propertyName, writeScope, location, value): Called when a property is written to. value contains the element or type information being written.
  9. The V4 GC State Machine and Lifecycle

    dev

    To support incremental collection, the V4 GC operates through a structured state machine. This allows the engine to pause and resume collection without stopping the entire application (Stop-The-World) for the entire duration.

    GC Stages

    1. Initialization: markStart (atomic) initializes the MarkStack and sets the incremental flag.
    2. Global Marking: markGlobalObject (atomic) marks the global object, identifier table, and compilation units.
    3. Stack Marking: markJSStack (atomic) marks the JS stack.
    4. Persistent/Weak Value Marking:
      • initMarkPersistentValues (atomic) followed by markPersistentValues (interruptible).
      • initMarkWeakValues (atomic) followed by markWeakValues (interruptible).
    5. Drain Phase: markDrain (interruptible) processes the MarkStack until empty.
    6. Finalization & Cleanup:
      • initCallDestroyObjects (atomic) rescans the stack and drains the MarkStack to ensure all live objects are marked.
      • callDestroyObject (interruptible) calls destroyObject on non-marked QObjectWrappers.
      • freeWeakMaps / freeWeakSets (atomic) remove references to dead objects.
      • handleQObjectWrappers (atomic) clears pending references.
    7. Sweep Phase: Multiple atomic phases perform the actual memory freeing across different allocators (identifier table, block allocator, huge item allocator, IC allocator). This phase also triggers destroy on objects marked with V4_NEEDS_DESTROY.
    8. Completion: updateMetaData (atomic) updates bitmaps and statistics, marking the cycle as done.
  10. Markdown support in Qt Quick Text items

    dev

    The Text, TextEdit, and TextArea items in Qt Quick support rich text formatting via Markdown. Since Qt 5.14, these items support two specific dialects:

    1. CommonMark Specification: A conservative, formal specification.
    2. GitHub Flavored Markdown (GFM): An extension of CommonMark that adds features like task lists and tables.

    You can use these items to display or edit Markdown-formatted content directly in your QML applications.

  11. Required qmldir entries for QML Modules

    dev

    A qmldir file defines a QML Module. For tooling like qmllint and qmlls to function correctly, the qmldir must be located in a folder within the import path that follows the module's URI (e.g., MyModule at /path/to/importpath/MyModule/qmldir).

    At a minimum, a qmldir must contain:

    • module: The module name.
    • typeinfo: A directive pointing to the .qmltypes file (e.g., typeinfo plugins.qmltypes).
    • depends: Entries for all QML Modules this module depends on.
    • File Location: Either a list of QML files in the module OR a prefer entry referring to the location of the QML files in the resource system.
  12. Run qmllint on QML files

    dev

    To run qmllint without CMake, you must manually provide import paths and resource files so the tool can map source files to their build-time locations.

    Key Flags:

    • -I <path>: Add an import path. Use multiple -I flags for multiple paths.
    • --resource <path>: Pass the .qrc files generated by the build system. This allows qmllint to map QML files from their build path back to their source paths.
    • --bare: Disables automatic adding of the current directory, default import paths, and auto-discovery of qmldir files. Use this to ensure linting only uses the paths you explicitly provided.

    Example Invocation: If Main.qml is part of MyModule and depends on a module in /path/to/build/:

    qmllint \
        -I /path/to/build/ \
        -I /path/to/qt/qml \
        --resource /path/to/build/.qt/rcc/qmake_mymodule.qrc \
        --resource /path/to/build/.qt/rcc/appmymodule_raw_qml_0.qrc \
        --bare \
        /path/to/source/MyModule/Main.qml