Skip to content

Input Widgets

Text input widgets with auto-completion, password management, search history, and tab sanitization.


AutoCompleteInput

A QLineEdit subclass with a built-in QCompleter powered by a configurable list of string suggestions.

Constructor parameters:

Parameter Type Default Description
parent QWidget \| None None Parent widget
suggestions list[str] \| None None Initial list of completion candidates
case_sensitive bool False Whether completion matching is case-sensitive
filter_mode Qt.MatchFlag Qt.MatchFlag.MatchContains How typed text is matched against suggestions
completion_mode QCompleter.CompletionMode QCompleter.CompletionMode.PopupCompletion How completions are presented

Properties:

Property Type Description
suggestions list[str] Gets or sets the full list of completion candidates (returns a copy)
case_sensitive bool Gets or sets case-sensitivity of matching
filter_mode Qt.MatchFlag Gets or sets the filter mode
completion_mode QCompleter.CompletionMode Gets or sets the completion mode

Methods:

Method Signature Description
addSuggestion() (suggestion: str) -> None Adds a candidate if it is not already present
removeSuggestion() (suggestion: str) -> None Removes a candidate if it exists
clearSuggestions() () -> None Removes all candidates
refreshStyle() () -> None Re-applies the QSS stylesheet

Example:

from PySide6.QtWidgets import QApplication
from ezqt_widgets import AutoCompleteInput

app = QApplication([])

inp = AutoCompleteInput(
    suggestions=["Python", "PySide6", "Qt", "PyQt6"],
    case_sensitive=False,
)
inp.addSuggestion("Rust")
inp.show()

app.exec()

AutoCompleteInput

AutoCompleteInput(parent: WidgetParent = None, suggestions: list[str] | None = None, case_sensitive: bool = False, filter_mode: MatchFlag = MatchContains, completion_mode: CompletionMode = PopupCompletion, *args: Any, **kwargs: Any)

Bases: QLineEdit

QLineEdit subclass with autocompletion support.

Provides a text input widget with autocompletion functionality. You can provide a list of suggestions (strings) to be used for autocompletion.

PARAMETER DESCRIPTION
parent

The parent widget (default: None).

TYPE: WidgetParent DEFAULT: None

suggestions

List of strings to use for autocompletion (default: empty list).

TYPE: list[str] | None DEFAULT: None

case_sensitive

Whether the autocompletion is case sensitive (default: False).

TYPE: bool DEFAULT: False

filter_mode

Filter mode for completion (default: Qt.MatchFlag.MatchContains).

TYPE: MatchFlag DEFAULT: MatchContains

completion_mode

Completion mode (default: QCompleter.CompletionMode.PopupCompletion).

TYPE: CompletionMode DEFAULT: PopupCompletion

*args

Additional arguments passed to QLineEdit.

TYPE: Any DEFAULT: ()

**kwargs

Additional keyword arguments passed to QLineEdit.

TYPE: Any DEFAULT: {}

Properties

suggestions: Get or set the list of suggestions for autocompletion. case_sensitive: Get or set whether autocompletion is case sensitive. filter_mode: Get or set the filter mode for completion. completion_mode: Get or set the completion mode.

Example

from ezqt_widgets import AutoCompleteInput inp = AutoCompleteInput(suggestions=["Alice", "Bob", "Charlie"]) inp.case_sensitive = False inp.suggestions = ["Alice", "Bob", "Charlie", "Dave"] inp.show()

Initialize the auto-complete input.

Source code in src/ezqt_widgets/widgets/input/auto_complete_input.py
def __init__(
    self,
    parent: WidgetParent = None,
    suggestions: list[str] | None = None,
    case_sensitive: bool = False,
    filter_mode: Qt.MatchFlag = Qt.MatchFlag.MatchContains,
    completion_mode: QCompleter.CompletionMode = QCompleter.CompletionMode.PopupCompletion,
    *args: Any,
    **kwargs: Any,
) -> None:
    """Initialize the auto-complete input."""
    super().__init__(parent, *args, **kwargs)

    # Initialize properties
    self._suggestions: list[str] = suggestions or []
    self._case_sensitive: bool = case_sensitive
    self._filter_mode: Qt.MatchFlag = filter_mode
    self._completion_mode: QCompleter.CompletionMode = completion_mode

    # Setup completer
    self._setup_completer()

suggestions property writable

suggestions: list[str]

Get the list of suggestions.

RETURNS DESCRIPTION
list[str]

A copy of the current suggestions list.

case_sensitive property writable

case_sensitive: bool

Get whether autocompletion is case sensitive.

RETURNS DESCRIPTION
bool

True if case sensitive, False otherwise.

filter_mode property writable

filter_mode: MatchFlag

Get the filter mode for completion.

RETURNS DESCRIPTION
MatchFlag

The current filter mode.

completion_mode property writable

completion_mode: CompletionMode

Get the completion mode.

RETURNS DESCRIPTION
CompletionMode

The current completion mode.

addSuggestion

addSuggestion(suggestion: str) -> None

Add a suggestion to the list.

PARAMETER DESCRIPTION
suggestion

The suggestion string to add.

TYPE: str

Source code in src/ezqt_widgets/widgets/input/auto_complete_input.py
def addSuggestion(self, suggestion: str) -> None:
    """Add a suggestion to the list.

    Args:
        suggestion: The suggestion string to add.
    """
    if suggestion and suggestion not in self._suggestions:
        self._suggestions.append(suggestion)
        self._model.setStringList(self._suggestions)

removeSuggestion

removeSuggestion(suggestion: str) -> None

Remove a suggestion from the list.

PARAMETER DESCRIPTION
suggestion

The suggestion string to remove.

TYPE: str

