spacr.qt.widgets.column_aligned_row¶
A row of buttons laid out over the columns of the table underneath it.
Regression’s Input Tables category starts with a Download row – Score, Count, Measurements (.db), Image crops – and the first three of those fill one column each of the paired-data table directly below. Each button is centred on its column, and the download table’s column widths are locked to the widths of their counterparts in the paired-data table below.
ONE COLUMN MODEL, READ IN ONE DIRECTION. The build the request describes –
a second table above the first, both told to keep the same widths – is two
column models that have to be kept in step, and this repository has already
paid for that once (see the _ClusterSettingsDialog docstring on what two
editors of one setting cost). This layout owns no widths at all. It asks the
paired table’s QHeaderView where each section starts and how wide it is,
every time it lays out, and it writes nothing back: the header never learns
that a strip is following it, so there is nothing to drift.
WHY A QLayout RATHER THAN SPACERS IN A QHBoxLayout. Stretches and fixed
spacers can be tuned to line up at one column width and are wrong at every
other one, so each drag of a column edge would mean rebuilding them. A
layout’s setGeometry runs on every relayout anyway, so reading the header
there is both shorter and correct at any width; all that is left to arrange
is that a column resize causes a relayout, which is what the sectionResized
connection below is for.
WHY A BUTTON IS CLAMPED TO ITS COLUMN. Measured on a 1400x900 screen with the table’s default 100 px columns: “Measurements (.db)” wants 127 px, so left at its natural width and centred on its column it would reach 3.5 px into the Count button beside it. Two download buttons drawn overlapping is exactly the confusion the alignment exists to remove, so the button is given its column and no more – which is also what “lock the width … to the width of the paired data column counterparts below” asks for. The cost is that a label longer than its column is clipped by Qt at the default width; the full sentence is in the button’s tooltip, and widening the column shows it.
Classes¶
Lay a row of widgets out over the sections of a |
Functions¶
|
Re-lay |
Module Contents¶
- class spacr.qt.widgets.column_aligned_row.ColumnAlignedRow(header, parent: PySide6.QtWidgets.QWidget | None = None, on_invalidate=None)[source]¶
Bases:
PySide6.QtWidgets.QLayoutLay a row of widgets out over the sections of a
QHeaderView.Each managed widget carries either a column index – it is centred in that column’s span, clamped to its width – or
None, in which case it is placed in a plain left-to-right run after the last aligned column.The header is read, never written. Nothing here calls
resizeSectionor a resize mode, so the user’s own column widths remain the only source of truth for what a column is.- Parameters:
header – the
QHeaderViewwhose sections the row aligns to. READ, never written – nothing here callsresizeSectionor a resize mode, so the user’s own column widths stay the only source of the geometry.parent – parent widget.
Lay a row out against a header’s column widths.
Passing
parentinstalls this as that widget’s layout, which is why the caller has to have removed the previous one first.- Parameters:
header – the header view whose sections set the column widths; the row follows its resizes, reorders and re-layouts.
parent – the widget to become the layout of, or
None.on_invalidate – called with no arguments whenever a managed widget’s size hint changes. THE ROW CANNOT ACT ON THAT ITSELF: a button that grew needs its COLUMN widened, the header is read and never written here, and a layout that wrote back to the geometry it reads would re-enter itself on the resize it caused. So it tells whoever owns the header instead.
- addItem(item) None[source]¶
Qt’s own door, used by
addWidget: no column, so it trails.- Parameters:
item – the
QLayoutItemto manage; it is placed in the trailing run after the column-aligned widgets.
- add_over_column(widget: PySide6.QtWidgets.QWidget, column: int | None) None[source]¶
Manage
widget, centred overcolumn(Noneto trail).Separate from
addWidgetbecause Qt’s signature has no room for the column, and a column set afterwards through a second call would be a second place the pairing is written down.- Parameters:
widget – the widget to place; it is reparented to the layout’s parent widget, and
Noneor a deleted widget is ignored.column – the table’s logical column index to centre the widget over, or
Noneto put it in the trailing run. An index past the header’s end or a hidden column also trails.
- count() int[source]¶
How many items the row holds.
Part of the QLayout contract: Qt walks a layout through count, itemAt and takeAt, so all three must agree about the same list.
- Returns:
the item count.
- eventFilter(watched, event)[source]¶
Follow the table when it moves or changes size.
- Parameters:
watched – the object the event is for (the table header’s viewport); not read.
event – the event; a resize, move or show re-lays the row out. It is never consumed.
- expandingDirections()[source]¶
Horizontally only. QLayout’s default claims both, which makes the form give this one-button-high row every spare pixel of height.
- invalidate() None[source]¶
Tell the header’s owner that a managed widget changed size.
WHY THIS EXISTS AND WHAT IT COST. A button’s caption is set in English when the row is built and REPLACED by the language pass afterwards, and “Count” is 100 px where “Contagem” is 151. The column was sized once, before the translation, and the row then clamped the wider caption into the narrower column for the life of the screen – which is this class behaving exactly as documented and still showing a cut-off word.
Qt already reports the event:
setTextcallsupdateGeometry, which invalidates the parent layout. The row passes it on rather than acting, because widening a column is the header owner’s job and doing it from here would re-enter this layout.Never raises: a failed refit is a column that stays where it was, and a layout that raised here would take the whole strip with it.
- itemAt(index)[source]¶
The item at
index, or None when out of range.NONE RATHER THAN RAISING: Qt probes past the end to discover where a layout stops, so an exception here is a crash during ordinary layout.
- Parameters:
index – the position.
- Returns:
the item, or None.
- minimumSize() PySide6.QtCore.QSize[source]¶
Zero wide. A strip narrower than its buttons still shows them in the right place, because the places come from the table, not from the strip’s own width.
- setGeometry(rect: PySide6.QtCore.QRect) None[source]¶
Put each widget over its column, and the rest after them.
- Parameters:
rect – the rectangle the layout is given, in the parent widget’s coordinates; widgets are vertically centred in it.
- spacr.qt.widgets.column_aligned_row.align_row_to_columns(strip: PySide6.QtWidgets.QWidget, header, columns: Iterable[Tuple[PySide6.QtWidgets.QWidget, int | None]], on_invalidate=None) ColumnAlignedRow | None[source]¶
Re-lay
strip’s widgets out overheader’s sections.Idempotent: a strip that is already following this header is returned unchanged, so a repeated show costs nothing and cannot stack two layouts.
- Parameters:
strip – the widget holding the buttons. Its existing layout is emptied and destroyed – the widgets survive, reparented on
strip.header – the
QHeaderViewwhose columns are followed.columns –
(widget, column index or None)in the order the un-aligned ones should trail in.on_invalidate – passed to the layout; called when a managed widget’s size hint changes, so the header’s owner can re-fit the column to a caption that has since been translated.
- Returns:
the installed layout, or
Nonewhen there was nothing to do.