schrodinger.ui.qt.table_speed_up module

A module for speeding up painting in Qt table and tree views. To use this module:

  • Add SpeedUpDelegateViewMixin to your table or tree view class. If your view uses multiple delegates, use MultipleSpeedUpDelegatesViewMixin instead.

  • Add MutlipleRolesRoleModelMixin to your table_helper.RowBasedTableModel model class.

  • If you have any proxies that don’t modify data (i.e. proxies for sorting or filtering), add MultipleRolesRoleProxyPassthroughMixin to them. If you have any proxies that modify data, add`MultipleRolesRoleProxyMixin` to them.

  • If defining custom roles, define roles using an enum that inherits from MultipleRolesUserRolesEnum.

  • If using custom delegates, make sure that they inherit from SpeedUpDelegate.

  • Additionally, subclass the view’s model (i.e. the top-most proxy) with FlagCacheProxyMixin to cache flags() return values.

If adding any code to this file, make sure that it doesn’t cause a slow down for any other panels that make use of this module.

class schrodinger.ui.qt.table_speed_up.SpeedUpDelegate(parent, data_cache)

Bases: PyQt6.QtWidgets.QStyledItemDelegate

A delegate that speeds up painting by:

  • Requesting all data at once using the MultipleRoles role instead of calling index.data() once per role.

  • Caching all data for the most recent indices

This delegate may be instantiated directly or subclassed if custom painting is required. If subclassing, note that data should be accessed via option.data rather than index.data().

Variables

PAINT_ROLES (frozenset) – A set of all roles used in painting. Subclasses should override this variable if they require data for additional roles.

PAINT_ROLES = frozenset({ItemDataRole.DisplayRole, ItemDataRole.DecorationRole, ItemDataRole.FontRole, ItemDataRole.TextAlignmentRole, ItemDataRole.BackgroundRole, ItemDataRole.ForegroundRole, ItemDataRole.CheckStateRole})
__init__(parent, data_cache)
Parameters
  • parent (QtWidgets.QTableView) – The parent widget

  • data_cache (DataCache) – The object to use for caching model data. Note that this cache is shared amongst all delegates and that the view, not the delegate, is responsible for clearing the cache when the model data changes.

initStyleOption(option, index)

Fetch all data from the index and load it into the style option object. In addition to the standard QStyleOptionViewItem attributes, all fetched data is stored in option.data as a dictionary of {role: value}. This way, data that doesn’t directly affect the style options can still be accessed without needing an additional index.data() call.

Note that the code for setting the attributes of option (other than data) is closely based on QStyledItemDelegage::initStyleOption.

See Qt documentation for argument documentation.

setModel(model)

Specify the model that this delegate will be fetching data from. This method must be called as soon as a model is set on the view. The model is cached because call model.data() is about four times faster than calling index.data().

Parameters

model (QtCore.QAbstractItemModel) – The model

EditNextItem = 1
EditPreviousItem = 2
class EndEditHint(value)

Bases: enum.Enum

An enumeration.

NoHint = 0
EditNextItem = 1
EditPreviousItem = 2
SubmitModelCache = 3
RevertModelCache = 4
NoHint = 0
RevertModelCache = 4
SubmitModelCache = 3
blockSignals(self, b: bool) bool
childEvent(self, a0: QChildEvent)
children(self) List[QObject]
closeEditor

closeEditor(self, editor: QWidget, hint: QAbstractItemDelegate.EndEditHint = QAbstractItemDelegate.NoHint) [signal]

commitData

commitData(self, editor: QWidget) [signal]

connectNotify(self, signal: QMetaMethod)
createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex) QWidget
customEvent(self, a0: QEvent)
deleteLater(self)
destroyEditor(self, editor: QWidget, index: QModelIndex)
destroyed

destroyed(self, object: typing.Optional[QObject] = None) [signal]

disconnect(a0: QMetaObject.Connection) bool
disconnect(self) None
disconnectNotify(self, signal: QMetaMethod)
displayText(self, value: Any, locale: QLocale) str
dumpObjectInfo(self)
dumpObjectTree(self)
dynamicPropertyNames(self) List[QByteArray]
editorEvent(self, event: QEvent, model: QAbstractItemModel, option: QStyleOptionViewItem, index: QModelIndex) bool
event(self, a0: QEvent) bool
eventFilter(self, object: QObject, event: QEvent) bool
findChild(self, type: type, name: str = '', options: Qt.FindChildOption = Qt.FindChildrenRecursively) QObject
findChild(self, types: Tuple, name: str = '', options: Qt.FindChildOption = Qt.FindChildrenRecursively) QObject
findChildren(self, type: type, name: str = '', options: Qt.FindChildOption = Qt.FindChildrenRecursively) List[QObject]
findChildren(self, types: Tuple, name: str = '', options: Qt.FindChildOption = Qt.FindChildrenRecursively) List[QObject]
findChildren(self, type: type, re: QRegularExpression, options: Qt.FindChildOption = Qt.FindChildrenRecursively) List[QObject]
findChildren(self, types: Tuple, re: QRegularExpression, options: Qt.FindChildOption = Qt.FindChildrenRecursively) List[QObject]
helpEvent(self, event: QHelpEvent, view: QAbstractItemView, option: QStyleOptionViewItem, index: QModelIndex) bool
inherits(self, classname: str) bool
installEventFilter(self, a0: QObject)
isSignalConnected(self, signal: QMetaMethod) bool
isWidgetType(self) bool
isWindowType(self) bool
itemEditorFactory(self) QItemEditorFactory
killTimer(self, id: int)
metaObject(self) QMetaObject
moveToThread(self, thread: QThread)
objectName(self) str
objectNameChanged

