Model/view helpers

Overview

qtypy.model.PythonListModel
A class that behaves both as a Python list and a QAbstractListModel.
qtypy.model.PythonTreeModel
A tree model based on PythonListModel which may contain other PythonListModel instances.
qtypy.widgets.view.ColumnedView

A multi-columned view for PythonTreeModel.

qtypy.widgets.view.Column
Base class for columns
qtypy.widgets.view.CheckableColumnMixin
Mixin to make a column checkable
qtypy.widgets.view.EditableColumnMixin
Mixin to make a column editable
qtypy.widgets.view.WidgetColumn
Column that displays a widget, when all else fails

Examples

Screenshot
#!/usr/bin/env python3

from PyQt5 import QtCore, QtWidgets

from qtypy.settings import Settings
from qtypy.widgets.view import ColumnedView
from qtypy.model import PythonListModel
from qtypy.widgets.view import Column, WidgetColumn, CheckableColumnMixin, EditableColumnMixin


class Item(PythonListModel):
    def __init__(self, n):
        super().__init__()

        self.n = n
        self.checked = False
        self.text = 'Edit me'

        if n == 7:
            for i in range(5):
                self.append(Item(i))


class SimpleColumn(Column):
    def __init__(self, name):
        self._name = name
        super().__init__()

    def name(self):
        return self._name

    def id(self):
        # For saveState/restoreState
        return self._name

    def labelForItem(self, item):
        return 'Item #%d in col %s (%s)' % (item.n, self._name, item.text)


class CheckColumn(CheckableColumnMixin, SimpleColumn):
    def checkState(self, item):
        return QtCore.Qt.Checked if item.checked else QtCore.Qt.Unchecked

    def setCheckState(self, item, state):
        print('== Check state for item "%s": %d' % (self.labelForItem(item), state))
        item.checked = state == QtCore.Qt.Checked

    def appliesToChildrenOf(self, parent):
        return parent is not None # Only for non-toplevel items


class EditColumn(EditableColumnMixin, SimpleColumn):
    def value(self, item):
        return item.text

    def setValue(self, item, value):
        print('== Set value for item "%s": %s' % (self.labelForItem(item), value))
        item.text = value

    def appliesToChildrenOf(self, parent):
        return parent is not None


class ComboColumn(WidgetColumn):
    def widgetFactory(self, item, parent):
        combo = QtWidgets.QComboBox(parent)
        combo.addItem('One')
        combo.addItem('Two')
        combo.addItem('Three')
        return combo

    def appliesToChildrenOf(self, parent):
        return parent is not None # Only for non-toplevel items


class CustomView(ColumnedView):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.setStandardButtons(self.BTN_ADD|self.BTN_DEL)
        self.addButtonClicked.connect(self._onAdd)
        self.delButtonClicked.connect(self._onDel)

    def _onAdd(self, selection):
        if selection:
            for item in selection:
                item.append(Item(42))
        else:
            self.model().append(Item(42))

    def _onDel(self, selection):
        for item in selection:
            parent = self.itemContainer(item)
            if parent is not None: # The parent itself may already have been removed
                parent.remove(item)

    def createContextMenu(self):
        # Column visibility menu
        menu = QtWidgets.QMenu(self)
        self.populateContextMenu(menu)
        return menu


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        model = PythonListModel()
        view = CustomView(model=model, parent=self)

        view.addColumn(SimpleColumn('Basic')).setResizeMode(Column.Interactive)
        view.addColumn(CheckColumn('Checkable')).setResizeMode(Column.Contents)
        view.addColumn(ComboColumn('Widget')).setResizeMode(Column.Interactive)
        view.addColumn(EditColumn('Editable')).setResizeMode(Column.Stretch)
        self.setCentralWidget(view)

        for n in range(10):
            model.append(Item(n))

        with Settings().grouped('model') as settings:
            if 'state' in settings:
                view.restoreState(settings['state'])

        self.show()
        self.raise_()

    def closeEvent(self, event):
        with Settings().grouped('model') as settings:
            settings['state'] = self.centralWidget().saveState()
        event.accept()


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    app.setApplicationName('qtypy example')
    win = MainWindow()
    app.exec_()

Reference

Models

Classes for Qt’s model/view programming, with a Pythonic touch.

class qtypy.model.PythonListModel(parent=None, value=None)[source]

Python list-like object that implements QAbstractListModel. Most list operations like iterating, slicing, etc are supported except for

  • reverse()
  • sort()
  • Slices with step

Items may define an itemDataChanged() signal, that is to be emitted whenever the item’s data changes.

copy()[source]

Returns a shallow copy of this object (same class, same content)

class qtypy.model.PythonTreeModel(model=None, parent=None)[source]

This is an implementation of QAbstractItemModel based on a PythonListModel. Elements of the list model that are themselves instances of PythonListModel will have children.

itemContainer(item)[source]

Looks up the item’s container

itemParent(item)[source]

Looks up the item’s parent in the tree

Views

class qtypy.widgets.view.ColumnedView(model, parent=None)[source]

