Skip to content

FilterHeader

Qt Base Class: QHeaderView

Signature: QHeaderView(self, orientation: PySide6.QtCore.Qt.Orientation, parent: Optional[PySide6.QtWidgets.QWidget] = None) -> None

Base classes

Name Children Inherits
HeaderView
prettyqt.widgets.headerview

⋔ Inheritance diagram

graph TD
  1473367134080["custom_widgets.FilterHeader"]
  1473296214896["widgets.HeaderView"]
  1473296228560["widgets.HeaderViewMixin"]
  1473293692144["widgets.AbstractItemViewMixin"]
  1473293679456["widgets.AbstractScrollAreaMixin"]
  1473293662864["widgets.FrameMixin"]
  1473293688240["widgets.WidgetMixin"]
  1473299815024["core.ObjectMixin"]
  140713234304496["builtins.object"]
  1473245548480["gui.PaintDeviceMixin"]
  1473241471584["QtWidgets.QHeaderView"]
  1473241438400["QtWidgets.QAbstractItemView"]
  1473290616416["QtWidgets.QAbstractScrollArea"]
  1473290626176["QtWidgets.QFrame"]
  1473290849680["QtWidgets.QWidget"]
  1473288842240["QtCore.QObject"]
  1473291690208["Shiboken.Object"]
  1473300082368["QtGui.QPaintDevice"]
  1473296214896 --> 1473367134080
  1473296228560 --> 1473296214896
  1473293692144 --> 1473296228560
  1473293679456 --> 1473293692144
  1473293662864 --> 1473293679456
  1473293688240 --> 1473293662864
  1473299815024 --> 1473293688240
  140713234304496 --> 1473299815024
  1473245548480 --> 1473293688240
  140713234304496 --> 1473245548480
  1473241471584 --> 1473296214896
  1473241438400 --> 1473241471584
  1473290616416 --> 1473241438400
  1473290626176 --> 1473290616416
  1473290849680 --> 1473290626176
  1473288842240 --> 1473290849680
  1473291690208 --> 1473288842240
  140713234304496 --> 1473291690208
  1473300082368 --> 1473290849680
  1473291690208 --> 1473300082368

🛈 DocStrings

Bases: HeaderView

A HeaderView subclass which includes widgets with filter possibilities.

When setting the header view on an ItemView, a proxy model will be created which is linked to the filter widgets. The correct filter widget is automatically inferred from the content of the columns.

So basically everything that needs to be done is the following:

model = MyModel()
widget = widgets.TableView()
widget.set_model(model)
widget.h_header = custom_widgets.FilterHeader() # same as setHorizontalHeader()

and you will get filter capabilities for your table.

Note

Since the FilterHeader will infer the column content type based on the first few rows, it will only work correctly for tables with homogenous data.

Image title