Source code in src/ezqt_widgets/widgets/input/auto_complete_input.py
def removeSuggestion(self, suggestion: str) -> None:
    """Remove a suggestion from the list.

    Args:
        suggestion: The suggestion string to remove.
    """
    if suggestion in self._suggestions:
        self._suggestions.remove(suggestion)
        self._model.setStringList(self._suggestions)

clearSuggestions

clearSuggestions() -> None

Clear all suggestions.

Source code in src/ezqt_widgets/widgets/input/auto_complete_input.py
def clearSuggestions(self) -> None:
    """Clear all suggestions."""
    self._suggestions.clear()
    self._model.setStringList(self._suggestions)

refreshStyle

refreshStyle() -> None

Refresh the widget's style.

Useful after dynamic stylesheet changes.

Source code in src/ezqt_widgets/widgets/input/auto_complete_input.py
def refreshStyle(self) -> None:
    """Refresh the widget's style.

    Useful after dynamic stylesheet changes.
    """
    self.style().unpolish(self)
    self.style().polish(self)
    self.update()

PasswordInput

A QWidget containing a QLineEdit in password mode, an optional colored strength bar, and a visibility-toggle icon.

Signals:

Signal Signature Emitted when
strengthChanged (int) The password text changes; value is the new strength score (0–100)
iconClicked () The visibility-toggle icon is clicked

Constructor parameters:

Parameter Type Default Description
parent QWidget \| None None Parent widget
show_strength bool True Whether to display the strength progress bar
strength_bar_height int 3 Height of the strength bar in pixels
show_icon QIcon \| QPixmap \| str \| None icons8 URL Icon displayed when the password is hidden (eye-open)
hide_icon QIcon \| QPixmap \| str \| None icons8 URL Icon displayed when the password is visible (eye-closed)
icon_size QSize \| tuple[int, int] QSize(16, 16) Size of the toggle icon

Properties:

Property Type Description
password str Gets or sets the raw password text
show_strength bool Gets or sets strength bar visibility
strength_bar_height int Gets or sets the bar height in pixels (minimum 1)
show_icon QIcon \| None Gets or sets the icon shown when password is hidden
hide_icon QIcon \| None Gets or sets the icon shown when password is visible
icon_size QSize Gets or sets the toggle icon size

Methods:

Method Signature Description
togglePassword() () -> None Switches the echo mode and updates the toggle icon
updateStrength() (text: str) -> None Recalculates the strength score and updates the bar
refreshStyle() () -> None Triggers a repaint

Strength score:

The score ranges from 0 to 100. Each criterion adds points:

Criterion Points
Length >= 8 +25
Contains uppercase letter +15
Contains lowercase letter +15
Contains digit +20
Contains special character +25

Bar color by score: 0–29 red, 30–59 orange, 60–79 green, 80–100 dark green.

Example:

from PySide6.QtWidgets import QApplication
from ezqt_widgets import PasswordInput

app = QApplication([])

field = PasswordInput(show_strength=True, strength_bar_height=4)
field.strengthChanged.connect(lambda score: print(f"Strength: {score}/100"))
field.show()

app.exec()

PasswordInput

PasswordInput(parent: QWidget | None = None, show_strength: bool = True, strength_bar_height: int = 3, show_icon: IconSourceExtended = SVG_EYE_OPEN, hide_icon: IconSourceExtended = SVG_EYE_CLOSED, icon_size: QSize | tuple[int, int] = QSize(16, 16), *args: Any, **kwargs: Any)

Bases: QWidget

Enhanced password input widget with integrated strength bar.

Features
  • QLineEdit in password mode with integrated strength bar
  • Right-side icon with click functionality
  • Icon management system (ThemeIcon, QIcon, QPixmap, path, URL, SVG)
  • Animated strength bar that fills the bottom border
  • Signal strengthChanged(int) emitted on password change
  • Color-coded strength indicator
  • External QSS styling support with CSS variables
PARAMETER DESCRIPTION
parent

The parent widget (default: None).

TYPE: QWidget | None DEFAULT: None

show_strength

Whether to show the password strength bar (default: True).

TYPE: bool DEFAULT: True

strength_bar_height

Height of the strength bar in pixels (default: 3).

TYPE: int DEFAULT: 3

show_icon

Icon for show password (ThemeIcon, QIcon, QPixmap, str, or None, default: URL to icons8.com).

TYPE: IconSourceExtended DEFAULT: SVG_EYE_OPEN

hide_icon

Icon for hide password (ThemeIcon, QIcon, QPixmap, str, or None, default: URL to icons8.com).

TYPE: IconSourceExtended DEFAULT: SVG_EYE_CLOSED

icon_size

Size of the icon (QSize or tuple, default: QSize(16, 16)).

TYPE: QSize | tuple[int, int] DEFAULT: QSize(16, 16)

*args

Additional arguments passed to QWidget.

TYPE: Any DEFAULT: ()

**kwargs

Additional keyword arguments passed to QWidget.

TYPE: Any DEFAULT: {}

Properties

password: Get or set the password text. show_strength: Get or set whether to show the strength bar. strength_bar_height: Get or set the strength bar height. show_icon: Get or set the show password icon. hide_icon: Get or set the hide password icon. icon_size: Get or set the icon size.

Signals

strengthChanged(int): Emitted when password strength changes. iconClicked(): Emitted when the icon is clicked.

Initialize the password input widget.

