Skip to content

QueryDialog

Bases: Dialog

A simple modal dialog class for collecting user input.

Source code in src/ttkbootstrap/dialogs/query.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
class QueryDialog(Dialog):
    """A simple modal dialog class for collecting user input."""

    def __init__(
            self,
            prompt: str,
            title: str = " ",
            initialvalue: Any = "",
            minvalue: Optional[Any] = None,
            maxvalue: Optional[Any] = None,
            width: int = 65,
            datatype: Any = str,
            padding: "tuple[int, int] | int" = (20, 20),
            parent: Optional[tkinter.Misc] = None,
            items: Optional[List[str]] = None,
    ) -> None:
        """Create a query dialog for collecting user input.

        Parameters:

            prompt (str):
                The prompt text to display above the input field. Supports
                multiline strings (separated by \\n).

            title (str):
                The dialog window title (default=' ').

            initialvalue (Any):
                The initial value to populate in the input field (default='').

            minvalue (Any):
                Minimum allowed value for numeric data types (int, float, complex).
                Ignored for strings.

            maxvalue (Any):
                Maximum allowed value for numeric data types (int, float, complex).
                Ignored for strings.

            width (int):
                Maximum width in characters for text wrapping of the prompt
                (default=65).

            datatype (type):
                Expected data type for validation (str, int, float, complex).
                When set to int, float, or complex, the input will be validated
                and converted (default=str).

            padding (int | tuple):
                Padding around the dialog content. Can be a single int or
                tuple (horizontal, vertical) (default=(20, 20)).

            parent (Widget):
                Parent widget. The dialog will be centered on this widget.

            items (List[str]):
                Optional list of items for dropdown selection. If provided,
                shows a Combobox instead of Entry. The Combobox supports
                filtering by typing. If items are provided, the input must
                match one from the list.
        """
        super().__init__(parent, title)
        self._prompt = prompt
        self._initialvalue = initialvalue
        self._items = items
        self._minvalue = minvalue
        self._maxvalue = maxvalue
        self._width = width
        self._datatype = datatype
        self._padding = padding
        self._result = None

    def create_body(self, master: tkinter.Misc) -> None:
        frame = ttk.Frame(master, padding=self._padding)
        if self._prompt:
            for p in self._prompt.split("\n"):
                prompt = "\n".join(textwrap.wrap(p, width=self._width))
                prompt_label = ttk.Label(frame, text=prompt)
                prompt_label.pack(pady=(0, 5), fill=X, anchor=N)
        if self._items is None or len(self._items) == 0:
            entry = ttk.Entry(master=frame)
        else:
            entry = ttk.Combobox(master=frame, values=self._items)
            entry.bind("<KeyRelease>", self.on_filter_list)
        entry.insert(END, self._initialvalue)
        entry.pack(pady=(0, 5), fill=X)
        entry.bind("<Return>", self.on_submit)
        entry.bind("<KP_Enter>", self.on_submit)
        entry.bind("<Escape>", self.on_cancel)
        frame.pack(fill=X, expand=True)
        self._initial_focus = entry

    def create_buttonbox(self, master: tkinter.Misc) -> None:
        frame = ttk.Frame(master, padding=(5, 10))

        submit = ttk.Button(
            master=frame,
            bootstyle="primary",
            text=MessageCatalog.translate("Submit"),
            command=self.on_submit,
        )
        submit.pack(padx=5, side=RIGHT)
        submit.lower()

        cancel = ttk.Button(
            master=frame,
            bootstyle="secondary",
            text=MessageCatalog.translate("Cancel"),
            command=self.on_cancel,
        )
        cancel.pack(padx=5, side=RIGHT)
        cancel.lower()

        ttk.Separator(self._toplevel).pack(fill=X)
        frame.pack(side=BOTTOM, fill=X, anchor=S)

    def on_submit(self, *_: Any) -> None:
        self._result = self._initial_focus.get()
        valid_result = self.validate()
        if not valid_result:
            return  # keep toplevel open for valid response
        self._toplevel.destroy()
        self.apply()

    def on_cancel(self, *_: Any) -> None:
        self._toplevel.destroy()
        return

    def on_filter_list(self, event: tkinter.Event) -> None:
        value = event.widget.get().lower()
        if not value:
            event.widget["values"] = self._items
        else:
            data = [k for k in self._items if value in k.lower()]
            event.widget["values"] = data

    def validate(self) -> bool:
        """Validate the data before closing."""
        # no default checks required for string data types,
        # unless there is a list of items to pick from
        if self._datatype not in [float, int, complex] and (self._items is None or len(self._items) == 0):
            return True

        # convert result to appropriate data type
        try:
            self._result = self._datatype(self._result)
        except ValueError:
            msg = MessageCatalog.translate("Should be of data type")
            Messagebox.ok(
                message=f"{msg} `{self._datatype}`",
                title=MessageCatalog.translate("Invalid data type"),
                parent=self._toplevel,
            )
            return False

        # max value range
        if self._maxvalue is not None and self._result > self._maxvalue:
            msg = MessageCatalog.translate("Number cannot be greater than")
            Messagebox.ok(
                message=f"{msg} {self._maxvalue}",
                title=MessageCatalog.translate("Out of range"),
                parent=self._toplevel,
            )
            return False

        # min value range
        if self._minvalue is not None and self._result < self._minvalue:
            msg = MessageCatalog.translate("Number cannot be less than")
            Messagebox.ok(
                message=f"{msg} {self._minvalue}",
                title=MessageCatalog.translate("Out of range"),
                parent=self._toplevel,
            )
            return False

        # item in list
        if self._items is not None and len(self._items) > 0 and self._result not in self._items:
            msg = MessageCatalog.translate("Select an item from the list")
            Messagebox.ok(
                message=msg,
                title=MessageCatalog.translate("Out of range"),
                parent=self._toplevel,
            )
            return False

        return True

    def apply(self) -> None:
        """Process the data after closing (no-op by default)."""
        pass

