I have a Qt 3 dialog that displays several hundred server records in a QListView. The first implementation stored the actual application state in QListViewItem subclasses. It worked until another window needed the same records and sorting the view began to feel suspiciously like rearranging the database.

Qt 3 does not provide the general item model API one might wish for here. QListView owns a tree of items, and those items naturally contain display text. That does not require making them the authoritative business objects.

My simpler pattern is to keep records in an ordinary domain collection and make each list item an adapter containing only a stable identifier. Display columns are copied from the record when the view is populated or refreshed.

class ServerItem : public QListViewItem
{
public:
    ServerItem(QListView *view, int id)
        : QListViewItem(view), serverId(id) {}

    int id() const { return serverId; }

private:
    int serverId;
};

When selection changes, the controller reads the item’s ID and looks up the record. Editing updates the record first, then refreshes the item text. Deleting the view item never deletes the underlying record unless the user explicitly requested that operation.

This separation fixes several observed problems. Sorting changes presentation order without changing application order. Two views can show the same record differently. Reloading the widget cannot silently discard unsaved state hidden in a child item. Unit-like tests can exercise record operations without constructing widgets or starting an X connection.

Signals and slots keep the pieces reasonably loose. The dialog connects selection and activation signals to slots that translate a QListViewItem * into a record ID. The record-owning object emits a signal after a successful change, and the view refreshes the affected row.

There is a caveat: copying all text into items can be expensive for very large datasets. For hundreds or a few thousand rows it is straightforward and fast enough. If the data is enormous, a custom widget or a specialised table that fetches visible values may be warranted. I would measure before building that machinery.

Stable IDs are important. Storing a pointer into a collection is tempting, but reallocating a vector or reloading records can invalidate it. An integer or other durable key makes the lookup explicit and failures easier to detect.

I do not call this a framework. It is three rules: own data outside widgets, put identities in items, and route changes through one owner. Qt’s item widgets remain useful presentation objects without becoming a tiny, badly documented database. Most dialogs need no grander architecture; they merely need the courage not to store reality in column zero.