Source code in src/ezqt_widgets/widgets/input/password_input.py
def __init__(
    self,
    parent: QWidget | None = None,
    show_strength: bool = True,
    strength_bar_height: int = 3,
    show_icon: IconSourceExtended = SVG_EYE_OPEN,
    hide_icon: IconSourceExtended = SVG_EYE_CLOSED,
    icon_size: QSize | tuple[int, int] = QSize(16, 16),
    *args: Any,
    **kwargs: Any,
) -> None:
    """Initialize the password input widget."""
    super().__init__(parent, *args, **kwargs)

    # Set widget type for QSS selection
    self.setProperty("type", "PasswordInput")
    self.setObjectName("PasswordInput")

    # Initialize properties
    self._show_strength: bool = show_strength
    self._strength_bar_height: int = strength_bar_height
    self._show_icon: QIcon | None = None
    self._hide_icon: QIcon | None = None
    self._show_icon_source: IconSourceExtended = show_icon
    self._hide_icon_source: IconSourceExtended = hide_icon
    self._icon_size: QSize = (
        QSize(*icon_size) if isinstance(icon_size, (tuple, list)) else icon_size
    )
    self._current_strength: int = 0
    self._password_visible: bool = False

    # Setup UI
    self._setup_ui()

    # Set icons
    if show_icon:
        self.show_icon = show_icon
    if hide_icon:
        self.hide_icon = hide_icon

    # Initialize icon display
    self._update_icon()

password property writable

password: str

Get the password text.

RETURNS DESCRIPTION
str

The current password text.

show_strength property writable

show_strength: bool

Get whether the strength bar is shown.

RETURNS DESCRIPTION
bool

True if strength bar is shown, False otherwise.

strength_bar_height property writable

strength_bar_height: int

Get the strength bar height.

RETURNS DESCRIPTION
int

The current strength bar height in pixels.

show_icon property writable

show_icon: QIcon | None

Get the show password icon.

RETURNS DESCRIPTION
QIcon | None

The current show password icon, or None if not set.

hide_icon property writable

hide_icon: QIcon | None

Get the hide password icon.

RETURNS DESCRIPTION
QIcon | None

The current hide password icon, or None if not set.

icon_size property writable

icon_size: QSize

Get the icon size.

RETURNS DESCRIPTION
QSize

The current icon size.

togglePassword

togglePassword() -> None

Toggle password visibility.

Source code in src/ezqt_widgets/widgets/input/password_input.py
def togglePassword(self) -> None:
    """Toggle password visibility."""
    self._password_visible = not self._password_visible
    if self._password_visible:
        self._password_input.setEchoMode(QLineEdit.EchoMode.Normal)
    else:
        self._password_input.setEchoMode(QLineEdit.EchoMode.Password)
    self._update_icon()

updateStrength

updateStrength(text: str) -> None

Update password strength.

PARAMETER DESCRIPTION
text

The password text to evaluate.

TYPE: str

Source code in src/ezqt_widgets/widgets/input/password_input.py
def updateStrength(self, text: str) -> None:
    """Update password strength.

    Args:
        text: The password text to evaluate.
    """
    score = _password_strength(text)
    self._current_strength = score
    self._strength_bar.setValue(score)
    self._update_strength_color(score)
    self.strengthChanged.emit(score)

setTheme

setTheme(theme: str) -> None

Update all icons' color for the given theme.

Can be connected directly to a theme-change signal to keep icons in sync with the application's color scheme.

PARAMETER DESCRIPTION
theme

The new theme ("dark" or "light").

TYPE: str

Source code in src/ezqt_widgets/widgets/input/password_input.py
def setTheme(self, theme: str) -> None:
    """Update all icons' color for the given theme.

    Can be connected directly to a theme-change signal to keep
    icons in sync with the application's color scheme.

    Args:
        theme: The new theme (``"dark"`` or ``"light"``).
    """
    if isinstance(self._show_icon, ThemeIcon):
        self._show_icon.setTheme(theme)
    if isinstance(self._hide_icon, ThemeIcon):
        self._hide_icon.setTheme(theme)
    self._update_icon()

refreshStyle

refreshStyle() -> None

Refresh the widget style.

Deprecated - use external QSS for styling.

Source code in src/ezqt_widgets/widgets/input/password_input.py
def refreshStyle(self) -> None:
    """Refresh the widget style.

    Deprecated - use external QSS for styling.
    """
    self.update()

SearchInput

A QLineEdit subclass that maintains a submission history navigable with the Up/Down arrow keys and emits searchSubmitted when the user presses Enter.

Signals:

Signal Signature Emitted when
searchSubmitted (str) The user presses Enter/Return; the text is also added to history

Constructor parameters:

Parameter Type Default Description
parent QWidget \| None None Parent widget
max_history int 20 Maximum number of history entries to keep
search_icon QIcon \| QPixmap \| str \| None None Optional icon displayed in the field
icon_position str "left" Icon position: "left" or "right"
clear_button bool True Whether to show Qt's built-in clear button

Properties:

Property Type Description
search_icon QIcon \| None Gets or sets the search icon
icon_position str Gets or sets the icon position ("left" or "right")
clear_button bool Gets or sets clear button visibility
max_history int Gets or sets the history size limit

Methods:

Method Signature Description
addToHistory() (text: str) -> None Adds a term to the front of history; ignores empty/whitespace-only strings
getHistory() () -> list[str] Returns a copy of the current history list
clearHistory() () -> None Empties the history and resets the navigation index
setHistory() (history_list: list[str]) -> None Replaces history with the provided list, trimmed to max_history
refreshStyle() () -> None Re-applies the QSS stylesheet

Keyboard navigation:

Key Effect
Enter / Return Submits current text, adds to history, emits searchSubmitted
Up Navigates backward through history
Down Navigates forward through history; restores current input at the end

Example:

from PySide6.QtWidgets import QApplication
from ezqt_widgets import SearchInput

app = QApplication([])

search = SearchInput(max_history=10, clear_button=True)
search.setPlaceholderText("Type and press Enter...")
search.searchSubmitted.connect(lambda q: print(f"Search: {q}"))
search.show()

app.exec()

SearchInput

SearchInput(parent: WidgetParent = None, max_history: int = 20, search_icon: IconSourceExtended = None, icon_position: str = 'left', clear_button: bool = True, *args: Any, **kwargs: Any)

Bases: QLineEdit