objectNameChanged(self, objectName: str) [signal]

paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex)
parent(self) QObject
property(self, name: str) Any
pyqtConfigure(...)

Each keyword argument is either the name of a Qt property or a Qt signal. For properties the property is set to the given value which should be of an appropriate type. For signals the signal is connected to the given value which should be a callable.

receivers(self, signal: PYQT_SIGNAL) int
removeEventFilter(self, a0: QObject)
sender(self) QObject
senderSignalIndex(self) int
setEditorData(self, editor: QWidget, index: QModelIndex)
setItemEditorFactory(self, factory: QItemEditorFactory)
setModelData(self, editor: QWidget, model: QAbstractItemModel, index: QModelIndex)
setObjectName(self, name: str)
setParent(self, a0: QObject)
setProperty(self, name: str, value: Any) bool
signalsBlocked(self) bool
sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) QSize
sizeHintChanged

sizeHintChanged(self, a0: QModelIndex) [signal]

startTimer(self, interval: int, timerType: Qt.TimerType = Qt.CoarseTimer) int
staticMetaObject = <PyQt6.QtCore.QMetaObject object>
thread(self) QThread
timerEvent(self, a0: QTimerEvent)
tr(sourceText: str, disambiguation: typing.Optional[str] = None, n: int = - 1) str
updateEditorGeometry(self, editor: QWidget, option: QStyleOptionViewItem, index: QModelIndex)
class schrodinger.ui.qt.table_speed_up.DataCache(maxlen=10000)

Bases: dict

A dictionary used for caching model data. The cache will hold data for at most MAXLEN indices. When additional data is added, the oldest data will be removed from the cache to avoid excessive memory usage.

__init__(maxlen=10000)
clear() None.  Remove all items from D.
__contains__(key, /)

True if the dictionary has the specified key, else False.

__len__()

Return len(self).

copy() a shallow copy of D
fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

items() a set-like object providing a view on D’s items
keys() a set-like object providing a view on D’s keys
pop(k[, d]) v, remove specified key and return the corresponding value.

If key is not found, d is returned if given, otherwise KeyError is raised

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) None.  Update D from dict/iterable E and F.

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values() an object providing a view on D’s values
class schrodinger.ui.qt.table_speed_up.MultipleSpeedUpDelegatesViewMixin(*args, **kwargs)

Bases: object

A mixin for QtWidgets.QAbstractItemView subclasses that cache data using SpeedUpDelegate (or a subclass) and require multiple delegates. Subclasses are required to instantiate all required delegates and must call setModel() on all delegates from view.setModel().

If only a single delegate is required, see SpeedUpDelegateViewMixin below.

Variables

DATA_CACHE_SIZE (int) – The maximum length of the DataCache cache.

DATA_CACHE_SIZE = 10000
__init__(*args, **kwargs)
setModel(model)

Connect signals so that the cache is cleared whenever it contains stale data. This needs to be done before anything else, so we connect these signals before calling the super-class setModel().

See QAbstractItemView documentation for additional method documentation.

class schrodinger.ui.qt.table_speed_up.SpeedUpDelegateViewMixin(*args, **kwargs)

Bases: schrodinger.ui.qt.table_speed_up.MultipleSpeedUpDelegatesViewMixin

A mixin for QtWidgets.QAbstractItemView subclasses that cache data using SpeedUpDelegate (or a subclass) and use a single delegate for the entire table. If multiple delegates are required, see MultipleSpeedUpDelegateViewMixin above.

Variables

DELEGATE_CLASS (type) – The class of the delegate for the table. Subclasses may override this, but the provided class must be a subclass of SpeedUpDelegate.

DELEGATE_CLASS

alias of schrodinger.ui.qt.table_speed_up.SpeedUpDelegate

__init__(*args, **kwargs)
setModel(model)

Connect signals so that the cache is cleared whenever it contains stale data. This needs to be done before anything else, so we connect these signals before calling the super-class setModel().

See QAbstractItemView documentation for additional method documentation.

DATA_CACHE_SIZE = 10000
class schrodinger.ui.qt.table_speed_up.MultipleRolesRoleModelMixin(*args, **kwargs)

Bases: schrodinger.ui.qt.table_helper.DataMethodDecoratorMixin

A mixin for models that can provide data for multiple roles at once with the MultipleRolesUserRolesEnum.MultipleRoles role. This mixin is intended for use with table_helper.RowBasedTableModel subclasses, but may be used with any QAbstractItemModel subclass that defines _genDataArgs,