__init__(prompt, title=' ', initialvalue='', minvalue=None, maxvalue=None, width=65, datatype=str, padding=(20, 20), parent=None, items=None)

Create a query dialog for collecting user input.

Parameters:

prompt (str):
    The prompt text to display above the input field. Supports
    multiline strings (separated by \n).

title (str):
    The dialog window title (default=' ').

initialvalue (Any):
    The initial value to populate in the input field (default='').

minvalue (Any):
    Minimum allowed value for numeric data types (int, float, complex).
    Ignored for strings.

maxvalue (Any):
    Maximum allowed value for numeric data types (int, float, complex).
    Ignored for strings.

width (int):
    Maximum width in characters for text wrapping of the prompt
    (default=65).

datatype (type):
    Expected data type for validation (str, int, float, complex).
    When set to int, float, or complex, the input will be validated
    and converted (default=str).

padding (int | tuple):
    Padding around the dialog content. Can be a single int or
    tuple (horizontal, vertical) (default=(20, 20)).

parent (Widget):
    Parent widget. The dialog will be centered on this widget.

items (List[str]):
    Optional list of items for dropdown selection. If provided,
    shows a Combobox instead of Entry. The Combobox supports
    filtering by typing. If items are provided, the input must
    match one from the list.
Source code in src/ttkbootstrap/dialogs/query.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
def __init__(
        self,
        prompt: str,
        title: str = " ",
        initialvalue: Any = "",
        minvalue: Optional[Any] = None,
        maxvalue: Optional[Any] = None,
        width: int = 65,
        datatype: Any = str,
        padding: "tuple[int, int] | int" = (20, 20),
        parent: Optional[tkinter.Misc] = None,
        items: Optional[List[str]] = None,
) -> None:
    """Create a query dialog for collecting user input.

    Parameters:

        prompt (str):
            The prompt text to display above the input field. Supports
            multiline strings (separated by \\n).

        title (str):
            The dialog window title (default=' ').

        initialvalue (Any):
            The initial value to populate in the input field (default='').

        minvalue (Any):
            Minimum allowed value for numeric data types (int, float, complex).
            Ignored for strings.

        maxvalue (Any):
            Maximum allowed value for numeric data types (int, float, complex).
            Ignored for strings.

        width (int):
            Maximum width in characters for text wrapping of the prompt
            (default=65).

        datatype (type):
            Expected data type for validation (str, int, float, complex).
            When set to int, float, or complex, the input will be validated
            and converted (default=str).

        padding (int | tuple):
            Padding around the dialog content. Can be a single int or
            tuple (horizontal, vertical) (default=(20, 20)).

        parent (Widget):
            Parent widget. The dialog will be centered on this widget.

        items (List[str]):
            Optional list of items for dropdown selection. If provided,
            shows a Combobox instead of Entry. The Combobox supports
            filtering by typing. If items are provided, the input must
            match one from the list.
    """
    super().__init__(parent, title)
    self._prompt = prompt
    self._initialvalue = initialvalue
    self._items = items
    self._minvalue = minvalue
    self._maxvalue = maxvalue
    self._width = width
    self._datatype = datatype
    self._padding = padding
    self._result = None

apply()

Process the data after closing (no-op by default).

Source code in src/ttkbootstrap/dialogs/query.py
203
204
205
def apply(self) -> None:
    """Process the data after closing (no-op by default)."""
    pass

validate()

Validate the data before closing.

Source code in src/ttkbootstrap/dialogs/query.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
def validate(self) -> bool:
    """Validate the data before closing."""
    # no default checks required for string data types,
    # unless there is a list of items to pick from
    if self._datatype not in [float, int, complex] and (self._items is None or len(self._items) == 0):
        return True

    # convert result to appropriate data type
    try:
        self._result = self._datatype(self._result)
    except ValueError:
        msg = MessageCatalog.translate("Should be of data type")
        Messagebox.ok(
            message=f"{msg} `{self._datatype}`",
            title=MessageCatalog.translate("Invalid data type"),
            parent=self._toplevel,
        )
        return False

    # max value range
    if self._maxvalue is not None and self._result > self._maxvalue:
        msg = MessageCatalog.translate("Number cannot be greater than")
        Messagebox.ok(
            message=f"{msg} {self._maxvalue}",
            title=MessageCatalog.translate("Out of range"),
            parent=self._toplevel,
        )
        return False

    # min value range
    if self._minvalue is not None and self._result < self._minvalue:
        msg = MessageCatalog.translate("Number cannot be less than")
        Messagebox.ok(
            message=f"{msg} {self._minvalue}",
            title=MessageCatalog.translate("Out of range"),
            parent=self._toplevel,
        )
        return False

    # item in list
    if self._items is not None and len(self._items) > 0 and self._result not in self._items:
        msg = MessageCatalog.translate("Select an item from the list")
        Messagebox.ok(
            message=msg,
            title=MessageCatalog.translate("Out of range"),
            parent=self._toplevel,
        )
        return False

    return True