QLineEdit subclass for search input with integrated history.

Features
  • Maintains a history of submitted searches
  • Navigate history with up/down arrows
  • Emits a searchSubmitted(str) signal on validation (Enter)
  • Optional search icon (left or right)
  • Optional clear button
PARAMETER DESCRIPTION
parent

The parent widget (default: None).

TYPE: WidgetParent DEFAULT: None

max_history

Maximum number of history entries to keep (default: 20).

TYPE: int DEFAULT: 20

search_icon

Icon to display as search icon (ThemeIcon, QIcon, QPixmap, str, or None, default: None).

TYPE: IconSourceExtended DEFAULT: None

icon_position

Icon position, 'left' or 'right' (default: 'left').

TYPE: str DEFAULT: 'left'

clear_button

Whether to show a clear button (default: True).

TYPE: bool DEFAULT: True

*args

Additional arguments passed to QLineEdit.

TYPE: Any DEFAULT: ()

**kwargs

Additional keyword arguments passed to QLineEdit.

TYPE: Any DEFAULT: {}

Properties

search_icon: Get or set the search icon. icon_position: Get or set the icon position ('left' or 'right'). clear_button: Get or set whether the clear button is shown. max_history: Get or set the maximum history size.

Signals

searchSubmitted(str): Emitted when a search is submitted (Enter key).

Example

from ezqt_widgets import SearchInput search = SearchInput(max_history=10, clear_button=True) search.searchSubmitted.connect(lambda q: print(f"Search: {q}")) search.setPlaceholderText("Type and press Enter...") search.show()

Initialize the search input.

Source code in src/ezqt_widgets/widgets/input/search_input.py
def __init__(
    self,
    parent: WidgetParent = None,
    max_history: int = 20,
    search_icon: IconSourceExtended = None,
    icon_position: str = "left",
    clear_button: bool = True,
    *args: Any,
    **kwargs: Any,
) -> None:
    """Initialize the search input."""
    super().__init__(parent, *args, **kwargs)

    # Initialize properties
    self._search_icon: QIcon | None = None
    self._icon_position: str = icon_position
    self._clear_button: bool = clear_button
    self._history: list[str] = []
    self._history_index: int = -1
    self._max_history: int = max_history
    self._current_text: str = ""

    # Setup UI
    self._setup_ui()

    # Set icon if provided
    if search_icon:
        # Setter accepts ThemeIcon | QIcon | QPixmap | str | None, but mypy sees return type
        self.search_icon = search_icon

search_icon property writable

search_icon: QIcon | None

Get the search icon.

RETURNS DESCRIPTION
QIcon | None

The current search icon, or None if not set.

icon_position property writable

icon_position: str

Get the icon position.

RETURNS DESCRIPTION
str

The current icon position ('left' or 'right').

clear_button property writable

clear_button: bool

Get whether the clear button is shown.

RETURNS DESCRIPTION
bool

True if clear button is shown, False otherwise.

max_history property writable

max_history: int

Get the maximum history size.

RETURNS DESCRIPTION
int

The maximum number of history entries.

addToHistory

addToHistory(text: str) -> None

Add a search term to history.

PARAMETER DESCRIPTION
text

The search term to add.

TYPE: str

Source code in src/ezqt_widgets/widgets/input/search_input.py
def addToHistory(self, text: str) -> None:
    """Add a search term to history.

    Args:
        text: The search term to add.
    """
    if not text.strip():
        return

    # Remove if already exists
    if text in self._history:
        self._history.remove(text)

    # Add to beginning
    self._history.insert(0, text)
    self._trim_history()
    self._history_index = -1

getHistory

getHistory() -> list[str]

Get the search history.

RETURNS DESCRIPTION
list[str]

A copy of the search history list.

Source code in src/ezqt_widgets/widgets/input/search_input.py
def getHistory(self) -> list[str]:
    """Get the search history.

    Returns:
        A copy of the search history list.
    """
    return self._history.copy()

clearHistory

clearHistory() -> None

Clear the search history.

Source code in src/ezqt_widgets/widgets/input/search_input.py
def clearHistory(self) -> None:
    """Clear the search history."""
    self._history.clear()
    self._history_index = -1

setHistory

setHistory(history_list: list[str]) -> None

Set the search history.

PARAMETER DESCRIPTION
history_list

List of history entries to set.

TYPE: list[str]

Source code in src/ezqt_widgets/widgets/input/search_input.py
def setHistory(self, history_list: list[str]) -> None:
    """Set the search history.

    Args:
        history_list: List of history entries to set.
    """
    self._history = [
        str(item).strip() for item in history_list if str(item).strip()
    ]
    self._trim_history()
    self._history_index = -1

keyPressEvent

keyPressEvent(event: QKeyEvent) -> None

Handle key press events.

PARAMETER DESCRIPTION
event

The key event.

TYPE: QKeyEvent

Source code in src/ezqt_widgets/widgets/input/search_input.py
def keyPressEvent(self, event: QKeyEvent) -> None:
    """Handle key press events.

    Args:
        event: The key event.
    """
    if event.key() == Qt.Key.Key_Return or event.key() == Qt.Key.Key_Enter:
        # Submit search
        text = self.text().strip()
        if text:
            self.addToHistory(text)
            self.searchSubmitted.emit(text)
    elif event.key() == Qt.Key.Key_Up:
        # Navigate history up
        if self._history:
            if self._history_index < len(self._history) - 1:
                self._history_index += 1
                self.setText(self._history[self._history_index])
            event.accept()
            return
    elif event.key() == Qt.Key.Key_Down:
        # Navigate history down
        if self._history_index > 0:
            self._history_index -= 1
            self.setText(self._history[self._history_index])
            event.accept()
            return
        elif self._history_index == 0:
            self._history_index = -1
            self.setText(self._current_text)
            event.accept()
            return

    # Store current text for history navigation
    if event.key() not in [Qt.Key.Key_Up, Qt.Key.Key_Down]:
        self._current_text = self.text()

    super().keyPressEvent(event)

