Skip to content

ColumnJoinerProxyModel

Qt Base Class: QAbstractProxyModel

Signature: QAbstractProxyModel(self, parent: Optional[PySide6.QtCore.QObject] = None) -> None

Base classes

Name Children Inherits
AbstractProxyModel
prettyqt.core.abstractproxymodel

⋔ Inheritance diagram

graph TD
  1473290761840["itemmodels.ColumnJoinerProxyModel"]
  1473299891152["core.AbstractProxyModel"]
  1473299903840["core.AbstractProxyModelMixin"]
  1473299890176["core.AbstractItemModelMixin"]
  1473299815024["core.ObjectMixin"]
  140713234304496["builtins.object"]
  1473289061840["QtCore.QAbstractProxyModel"]
  1473289050128["QtCore.QAbstractItemModel"]
  1473288842240["QtCore.QObject"]
  1473291690208["Shiboken.Object"]
  1473299891152 --> 1473290761840
  1473299903840 --> 1473299891152
  1473299890176 --> 1473299903840
  1473299815024 --> 1473299890176
  140713234304496 --> 1473299815024
  1473289061840 --> 1473299891152
  1473289050128 --> 1473289061840
  1473288842240 --> 1473289050128
  1473291690208 --> 1473288842240
  140713234304496 --> 1473291690208

🛈 DocStrings

Bases: AbstractProxyModel

Proxy model which joins the contents of several columns.

The columns are joined based on a formatter and appended to the end of the model as a new column.

The formatter must look like {0} - {1}: {4}. The format codes are then populated with the content of given columns, in this case it would be {Text of column 0} - {Text of Column 1}: {Text of Column 4}

Example

table.proxifier.join_columns(formatter="{0} - {2}", header="New column")
table.show()
# or
model = MyModel()
proxy = ColumnJoinerProxyModel()
proxy.set_source_model(model)
proxy.add_column(formatter="{0} - {2}", header="New column")
proxy.add_column(formatter="{4}: {5}", header="Another column")
table.set_model(proxy)
table.show()

data = dict(first=["John", "Mary"], last=["Doe", "Bo"])
model = gui.StandardItemModel.from_dict(data)
table = widgets.TableView()
table.set_model(model)
# table.proxifier.add_column(header="Full name", formatter="{1}, {0}")
table.show()
Image title

data = dict(first=["John", "Mary"], last=["Doe", "Bo"])
model = gui.StandardItemModel.from_dict(data)
table = widgets.TableView()
table.set_model(model)
table.proxifier.add_column(header="Full name", formatter="{1}, {0}")
table.show()
Image title

