Compact Window Patterns

Compact window patterns enable minimal UI layouts that work well on smaller screens and when tiling multiple windows side-by-side.

Overview

Traditional form dialogs often require large minimum widths to accommodate titles, help buttons, and action buttons in a single row. The compact window pattern separates these elements into multiple rows, allowing windows to be much narrower while maintaining usability.

Two-Row Header Pattern

The two-row header pattern separates the window title from action buttons:

Row 1: Title and help button Row 2: Action buttons (Save, Cancel, Reset, etc.)

Traditional Single-Row Layout:

[Configure MyClass] [?]          [View Code] [Reset] [Cancel] [Save]

Minimum width: 600-800px

Compact Two-Row Layout:

[Configure MyClass] [?]
[View Code] [Reset] [Cancel] [Save]

Minimum width: 150-400px

Implementation

Using _create_compact_header Helper

The BaseManagedWindow class provides a helper for creating compact headers:

from pyqt_reactive.widgets.shared.base_form_dialog import BaseManagedWindow

class MyConfigWindow(BaseManagedWindow):
    def setup_ui(self):
        layout = QVBoxLayout(self)

        # Create compact two-row header
        title_label, button_layout = self._create_compact_header(
            layout,
            title_text="Configure MyClass",
            title_color=self.color_scheme.to_hex(
                self.color_scheme.text_accent
            )
        )

        # Add action buttons to button row
        save_btn = QPushButton("Save")
        cancel_btn = QPushButton("Cancel")
        button_layout.addWidget(save_btn)
        button_layout.addWidget(cancel_btn)

Manual Implementation

You can also implement the pattern manually:

def setup_ui(self):
    layout = QVBoxLayout(self)

    # Row 1: Title
    title_widget = QWidget()
    title_layout = QHBoxLayout(title_widget)

    self.header_label = QLabel("Window Title")
    self.header_label.setFont(QFont("Arial", 14, QFont.Weight.Bold))
    title_layout.addWidget(self.header_label)
    title_layout.addStretch()

    layout.addWidget(title_widget)

    # Row 2: Buttons
    button_widget = QWidget()
    button_layout = QHBoxLayout(button_widget)
    button_layout.addStretch()

    save_btn = QPushButton("Save")
    cancel_btn = QPushButton("Cancel")
    button_layout.addWidget(save_btn)
    button_layout.addWidget(cancel_btn)

    layout.addWidget(button_widget)

Window Size Guidelines

Minimum Sizes

For compact windows, use these minimum sizes:

  • Minimum width: 150px (ultra-minimal, allows narrow tiling)

  • Default width: 400-500px (comfortable for most content)

  • Minimum height: 150px (just enough for header + some content)

Example from ConfigWindow:

self.setMinimumSize(150, 150)  # Ultra minimal
self.resize(400, 400)          # Default size

Benefits

Screen Space Efficiency

  • Side-by-side tiling: Two windows fit comfortably on a 1920px wide monitor

  • Laptop screens: Works well on smaller screens (1366px, 1440px)

  • Multi-monitor setups: Allows dense window arrangements

Improved Usability

  • Reduced eye movement: Buttons are closer to content

  • Better focus: Title is prominent at top

  • Scannable layout: Clear visual hierarchy

Integration with Responsive Widgets

Combine compact headers with responsive layouts for maximum flexibility:

from pyqt_reactive.widgets.shared.responsive_layout_widgets import (
    set_wrapping_enabled
)

# Enable responsive wrapping
set_wrapping_enabled(True)

# Create compact window
window = ConfigWindow(config_class=MyConfig)

# Parameter rows will wrap when narrow
# Window can be very narrow while remaining usable

Examples

ConfigWindow

class ConfigWindow(BaseFormDialog):
    def setup_ui(self):
        self.setMinimumSize(150, 150)
        self.resize(400, 400)

        layout = QVBoxLayout(self)

        # Compact two-row header
        title_text = f"Configure {self.config_class.__name__}"
        title_color = self.color_scheme.to_hex(
            self.color_scheme.text_accent
        )
        self._header_label, button_layout = self._create_compact_header(
            layout, title_text, title_color
        )

        # Add help button to title row
        help_btn = HelpButton(help_target=self.config_class)
        title_row = self._header_label.parent().layout()
        title_row.insertWidget(1, help_btn)

        # Add action buttons to button row
        button_layout.addWidget(view_code_btn)
        button_layout.addWidget(reset_btn)
        button_layout.addWidget(cancel_btn)
        button_layout.addWidget(save_btn)

DualEditorWindow

class DualEditorWindow(BaseFormDialog):
    def setup_ui(self):
        self.setMinimumSize(150, 150)
        self.resize(400, 400)

        layout = QVBoxLayout(self)

        # Row 1: Title only
        title_widget = QWidget()
        title_layout = QHBoxLayout(title_widget)

        self.header_label = QLabel()
        self.header_label.setFont(
            QFont("Arial", 14, QFont.Weight.Bold)
        )
        title_layout.addWidget(self.header_label)
        title_layout.addStretch()

        layout.addWidget(title_widget)

        # Row 2: Tabs and buttons
        control_row = QHBoxLayout()
        control_row.addWidget(self.tab_bar, 0)
        control_row.addStretch()
        control_row.addWidget(cancel_btn)
        control_row.addWidget(save_btn)

        layout.addLayout(control_row)

See Also