data(index, role=ItemDataRole.DisplayRole, multiple_roles=None)

Provide data for the specified index and role. Subclasses normally do not need to redefine this method. Instead, new methods should be created and decorated with table_helper.data_method.

Parameters
  • index (QtCore.QModelIndex) – The index to return data for.

  • role (int) – The role to request data for.

  • multiple_roles (frozenset) – If role equals {MultipleRolesUserRolesEnum.MultipleRoles}, a set of roles to retrieve data for. Ignored otherwise.

Returns

The requested data. If role equals {MultipleRolesUserRolesEnum.MultipleRoles}, will be a dictionary of {role: value}. The dictionary not contain roles that are not provided by this model and may contain additional roles that were not explicitly requested.

Return type

object

__init__(*args, **kwargs)
class schrodinger.ui.qt.table_speed_up.MultipleRolesRoleProxyMixin(*args, **kwargs)

Bases: schrodinger.ui.qt.table_speed_up.MultipleRolesRoleModelMixin

A mixin for proxy models that can provide data for multiple roles at once with the MultipleRolesUserRolesEnum.MultipleRoles role. This mixin is only intended for proxies that provide or modify data. For proxies that sort or filter without modifying data, use MultipleRolesRoleProxyPassthroughMixin instead.

data(proxy_index, role=ItemDataRole.DisplayRole, multiple_roles=None)

Provide data for the specified index and role. Subclasses normally do not need to redefine this method. Instead, new methods should be created and decorated with table_helper.data_method.

Parameters
  • index (QtCore.QModelIndex) – The index to return data for.

  • role (int) – The role to request data for.

  • multiple_roles (frozenset) – If role equals {MultipleRolesUserRolesEnum.MultipleRoles}, a set of roles to retrieve data for. Ignored otherwise.

Returns

The requested data. If role equals {MultipleRolesUserRolesEnum.MultipleRoles}, will be a dictionary of {role: value}. The dictionary not contain roles that are not provided by this model and may contain additional roles that were not explicitly requested.

Return type

object

__init__(*args, **kwargs)
class schrodinger.ui.qt.table_speed_up.MultipleRolesRoleProxyPassthroughMixin

Bases: object

A mixin for proxy models that sort or filter a MultipleRolesRoleModelMixin model but don’t provide or modify any data. For proxies that modify or provide data, use MultipleRolesRoleProxyMixin instead.

data(proxy_index, role, multiple_roles=None)
class schrodinger.ui.qt.table_speed_up.AbstractFlagCacheProxyMixinMetaclass

Bases: PyQt6.sip.wrappertype

A metaclass for FlagCacheProxyMixin. It ensures, in the following scenario:

class MyModel(FlagCacheProxyMixin, QtCore.QAbstractProxyModel):

    def flags(self, index):
        if self.longComplicatedThing(index):
            return Qt.ItemIsSelectable | Qt.ItemIsEditable
        else:
            return Qt.NoItemFlags

my_model = MyModel()

that my_model.flags(index) will call FlagCacheProxyMixin.flags first, and that MyModel.flags is only called if the desired value is not found in the cache. Without this metaclass, MyModel.flags would instead be called first and my_model would never use the flags cache.

mro()

Determine the method resolution order for the specified class. If this class inherits from QtCore.QAbstractItemModel, then we make sure that the appropriate AbstractFlagCacheProxyMixin subclass appears first in the MRO list.

Parameters

cls (AbstractFlagCacheProxyMixin) – The class to determine the MRO for

Returns

A list of base class in desired MRO order

Return type

list(object)

__init__(*args, **kwargs)
class schrodinger.ui.qt.table_speed_up.AbstractFlagCacheProxyMixin(*args, **kwargs)

Bases: object

A mixin for QAbstractItemProxyModel subclasses to cache flags() return values. This class does not implement any caching and should not be used directly. See FlagCacheProxyMixin below instead.

Note that if this mixin is used on a non-proxy model - or on a proxy model that changes flags() return values independently of changes to the underlying source model - then the subclass is responsible for calling self._flag_cache.clear() whenever the flags() return value changes.

__init__(*args, **kwargs)
setSourceModel(model)

When this class is mixed in to a proxy model, connect signals so that the cache is cleared whenever it contains stale data. This needs to be done before anything else, so we connect these signals before calling the super-class setSourceModel().

See QAbstractItemProxyModel documentation for additional method documentation.

class schrodinger.ui.qt.table_speed_up.FlagCacheProxyMixin(*args, **kwargs)

Bases: schrodinger.ui.qt.table_speed_up.AbstractFlagCacheProxyMixin

A mixin for QAbstractItemProxyModel subclasses to cache flags() return values per-cell.

flags(index)
__init__(*args, **kwargs)
setSourceModel(model)

When this class is mixed in to a proxy model, connect signals so that the cache is cleared whenever it contains stale data. This needs to be done before anything else, so we connect these signals before calling the super-class setSourceModel().

See QAbstractItemProxyModel documentation for additional method documentation.