qt6.standard_item_model

The interface for this class is kept to a minimum and it may be unusable to your project. This early release was done so it’s possible to gather usage experience sooner. Next releases should fill in the missing gaps so it can be used for a wider range of projects.

This class represents a handle to an instance of QStandardItemModel. To use this class, just set the property model of some view to an instance of this class and from there do as you’d usually do in standard Qt.

local system = require 'system'
local qt = require 'qt6'

local qml = qt.load_qml(byte_span.append([[
import QtQuick

Window {
    ListView {
        id: view
        anchors.fill: parent

        delegate: Text {
            text: model.name + ": " + model.number
        }
    }
}
]]))

qml.object['visibleChanged(bool)'] = function(visible)
    if not visible then
        spawn(function() system.exit() end):detach()
    end
end

local model = qt.standard_item_model.new(0, 1)
model:set_role_names{'name', 'number'}
model:append_item{ name = "Bill Smith", number = "555 3264" }
model:append_item{ name = "John Brown", number = "555 8426" }
model:append_item{ name = "Sam Wise", number = "555 0473" }
qml.property.view.model = model
qml.object('show()')
Lua conventions on index starting at 1 are ignored. Indexes here are Qt-mandated and start at 0.

Implementation details

The bindings for QStandardItemModel are special. Under the hood, two instances are created (so the program wastes at least two times more RAM for each model than a traditional Qt-based program), and they’re incrementally synchronized as changes are made. The synchronization algorithm is clever enough to have a few desired properties:

  • When the models are synchronized, the algorithm doesn’t consume CPU time. IOW, there’s no variation of busy-looping or similar.

  • The sync algorithm is triggered again as soon as one thread makes changes to its model. IOW, no timer is used to synchronize at specific intervals, and latency is kept to a minimum.

  • Changes are propagated in batches if possible, so on rendering cycles we only schedule a redraw for the last state and save on CPU resources.

  • If possible, the notifier removes queued updates that cancel each-other (among other optimizations) to provide some flow control. As new versions are released, improvements to this area are expected until complete flow control is provided.

These strategies are focused on making the double-model detail invisible to the system operator by reducing the observed latency to humans.

Furthermore, the system also performs auto-translation of model indexes as data travels back-and-forth between threads to make the double-model transparent to the programmer as well.

In short, this is an implementation detail that hopefully will rarely be noticed by the user. The rest of this C++ plugin has a trend of scheduling jobs to the Qt thread that is not blocked by the Lua program at any step. On this trend of async-by-default, the programmer has fewer guarantees about the state of the underlying Qt data as it could already be gone once the Lua program schedules the next modification/job (e.g. form data could be overridden by the unblocked GUI thread as the Lua program is still catching up to some emitted Qt’s signal). This trend is broken here. The Qt thread still runs asynchronously to the Lua thread, but this time there’s more machinery between the two threads to make this behaviour more transparent than what you might have seen in other classes of this C++ plugin (at the cost of some extra CPU/RAM when compared to traditional Qt-based apps).

A limitation of the current system that will be solved in future versions is that as of now the model on the Qt thread is read-only to the QML view. There are many approaches to solve this problem, and they need to be compared before the development team settles on one solution.

Functions

new() → standard_item_model

function() -> standard_item_model                                (1)
function(rows: integer, columns: integer) -> standard_item_model (2)

Constructor.

set_role_names(self, names: string[])

Sets the item role names to names.

Similar to affine function objects, this function can only be called once.

The model will only accept your custom roles once you call this function.

clear(self)

Removes all items (including header items) from the model and sets the number of rows and columns to zero.

append_item(self, item: table)

Appends a row containing a single item.

insert_item(self, row: integer, item: table)

Inserts the item at the position in the list given by row.

remove_rows(self, row: integer, count: integer)

Removes count rows starting with the given row from the model.

set_item(self, row: integer, column: integer, item: table)

Sets the item for the given row and column to item. The previous item at the given location (if there was one) is deleted.

item(self, row: integer, column: integer = 0) → table|nil

Returns the item for the given row and column if one has been set; otherwise returns nil.

Properties

row_count: integer

Read-write property.

column_count: integer

Read-write property.