setTheme

setTheme(theme: str) -> None

Update the search icon color for the given theme.

Can be connected directly to a theme-change signal to keep the icon in sync with the application's color scheme.

PARAMETER DESCRIPTION
theme

The new theme ("dark" or "light").

TYPE: str

Source code in src/ezqt_widgets/widgets/input/search_input.py
def setTheme(self, theme: str) -> None:
    """Update the search icon color for the given theme.

    Can be connected directly to a theme-change signal to keep
    the icon in sync with the application's color scheme.

    Args:
        theme: The new theme (``"dark"`` or ``"light"``).
    """
    if isinstance(self._search_icon, ThemeIcon):
        self._search_icon.setTheme(theme)
        self.update()

refreshStyle

refreshStyle() -> None

Refresh the widget style.

Useful after dynamic stylesheet changes.

Source code in src/ezqt_widgets/widgets/input/search_input.py
def refreshStyle(self) -> None:
    """Refresh the widget style.

    Useful after dynamic stylesheet changes.
    """
    self.style().unpolish(self)
    self.style().polish(self)
    self.update()

TabReplaceTextEdit

A QPlainTextEdit subclass that intercepts paste events and replaces tab characters with a configurable string. Useful for pasting tabular or CSV data.

Constructor parameters:

Parameter Type Default Description
parent QWidget \| None None Parent widget
tab_replacement str "\n" String substituted for each \t character
sanitize_on_paste bool True Whether to sanitize text on paste
remove_empty_lines bool True Whether to discard empty lines during sanitization
preserve_whitespace bool False If True, keeps lines that contain only whitespace

Properties:

Property Type Description
tab_replacement str Gets or sets the tab replacement string
sanitize_on_paste bool Gets or sets whether sanitization is active on paste
remove_empty_lines bool Gets or sets whether empty lines are removed
preserve_whitespace bool Gets or sets whitespace-only line preservation

Methods:

Method Signature Description
sanitizeText() (text: str) -> str Applies tab replacement and optional empty-line removal; returns the result
refreshStyle() () -> None Re-applies the QSS stylesheet

Behavior notes:

  • Pressing the Tab key inserts tab_replacement at the cursor (no focus change).
  • Paste events (Ctrl+V) are intercepted when sanitize_on_paste is True and route through sanitizeText() before insertion.

Example:

from PySide6.QtWidgets import QApplication
from ezqt_widgets import TabReplaceTextEdit

app = QApplication([])

# Pasting "col1\tcol2\n\ncol3\tcol4" produces "col1;col2\ncol3;col4"
editor = TabReplaceTextEdit(
    tab_replacement=";",
    remove_empty_lines=True,
)
editor.show()

app.exec()

TabReplaceTextEdit

TabReplaceTextEdit(parent: WidgetParent = None, tab_replacement: str = '\n', sanitize_on_paste: bool = True, remove_empty_lines: bool = True, preserve_whitespace: bool = False, *args: Any, **kwargs: Any)

Bases: QPlainTextEdit

QPlainTextEdit subclass with tab replacement and text sanitization.

Sanitizes pasted text by replacing tab characters according to the chosen mode and removing empty lines. Useful for pasting tabular data or ensuring clean input.

PARAMETER DESCRIPTION
parent

The parent widget (default: None).

TYPE: WidgetParent DEFAULT: None

tab_replacement

The string to replace tab characters with (default: "\n").

TYPE: str DEFAULT: '\n'

sanitize_on_paste

Whether to sanitize pasted text (default: True).

TYPE: bool DEFAULT: True

remove_empty_lines

Whether to remove empty lines during sanitization (default: True).

TYPE: bool DEFAULT: True

preserve_whitespace

Whether to preserve leading/trailing whitespace (default: False).

TYPE: bool DEFAULT: False

*args

Additional arguments passed to QPlainTextEdit.

TYPE: Any DEFAULT: ()

**kwargs

Additional keyword arguments passed to QPlainTextEdit.

TYPE: Any DEFAULT: {}

Properties

tab_replacement: Get or set the string used to replace tab characters. sanitize_on_paste: Enable or disable sanitizing pasted text. remove_empty_lines: Get or set whether to remove empty lines. preserve_whitespace: Get or set whether to preserve whitespace.

Example

from ezqt_widgets import TabReplaceTextEdit editor = TabReplaceTextEdit(tab_replacement=";", remove_empty_lines=True) editor.setPlainText("alpha\tbeta\n\ngamma\tdelta")

Paste triggers sanitization; tabs become ";" and empty lines removed

editor.show()

Initialize the tab replace text edit.

Source code in src/ezqt_widgets/widgets/input/tab_replace_textedit.py
def __init__(
    self,
    parent: WidgetParent = None,
    tab_replacement: str = "\n",
    sanitize_on_paste: bool = True,
    remove_empty_lines: bool = True,
    preserve_whitespace: bool = False,
    *args: Any,
    **kwargs: Any,
) -> None:
    """Initialize the tab replace text edit."""
    super().__init__(parent, *args, **kwargs)

    # Set widget type property
    self.setProperty("type", "TabReplaceTextEdit")

    # Initialize properties
    self._tab_replacement: str = tab_replacement
    self._sanitize_on_paste: bool = sanitize_on_paste
    self._remove_empty_lines: bool = remove_empty_lines
    self._preserve_whitespace: bool = preserve_whitespace

tab_replacement property writable

tab_replacement: str

Get the string used to replace tab characters.

RETURNS DESCRIPTION
str

The current tab replacement string.

sanitize_on_paste property writable

sanitize_on_paste: bool

Get whether sanitizing pasted text is enabled.