A multi-column view for a PythonTreeModel or PythonListModel.

BTN_ADD = 1

Standard Add button

BTN_DEL = 2

Standard Remove button

selectionChanged = None

Signal emitted when the selection changes

addButtonClicked = None

Signal emitted when the “Add” button is clicked; current selection is passed as argument.

delButtonClicked = None

Signal emitted when the “Remove” button is clicked; current selection is passed as argument.

selection()[source]

Returns the set of selected model objects

model()[source]

Returns the PythonListModel of root elements

itemContainer(item)[source]

Returns the PythonListModel that contains item

expandAll(root=None)[source]

Expands all items

setStandardButtons(buttons)[source]

Show standard buttons. The argument is an ORed combination of BTN_* values. The order and position of buttons will depend on the current platform’s HIG.

standardButton(type_)[source]

Returns the specified standard button

addButtonEnabled(selection)[source]

Called to check if the ‘Add’ button should be enabled; return a boolean. The argument is a set of currently selected items (model objects). The default returns True.

delButtonEnabled(selection)[source]

Called to check if the ‘Remove’ button should be enabled; return a boolean. The argument is a set of currently selected items (model objects). The default returns True if the selection is not empty.

saveState()[source]

Returns a bytes object encapsulating the current state (column visibility, order, etc). You can save this in your settings and use it later to restore the state using restoreState.

restoreState(state)[source]

Restore the state saved through saveState. If the versions do not match, nothing is done. Returns True if the state was restored.

addColumn(column, visible=True)[source]

Append a column (instance of a Column subclass). Returns the column instance, for chaining.

createContextMenu()[source]

This is called when then user right-clicks the view header. Return None for no context menu. You can use populateContextMenu to add actions to show/hide columns.

populateContextMenu(menu)[source]

This appends to the menu as many checkable actions as there are columns, to show or hide them.

setEditTriggers(triggers)[source]

Sets edit triggers for the underlying tree view

class qtypy.widgets.view.Column[source]

Represents a column in a tree view. When you want to display data from a PythonTreeModel, use a ColumnedView and add instances of subclasses of this class to define columns.

Various mixins are available for common behavior (checkable, editable, etc).

Constant values for setResizeMode:

Variables:
  • Interactive – Column is user-resizable
  • Stretch – Column takes all available space
  • Contents – Column is resized according to contents
nameChanged = None

This signal should be emitted if the column name changes

id()[source]

Return a persistent string identifier for this column; this is used by saveState/restoreState in ColumnedView.

name()[source]

Return the column’s name, or None.

appliesToChildrenOf(parent)[source]

Return True if this column applies to children of parent

setVisible(visible)[source]

Sets the current column visibility. This must be called after the column has been added to a view.

setResizeMode(mode)[source]

Sets the resize mode. Possible values are either class attributes Interactive, Stretch or Contents, or an integer for a fixed size.

Note

by default all columns are user-resizable, except for the last one which is stretched.

show()[source]

Short for setVisible(True)

hide()[source]

Short for setVisible(False)

labelForItem(item)[source]

Returns the text for this column for the given item. The default is to cast the item to str.

flags()[source]

Called when the model needs to know flags associated with this column.

data(item, role)[source]

Called when the model needs the item’s data for this column. Mixins override this and provide specific methods (like checkState() in CheckableColumnMixin).

setData(item, role, value)[source]

Called when the item’s data for this column has been changed by the user and must be updated. Mixins override this and provide specific methods (like setCheckState() in CheckableColumnMixin).

class qtypy.widgets.view.CheckableColumnMixin[source]

Mixin to make a column checkable.

checkState(item)[source]

Override to return the check state for the item

setCheckState(item, state)[source]

Override to update the item state

class qtypy.widgets.view.EditableColumnMixin[source]

Mixin to make a column editable with the default editor.

value(item)[source]

Override to return the item’s edit value. The default is the item’s label.

setValue(item, value)[source]

Override to update the item’s edit value.

class qtypy.widgets.view.EditableTextColumn(column_name, attr_name)[source]

Concrete column class to display an editable text attribute

name()[source]

Return the column’s name, or None.

value(item)[source]

Override to return the item’s edit value. The default is the item’s label.

setValue(item, value)[source]

Override to update the item’s edit value.

class qtypy.widgets.view.CheckColumn(column_name, attr_name)[source]

Concrete column class to display a checkbox

name()[source]

Return the column’s name, or None.

labelForItem(item)[source]

Returns the text for this column for the given item. The default is to cast the item to str.

checkState(item)[source]

Override to return the check state for the item

setCheckState(item, state)[source]

Override to update the item state

class qtypy.widgets.view.WidgetColumn(column_name)[source]

A column that display a widget for each row.

name()[source]

Return the column’s name, or None.

labelForItem(item)[source]

Returns the text for this column for the given item. The default is to cast the item to str.

widgetFactory(item, parent)[source]

Widget factory. This is what you should overload.

Parameters:
  • item – The item
  • parent – Parent for the new widget