Skip to main content

qtflex - responsive width adaptation for Qt

Qt widgets don't adapt their labels to available width. qtflex adds a small, cooperating set: a container that measures and broadcasts a width CLASS, and consumers (action bars, tree headers) that adapt to it - CSS-media-query thinking, but content-driven instead of pixel breakpoints. Plus FloorCap: a one-line fix for child widgets that hard-floor your window's minimum size.

Bindings: PySide6 (tested live), PyQt6 (import-smoked), PySide2/PyQt5 (supported by the shim, untested). Zero dependencies beyond your Qt binding.

ResponsiveContainer

A width-broadcasting parent. Emits width_class_changed(str) with 'full' | 'compact' | 'min', classified against the CONTENT (member children's natural width vs available), not magic px:

  • full: everything fits at natural width
  • compact: fits only when children shrink (>= 60% of natural)
  • min: the floor

API: add(w, member=True) (member widths define the breakpoints), add_layout(l), add_stretch(), layout_box(), width_class property.

Implementation note: a Qt container cannot shrink below its children's minimumSizeHint, so the container uses Ignored horizontal size policy and classifies against the resize EVENT width, never self.width().

ResponsiveBar

An action bar that degrades gracefully as width shrinks, in order:

  1. PROMOTE: restore wider label tiers while they fit
  2. compress spacing (max_spacing -> min_spacing)
  3. DEMOTE: the widest button with a shorter tier drops one tier (repeat)
  4. SPILL: at the tier floor, lowest-priority buttons hide into a » overflow menu (menu label = shortest tier, click = original handler). The bar is never fully empty - the highest-priority button always stays visible.

API:

  • add_button(tiers, tooltip=None, on_click=None, style=None, cursor=True, priority=100) - tiers is a list widest->shortest, e.g. ["Re-read all ({n})", "Re-read {n}", "RR"]; {n} templates update via set_count(btn, n). Lower priority spills first. Returns the QPushButton.
  • add_widget(w) - fixed pass-through widget (dropdown, LED), never demoted.
  • add_stretch()
  • subscribe_to(container) - drive layout from a ResponsiveContainer; bars sharing one container demote in concert. Without it the bar self-measures via its own resizeEvent.

Constructor: min_spacing=1, max_spacing=6, margins=(5, 0, 5, 5), spill=True, demote="staged", compact_counts=False.

  • spill=False: buttons stop at their shortest tier, no overflow menu; below the floor they shrink proportionally (elide) rather than paint past the bar's edges.
  • demote="staged" (default): buttons demote one step at a time, ordered by the tier FRACTION the step would reach - unequal tier-list lengths degrade proportionally, no button hits its floor while others sit untouched. Promotion mirrors this: the deepest-demoted (by fraction) recovers first, with a hysteresis band so boundary widths never flap. ("uniform" reserved, not yet implemented.)
  • compact_counts=True: {n} counts render as 1.1k / 2.3M above 999, keeping label width bounded as counts grow. set_count re-runs the layout, so a growing number can trigger demotion without a resize.

Tier state is tracked internally (never re-derived from button text) - count changes cannot desync the tier machine.

Driving the bar from a parent widget instead of a ResponsiveContainer: set bar._driven = True and call bar._apply_layout(bar.width()) from the parent's resizeEvent. Exactly ONE width source per bar - a bar fed by two sources (own resizeEvent + a parent driver) will oscillate.

ResponsiveHeader

Column collapse for QTreeView/QTreeWidget, same priority vocabulary. ResponsiveHeader(tree, {2: 10, 3: 20}) - lower priority hides first; column 0 is never hidden; unlisted columns default to priority 100. apply(width_class): full = all shown; compact = hide 1; min = hide half. subscribe_to(container) joins the same broadcast.

Wiring

from qtflex import ResponsiveBar, ResponsiveContainer, ResponsiveHeader

cont = ResponsiveContainer()
bar = ResponsiveBar()
cont.add(bar)
bar.subscribe_to(cont)
hdr = ResponsiveHeader(tree, {2: 10, 3: 20})
hdr.subscribe_to(cont)

qtcompat

Internal binding shim (PySide6 > PySide2 > PyQt6 > PyQt5, first importable wins); Signal normalized across PySide/PyQt. qtflex.QT_BINDING names the active binding.

FloorCap - stop child widgets from hard-flooring your window

Qt sums every child's minimumSizeHint into the window's hard minimum; a multi-pane panel can silently block window-edge resize at ~window width. setSizePolicy(Ignored) does NOT shrink the hint - only an override does.

from qtflex import FloorCap, floor_cap

class MyPanel(FloorCap, QWidget):   # mixin form
    FLOOR_W = 200

Capped = floor_cap(SomePanel, w=200)  # wrapper form

License

MIT

Metadata

Release files for qtflex 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qtflex 0.1.3
File Size Uploaded Provenance
qtflex-0.1.3.tar.gz 9.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for qtflex 0.1.3
File Interpreter ABI Platform
qtflex-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 20.8 kB

Release files / qtflex-0.1.3.tar.gz

Download URL qtflex-0.1.3.tar.gz
Size 9.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d8bd86b7e0156c01ca2449a70b38141a47b3d4e39446a2c522623122336f2ce2
BLAKE2b-256 checksum
How to use checksums
0a31fea67ac265a0c377d37cbe458d3b8e9489319081466f42928e963f4e9659
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.

Transparency log

Release files / qtflex-0.1.3-py3-none-any.whl

Download URL qtflex-0.1.3-py3-none-any.whl
Size 11.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1b9af1029500eadba2c83bb18fcd0670a7a15eb1390490b165cde00adaa90625
BLAKE2b-256 checksum
How to use checksums
a5ba0b13c19694b59ff2796a2beea5fd030d884b9098acad8c19b1cb9f26a9a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.

Transparency log

Security for qtflex 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for qtflex-0.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page