RETURNS DESCRIPTION
bool

True if sanitization is enabled, False otherwise.

remove_empty_lines property writable

remove_empty_lines: bool

Get whether empty lines are removed.

RETURNS DESCRIPTION
bool

True if empty lines are removed, False otherwise.

preserve_whitespace property writable

preserve_whitespace: bool

Get whether whitespace is preserved.

RETURNS DESCRIPTION
bool

True if whitespace is preserved, False otherwise.

sanitizeText

sanitizeText(text: str) -> str

Sanitize text by replacing tabs and optionally removing empty lines.

PARAMETER DESCRIPTION
text

The text to sanitize.

TYPE: str

RETURNS DESCRIPTION
str

The sanitized text.

Source code in src/ezqt_widgets/widgets/input/tab_replace_textedit.py
def sanitizeText(self, text: str) -> str:
    """Sanitize text by replacing tabs and optionally removing empty lines.

    Args:
        text: The text to sanitize.

    Returns:
        The sanitized text.
    """
    # Replace tabs
    sanitized = text.replace("\t", self._tab_replacement)

    if self._remove_empty_lines:
        # Split into lines
        lines = sanitized.split("\n")

        # Filter empty lines
        if self._preserve_whitespace:
            # Keep lines with whitespace
            lines = [line for line in lines if line.strip() or line]
        else:
            # Remove all empty lines but preserve whitespace
            lines = [line for line in lines if line.strip()]

        # Rejoin lines
        sanitized = "\n".join(lines)

    return sanitized

keyPressEvent

keyPressEvent(event: QKeyEvent) -> None

Handle key press events.

Overridden method from QPlainTextEdit. Modifies the behavior of the paste operation and tab key handling.

PARAMETER DESCRIPTION
event

The key event.

TYPE: QKeyEvent

Source code in src/ezqt_widgets/widgets/input/tab_replace_textedit.py
def keyPressEvent(self, event: QKeyEvent) -> None:
    """Handle key press events.

    Overridden method from QPlainTextEdit. Modifies the behavior of
    the paste operation and tab key handling.

    Args:
        event: The key event.
    """
    # Handle tab key
    if event.key() == Qt.Key.Key_Tab:
        # Insert tab replacement
        cursor = self.textCursor()
        cursor.insertText(self._tab_replacement)
        event.accept()
        return

    # Handle paste
    if self._sanitize_on_paste and event.matches(QKeySequence.StandardKey.Paste):
        # Get clipboard text
        clipboard = QApplication.clipboard()
        text = clipboard.text()

        # Sanitize text
        text = self.sanitizeText(text)

        # Insert sanitized text
        self.insertPlainText(text)
        event.accept()
        return

    # Default behavior
    super().keyPressEvent(event)

refreshStyle

refreshStyle() -> None

Refresh the widget's style.

Useful after dynamic stylesheet changes.

Source code in src/ezqt_widgets/widgets/input/tab_replace_textedit.py
def refreshStyle(self) -> None:
    """Refresh the widget's style.

    Useful after dynamic stylesheet changes.
    """
    self.style().unpolish(self)
    self.style().polish(self)
    self.update()

FilePickerInput

A composite QWidget combining a QLineEdit and a folder icon button that opens a QFileDialog for file or directory selection. Supports theme-aware icon rendering via ThemeIcon.

Signals:

Signal Signature Emitted when
fileSelected (str) A path is chosen via the dialog
pathChanged (str) The text in the QLineEdit changes (every keystroke)

Constructor parameters:

Parameter Type Default Description
parent QWidget \| None None Parent widget
placeholder str "Select a file..." Placeholder text for the QLineEdit
mode "file" \| "directory" "file" Whether the dialog selects a file or a directory
filter str "" File filter string, e.g. "Images (*.png *.jpg)"
dialog_title str "" Window title for the QFileDialog; auto-set if empty

Properties:

Property Type Description
path str Gets or sets the current path shown in the QLineEdit
mode "file" \| "directory" Gets or sets the selection mode
placeholder_text str Gets or sets the QLineEdit placeholder text
filter str Gets or sets the file dialog filter string
dialog_title str Gets or sets the file dialog window title

Methods:

Method Signature Description
clear() () -> None Clears the current path from the QLineEdit
setTheme() (theme: str) -> None Updates the folder icon color; connect to a themeChanged signal
refreshStyle() () -> None Re-applies the QSS stylesheet

Behavior notes:

  • fileSelected is emitted only when the user picks a path via the dialog, not on manual text edits.
  • pathChanged is emitted on every text change in the QLineEdit, including manual entry.
  • When mode is "directory", the dialog default title is "Select Directory"; when "file", it is "Select File". Setting dialog_title overrides both defaults.
  • Passing an invalid value to mode (neither "file" nor "directory") leaves the mode unchanged.

Example:

from PySide6.QtWidgets import QApplication
from ezqt_widgets import FilePickerInput

app = QApplication([])

picker = FilePickerInput(
    placeholder="Choose a CSV file...",
    mode="file",
    filter="CSV files (*.csv)",
)
picker.fileSelected.connect(lambda p: print(f"Selected: {p}"))
picker.pathChanged.connect(lambda p: print(f"Path text: {p}"))
picker.show()

app.exec()

FilePickerInput

FilePickerInput(parent: WidgetParent = None, *, placeholder: str = 'Select a file...', mode: Literal['file', 'directory'] = 'file', filter: str = '', dialog_title: str = '')

Bases: QWidget

Composite input widget combining a QLineEdit and a folder icon button.

Clicking the folder button opens a QFileDialog (file or directory mode). The selected path is displayed in the QLineEdit. The widget supports theme-aware icon rendering via ThemeIcon.

Features
  • File or directory selection via QFileDialog
  • Editable QLineEdit for manual path entry
  • Theme-aware folder icon via ThemeIcon
  • Signals for file selection and path text changes
  • Configurable placeholder, filter, and dialog title