Source code in prettyqt\itemmodels\proxies\columnjoinerproxymodel.py
class ColumnJoinerProxyModel(core.AbstractProxyModel):
    """Proxy model which joins the contents of several columns.

    The columns are joined based on a formatter and appended to the end of the model
    as a new column.

    The formatter must look like `{0} - {1}: {4}`.
    The format codes are then populated with the content of given columns,
    in this case it would be `{Text of column 0} - {Text of Column 1}: {Text of Column 4}`

    ### Example

    ```py
    table.proxifier.join_columns(formatter="{0} - {2}", header="New column")
    table.show()
    # or
    model = MyModel()
    proxy = ColumnJoinerProxyModel()
    proxy.set_source_model(model)
    proxy.add_column(formatter="{0} - {2}", header="New column")
    proxy.add_column(formatter="{4}: {5}", header="Another column")
    table.set_model(proxy)
    table.show()
    ```

    === "Without proxy"

        ```py
        data = dict(first=["John", "Mary"], last=["Doe", "Bo"])
        model = gui.StandardItemModel.from_dict(data)
        table = widgets.TableView()
        table.set_model(model)
        # table.proxifier.add_column(header="Full name", formatter="{1}, {0}")
        table.show()

        ```
        <figure markdown>
          ![Image title](../../images/columnjoinerproxymodel_before.png)
        </figure>

    === "With proxy"

        ```py
        data = dict(first=["John", "Mary"], last=["Doe", "Bo"])
        model = gui.StandardItemModel.from_dict(data)
        table = widgets.TableView()
        table.set_model(model)
        table.proxifier.add_column(header="Full name", formatter="{1}, {0}")
        table.show()
        ```
        <figure markdown>
          ![Image title](../../images/columnjoinerproxymodel_after.png)
        </figure>
    """

    ID = "column_join"
    ICON = "mdi.table-column-plus-before"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.mapping = []

    def columnCount(self, parent: core.ModelIndex | None = None) -> int:
        parent = parent or core.ModelIndex()
        return (
            0
            if self.sourceModel() is None
            else self.sourceModel().columnCount(parent) + len(self.mapping)
        )

    def rowCount(self, parent: core.ModelIndex | None = None) -> int:
        return self.sourceModel().rowCount()

    def flags(self, index: core.ModelIndex) -> constants.ItemFlag:
        column = index.column()
        if self.is_additional_column(column):
            flags = self.mapping[column - self.columnCount()].flags
            return (
                flags
                if flags is not None
                else constants.IS_ENABLED | constants.IS_SELECTABLE
            )
        return self.sourceModel().flags(index)

    def is_additional_column(self, column: int):
        col_count = self.sourceModel().columnCount()
        return column >= col_count

    def index(self, row: int, column: int, parent: core.ModelIndex | None = None):
        parent = parent or core.ModelIndex()
        if self.is_additional_column(column):
            return self.createIndex(row, column, core.ModelIndex())
        return self.sourceModel().index(row, column, parent)

    def parent(self, index=None):
        if index is None:
            return super().parent()
        if self.is_additional_column(index.column()):
            return core.ModelIndex()
        return self.sourceModel().parent(index)

    def data(
        self,
        index: core.ModelIndex,
        role: constants.ItemDataRole = constants.DISPLAY_ROLE,
    ):
        col_count = self.sourceModel().columnCount()
        column = index.column()
        if self.is_additional_column(column):
            if role == constants.DISPLAY_ROLE:
                mapper = self.mapping[column - col_count]
                formatter = mapper.formatter
                field_names = [
                    field_name
                    for (
                        _literal_text,
                        field_name,
                        _format_spec,
                        _conversion,
                    ) in string.Formatter().parse(formatter)
                    # if field_name is not None
                ]
                match formatter:
                    case str():
                        for name in field_names:
                            idx = self.index(index.row(), int(name), index.parent())
                            data = self.data(idx)
                            formatter = formatter.replace(f"{{{name}}}", data)
                        return formatter
                    case Callable():
                        return formatter(index)
            return None
        return super().data(index, role)

    def headerData(
        self,
        section: int,
        orientation: constants.Orientation,
        role: constants.ItemDataRole = constants.DISPLAY_ROLE,
    ):
        if orientation == constants.HORIZONTAL and self.is_additional_column(section):
            if role == constants.DISPLAY_ROLE:
                mapper = self.mapping[section - self.columnCount()]
                return mapper.header
            return None
        return super().headerData(section, orientation, role)

    def mapToSource(self, proxy_index):
        if not proxy_index.isValid():
            return core.ModelIndex()
        column = proxy_index.column()
        if self.is_additional_column(column):
            return core.ModelIndex()
        return self.sourceModel().index(proxy_index.row(), column, proxy_index.parent())

    def mapFromSource(self, index):
        if self.is_additional_column(index.column()):
            return core.ModelIndex()
        return self.sourceModel().index(index.row(), index.column(), index.parent())

    def add_mapping(
        self, header: str, formatter: str, flags: constants.ItemFlag | None = None
    ):
        """Add a new column to the table.

        Arguments:
            header: Label used for the section header.
            formatter: String formatter (example "{0}: {1}")
            flags: ItemFlags for new column
        """
        self.mapping.append(ColumnMapping(formatter, header, flags))

add_mapping(header: str, formatter: str, flags: constants.ItemFlag | None = None)

Add a new column to the table.

Parameters:

Name Type Description Default
header str

Label used for the section header.

required
formatter str

String formatter (example "{0}: {1}")

required
flags ItemFlag | None

ItemFlags for new column

None
Source code in prettyqt\itemmodels\proxies\columnjoinerproxymodel.py
def add_mapping(
    self, header: str, formatter: str, flags: constants.ItemFlag | None = None
):
    """Add a new column to the table.

    Arguments:
        header: Label used for the section header.
        formatter: String formatter (example "{0}: {1}")
        flags: ItemFlags for new column
    """
    self.mapping.append(ColumnMapping(formatter, header, flags))

⌗ Property table

Qt Property Type Doc
objectName QString
sourceModel QAbstractItemModel