FilterHeader widget
Source code in prettyqt\custom_widgets\itemviews\filterheader.py
class FilterHeader(widgets.HeaderView):
    """A HeaderView subclass which includes widgets with filter possibilities.

    When setting the header view on an ItemView, a proxy model will be created which is
    linked to the filter widgets.
    The correct filter widget is automatically inferred from the content of the columns.

    So basically everything that needs to be done is the following:

    ```py
    model = MyModel()
    widget = widgets.TableView()
    widget.set_model(model)
    widget.h_header = custom_widgets.FilterHeader() # same as setHorizontalHeader()
    ```

    and you will get filter capabilities for your table.

    !!! note
        Since the FilterHeader will infer the column content type based on the first few
        rows, it will only work correctly for tables with homogenous data.

    <figure markdown>
      ![Image title](../../images/filterheader.png)
      <figcaption>FilterHeader widget</figcaption>
    </figure>

    """

    def __init__(self, parent: widgets.TableView):
        self._editors_visible = False
        self._editors = []
        self._proxy = parent.proxifier.get_proxy(
            "multi_column_filter",
            recursive_filtering_enabled=True,
        )
        self._padding = 6
        super().__init__(constants.HORIZONTAL, parent)
        self.setStretchLastSection(True)
        # self.setResizeMode(QHeaderView.Stretch)
        self.setDefaultAlignment(constants.ALIGN_CENTER_LEFT)
        # self.setSortIndicatorShown(False)
        self.sectionResized.connect(self._adjust_positions)
        parent.h_scrollbar.valueChanged.connect(self._adjust_positions)
        parent.model_changed.connect(self._update_filter_boxes)
        self.sectionResized.connect(self._adjust_positions)
        self._update_filter_boxes()
        self.update_geometries()

    @classmethod
    def setup_example(cls):
        w = widgets.TableView()
        widget = cls(parent=w)
        return widget

    def are_editors_visible(self) -> bool:
        return self._editors_visible

    def set_editors_visible(self, visible: bool):
        self._editors_visible = visible
        for editor in self._editors:
            editor.setVisible(visible)
        self.updateGeometries()

    def _update_filter_boxes(self):
        # TODO: deal with column changes by connecting to Model signals.
        # That way we wouldnt have to update all editors on change.
        while self._editors:
            editor = self._editors.pop()
            editor.deleteLater()
        self.create_editors()
        self._adjust_positions()

    def create_editors(self):
        # using parent model here bc we cant guarantee that we are already set to view.
        parent = self.parent()
        model = parent.model()
        self._proxy.clear_filters()
        for i in range(model.columnCount()):
            typ = model.get_column_type(i)
            if typ is bool:

                def set_filter(val, i=i):
                    self._proxy.set_filter_value(i, val, constants.CHECKSTATE_ROLE)

                name = f"filter_combo_{i}"
                widget = widgets.ComboBox(margin=0, object_name=name, parent=self)
                widget.add_items(BOOL_ITEMS)
                widget.value_changed.connect(set_filter)
            elif typ in [int, float]:

                def set_filter(val, i=i):
                    self._proxy.set_filter_value(i, val)

                name = f"filter_numwidget_{i}"
                widget = custom_widgets.NumFilterWidget(
                    margin=0, object_name=name, parent=self
                )
                widget.filter_changed.connect(set_filter)
                title = model.headerData(i, constants.HORIZONTAL, constants.DISPLAY_ROLE)
                widget.lineedit.setPlaceholderText(f"Filter {title}...")
            elif typ is str:

                def set_filter(val, i=i):
                    self._proxy.set_filter_value(i, val)

                name = f"filter_lineedit_{i}"
                widget = widgets.LineEdit(margin=0, object_name=name, parent=self)
                widget.value_changed.connect(set_filter)
                title = model.headerData(i, constants.HORIZONTAL, constants.DISPLAY_ROLE)
                widget.setPlaceholderText(f"Filter {title}...")
            else:
                widget = widgets.Widget()
            widget.show()
            self._editors.append(widget)

    def sizeHint(self) -> core.QSize:
        size = super().sizeHint()
        if self._editors:
            height = self._editors[0].sizeHint().height()
            size.setHeight(size.height() + height + self._padding)
        return size

    def updateGeometries(self):
        if self._editors:
            height = self._editors[0].sizeHint().height()
            self.setViewportMargins(0, 0, 0, height + self._padding)
        else:
            self.setViewportMargins(0, 0, 0, 0)
        super().updateGeometries()
        self._adjust_positions()

    def _adjust_positions(self):
        for index, editor in enumerate(self._editors):
            height = editor.sizeHint().height()
            compensate_y = 0
            compensate_x = 0
            match editor:
                case widgets.QComboBox():
                    compensate_y = +2
                case widgets.QPushButton():
                    compensate_y = -1
                case widgets.QCheckBox():
                    compensate_y = 4
                    compensate_x = 4
                case widgets.QWidget():
                    compensate_y = -1
            editor.move(
                self.sectionPosition(index) - self.offset() + 1 + compensate_x,
                height + (self._padding // 2) + compensate_y,
            )
            editor.resize(self.sectionSize(index), height)

    def set_filter_case_sensitive(self, value: bool):
        self._proxy.set_filter_case_sensitive(value)

    def clear_filters(self):
        for editor in self._editors:
            editor.clear()

    editors_visible = core.Property(
        bool,
        are_editors_visible,
        set_editors_visible,
        doc="Whether the filter widgets are visible",
    )

⌗ Property table

Qt Property Type Doc
objectName QString
modal bool
windowModality Qt::WindowModality
enabled bool
geometry QRect
frameGeometry QRect
normalGeometry QRect
x int
y int
pos QPoint
frameSize QSize
size QSize
width int
height int
rect QRect
childrenRect QRect
childrenRegion QRegion
sizePolicy QSizePolicy
minimumSize QSize
maximumSize QSize
minimumWidth int
minimumHeight int
maximumWidth int
maximumHeight int
sizeIncrement QSize
baseSize QSize
palette QPalette
font QFont
cursor QCursor
mouseTracking bool
tabletTracking bool
isActiveWindow bool
focusPolicy Qt::FocusPolicy
focus bool
contextMenuPolicy Qt::ContextMenuPolicy
updatesEnabled bool
visible bool
minimized bool
maximized bool
fullScreen bool
sizeHint QSize
minimumSizeHint QSize
acceptDrops bool
windowTitle QString
windowIcon QIcon
windowIconText QString
windowOpacity double
windowModified bool
toolTip QString
toolTipDuration int
statusTip QString
whatsThis QString
accessibleName QString
accessibleDescription QString
layoutDirection Qt::LayoutDirection
autoFillBackground bool
styleSheet QString
locale QLocale
windowFilePath QString
inputMethodHints QFlags
frameShape QFrame::Shape
frameShadow QFrame::Shadow
lineWidth int
midLineWidth int
frameWidth int
frameRect QRect
verticalScrollBarPolicy Qt::ScrollBarPolicy
horizontalScrollBarPolicy Qt::ScrollBarPolicy
sizeAdjustPolicy QAbstractScrollArea::SizeAdjustPolicy
autoScroll bool
autoScrollMargin int
editTriggers QFlags
tabKeyNavigation bool
showDropIndicator bool
dragEnabled bool
dragDropOverwriteMode bool
dragDropMode QAbstractItemView::DragDropMode
defaultDropAction Qt::DropAction
alternatingRowColors bool
selectionMode QAbstractItemView::SelectionMode
selectionBehavior QAbstractItemView::SelectionBehavior
iconSize QSize
textElideMode Qt::TextElideMode
verticalScrollMode QAbstractItemView::ScrollMode
horizontalScrollMode QAbstractItemView::ScrollMode
firstSectionMovable bool
showSortIndicator bool
highlightSections bool
stretchLastSection bool
cascadingSectionResizes bool
defaultSectionSize int
minimumSectionSize int
maximumSectionSize int
defaultAlignment QFlags
sortIndicatorClearable bool
editors_visible bool Whether the filter widgets are visible

🖼 Screenshot