PARAMETER DESCRIPTION
parent

The parent widget (default: None).

TYPE: WidgetParent DEFAULT: None

placeholder

Placeholder text for the QLineEdit (default: "Select a file...").

TYPE: str DEFAULT: 'Select a file...'

mode

Selection mode, either "file" or "directory" (default: "file").

TYPE: Literal['file', 'directory'] DEFAULT: 'file'

filter

File filter string for QFileDialog, e.g. "Images (.png .jpg)" (default: "").

TYPE: str DEFAULT: ''

dialog_title

Title for the QFileDialog window (default: "").

TYPE: str DEFAULT: ''

Properties

path: Get or set the current file/directory path. mode: Get or set the selection mode ("file" or "directory"). placeholder_text: Get or set the QLineEdit placeholder text. filter: Get or set the file dialog filter string. dialog_title: Get or set the file dialog window title.

Signals

fileSelected(str): Emitted when a path is chosen via the dialog. pathChanged(str): Emitted on every text change in the QLineEdit.

Example

from ezqt_widgets import FilePickerInput picker = FilePickerInput(placeholder="Choose a CSV file...", ... filter="CSV files (*.csv)") picker.fileSelected.connect(lambda p: print(f"Selected: {p}")) picker.show()

Initialize the file picker input.

Source code in src/ezqt_widgets/widgets/input/file_picker_input.py
def __init__(
    self,
    parent: WidgetParent = None,
    *,
    placeholder: str = "Select a file...",
    mode: Literal["file", "directory"] = "file",
    filter: str = "",  # noqa: A002
    dialog_title: str = "",
) -> None:
    """Initialize the file picker input."""
    super().__init__(parent)
    self.setProperty("type", "FilePickerInput")

    # Initialize private state
    self._mode: Literal["file", "directory"] = mode
    self._filter: str = filter
    self._dialog_title: str = dialog_title
    self._folder_icon: ThemeIcon | None = None

    # Setup UI
    self._setup_widget(placeholder)

path property writable

path: str

Get the current path displayed in the QLineEdit.

RETURNS DESCRIPTION
str

The current path string.

mode property writable

mode: Literal['file', 'directory']

Get the file dialog selection mode.

RETURNS DESCRIPTION
Literal['file', 'directory']

The current mode ("file" or "directory").

placeholder_text property writable

placeholder_text: str

Get the QLineEdit placeholder text.

RETURNS DESCRIPTION
str

The current placeholder text.

filter property writable

filter: str

Get the file dialog filter string.

RETURNS DESCRIPTION
str

The current filter string.

dialog_title property writable

dialog_title: str

Get the file dialog window title.

RETURNS DESCRIPTION
str

The current dialog title.

clear

clear() -> None

Clear the current path from the QLineEdit.

Source code in src/ezqt_widgets/widgets/input/file_picker_input.py
def clear(self) -> None:
    """Clear the current path from the QLineEdit."""
    self._line_edit.clear()

setTheme

setTheme(theme: str) -> None

Update the folder icon color for the given theme.

Can be connected directly to a theme-change signal to keep the icon in sync with the application's color scheme.

PARAMETER DESCRIPTION
theme

The new theme ("dark" or "light").

TYPE: str

Source code in src/ezqt_widgets/widgets/input/file_picker_input.py
def setTheme(self, theme: str) -> None:
    """Update the folder icon color for the given theme.

    Can be connected directly to a theme-change signal to keep
    the icon in sync with the application's color scheme.

    Args:
        theme: The new theme (``"dark"`` or ``"light"``).
    """
    if isinstance(self._folder_icon, ThemeIcon):
        self._folder_icon.setTheme(theme)
        self._btn.setIcon(self._folder_icon)

refreshStyle

refreshStyle() -> None

Refresh the widget style.

Useful after dynamic stylesheet changes.

Source code in src/ezqt_widgets/widgets/input/file_picker_input.py
def refreshStyle(self) -> None:
    """Refresh the widget style.

    Useful after dynamic stylesheet changes.
    """
    self.style().unpolish(self)
    self.style().polish(self)
    self.update()

SpinBoxInput

A fully custom numeric spin box QWidget with integrated decrement (−) and increment (+) QToolButton flanking a central QLineEdit. Supports mouse wheel input and real-time QIntValidator clamping.

Signals:

Signal Signature Emitted when
valueChanged (int) The integer value changes

Constructor parameters:

Parameter Type Default Description
parent QWidget \| None None Parent widget
value int 0 Initial value; clamped between minimum and maximum
minimum int 0 Minimum allowed value
maximum int 100 Maximum allowed value
step int 1 Increment/decrement step size (minimum 1)
prefix str "" String prepended to the displayed value
suffix str "" String appended to the displayed value

Properties:

Property Type Description
value int Gets or sets the current value; clamped and emits valueChanged
minimum int Gets or sets the minimum; updates the validator and re-clamps the value
maximum int Gets or sets the maximum; updates the validator and re-clamps the value
step int Gets or sets the step size (minimum 1)
prefix str Gets or sets the display prefix; refreshes the QLineEdit
suffix str Gets or sets the display suffix; refreshes the QLineEdit

Methods:

Method Signature Description
setValue() (value: int) -> None Sets the value, clamped between minimum and maximum; emits valueChanged only if the value actually changes
stepUp() () -> None Increments the value by step, clamped at maximum
stepDown() () -> None Decrements the value by step, clamped at minimum
refreshStyle() () -> None Re-applies the QSS stylesheet

Behavior notes:

  • Mouse wheel scrolling increments (scroll up) or decrements (scroll down) by step when the widget has focus.
  • valueChanged is emitted only when the value actually changes, not on every display refresh.
  • prefix and suffix are stripped before parsing the QLineEdit text.

Example:

from PySide6.QtWidgets import QApplication
from ezqt_widgets import SpinBoxInput

app = QApplication([])

spin = SpinBoxInput(value=10, minimum=0, maximum=200, step=5, suffix=" px")
spin.valueChanged.connect(lambda v: print(f"Value: {v}"))
spin.show()

app.exec()

SpinBoxInput

SpinBoxInput(parent: WidgetParent = None, *, value: int = 0, minimum: int = 0, maximum: int = 100, step: int = 1, prefix: str = '', suffix: str = '')

Bases: QWidget

Custom numeric spin box with integrated decrement and increment buttons.

Provides a fully stylable numeric input with − and + buttons flanking a central QLineEdit. Supports mouse wheel increments and real-time QIntValidator clamping.

Features
  • Decrement (−) and increment (+) QToolButtons
  • Central QLineEdit with QIntValidator
  • Mouse wheel increments/decrements by step
  • Value clamped between minimum and maximum at all times
  • Optional prefix and suffix labels
  • Signal emitted only when value changes
PARAMETER DESCRIPTION
parent

The parent widget (default: None).

TYPE: WidgetParent DEFAULT: None

value

Initial value (default: 0).

TYPE: int DEFAULT: 0

minimum

Minimum allowed value (default: 0).

TYPE: int DEFAULT: 0

maximum

Maximum allowed value (default: 100).

TYPE: int DEFAULT: 100

step

Step size for increment/decrement (default: 1).

TYPE: int DEFAULT: 1

prefix

String prepended to the displayed value (default: "").

TYPE: str DEFAULT: ''

suffix

String appended to the displayed value (default: "").

TYPE: str DEFAULT: ''

Properties

value: Get or set the current integer value. minimum: Get or set the minimum allowed value. maximum: Get or set the maximum allowed value. step: Get or set the step size. prefix: Get or set the display prefix. suffix: Get or set the display suffix.

Signals

valueChanged(int): Emitted when the value changes.

Example

from ezqt_widgets import SpinBoxInput spin = SpinBoxInput(value=10, minimum=0, maximum=100, step=5) spin.valueChanged.connect(lambda v: print(f"Value: {v}")) spin.show()

Initialize the spin box input.

Source code in src/ezqt_widgets/widgets/input/spin_box_input.py
def __init__(
    self,
    parent: WidgetParent = None,
    *,
    value: int = 0,
    minimum: int = 0,
    maximum: int = 100,
    step: int = 1,
    prefix: str = "",
    suffix: str = "",
) -> None:
    """Initialize the spin box input."""
    super().__init__(parent)
    self.setProperty("type", "SpinBoxInput")

    # Initialize private state
    self._minimum: int = minimum
    self._maximum: int = maximum
    self._step: int = max(1, step)
    self._prefix: str = prefix
    self._suffix: str = suffix
    self._value: int = max(minimum, min(maximum, value))

    # Enable mouse wheel focus
    self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)

    # Setup UI
    self._setup_widget()

value property writable

value: int

Get the current integer value.

RETURNS DESCRIPTION
int

The current value.

minimum property writable

minimum: int

Get the minimum allowed value.

RETURNS DESCRIPTION
int

The current minimum.

maximum property writable

maximum: int

Get the maximum allowed value.

RETURNS DESCRIPTION
int

The current maximum.

step property writable

step: int

Get the step size for increment/decrement.

RETURNS DESCRIPTION
int

The current step size.

prefix property writable

prefix: str

Get the display prefix.

RETURNS DESCRIPTION
str

The current prefix string.

suffix property writable

suffix: str

Get the display suffix.

RETURNS DESCRIPTION
str

The current suffix string.

setValue

setValue(value: int) -> None

Set the value, clamped between minimum and maximum.

PARAMETER DESCRIPTION
value

The new value to set.

TYPE: int

Source code in src/ezqt_widgets/widgets/input/spin_box_input.py
def setValue(self, value: int) -> None:
    """Set the value, clamped between minimum and maximum.

    Args:
        value: The new value to set.
    """
    clamped = max(self._minimum, min(self._maximum, int(value)))
    if clamped != self._value:
        self._value = clamped
        self._update_display()
        self.valueChanged.emit(self._value)
    else:
        # Always refresh display to show prefix/suffix
        self._update_display()

stepUp

stepUp() -> None

Increment the value by step, clamped at maximum.

Source code in src/ezqt_widgets/widgets/input/spin_box_input.py
def stepUp(self) -> None:
    """Increment the value by step, clamped at maximum."""
    self.setValue(self._value + self._step)

stepDown

stepDown() -> None

Decrement the value by step, clamped at minimum.

Source code in src/ezqt_widgets/widgets/input/spin_box_input.py
def stepDown(self) -> None:
    """Decrement the value by step, clamped at minimum."""
    self.setValue(self._value - self._step)

wheelEvent

wheelEvent(event: QWheelEvent) -> None

Handle mouse wheel to increment or decrement by step.

PARAMETER DESCRIPTION
event

The wheel event.

TYPE: QWheelEvent

Source code in src/ezqt_widgets/widgets/input/spin_box_input.py
def wheelEvent(self, event: QWheelEvent) -> None:
    """Handle mouse wheel to increment or decrement by step.

    Args:
        event: The wheel event.
    """
    delta = event.angleDelta().y()
    if delta > 0:
        self.stepUp()
    elif delta < 0:
        self.stepDown()
    event.accept()

refreshStyle

refreshStyle() -> None

Refresh the widget style.

Useful after dynamic stylesheet changes.

Source code in src/ezqt_widgets/widgets/input/spin_box_input.py
def refreshStyle(self) -> None:
    """Refresh the widget style.

    Useful after dynamic stylesheet changes.
    """
    self.style().unpolish(self)
    self.style().polish(self)
    self.update()