[New-bugs-announce] [issue42305] Added Auto_Complete DropBox Suggestion For Tkinter

Mechtron 750 report at bugs.python.org
Tue Nov 10 02:51:05 EST 2020


New submission from Mechtron 750 <rajvirsinghdeol1313 at gmail.com>:

# This is auto complete drop box suggestion wiget for tkinter
# Tkinter Autocomplete

Text autocompletion provides relevant real-time results to users. Because tkinter does not provide a widget for adding autocompletion to GUIs out of the box, I decided to make one myself. This utility is compatible with and has been tested on Python 2.7.1 and Python 3.6.0.

### Structure

###### NOTE: The `Tkinter` library for Python 2 and `tkinter` library for Python 3 will from now on be referred to as `tk`.

The `AutocompleteEntry` class (which can be found [here](https://github.com/RajvirSingh1313/Tkinter_Autocomplete_DropBox/blob/master/main.py))
derives from `tk.Frame` and is a container used to group a `tk.Entry` and `tk.Listbox` widget. Should you need to modify the widgets,
they can be accessed as (respectively) `AutocompleteEntry` s `entry` and `listbox` attributes.<br />

The entry widget acts like a normal textbox. When activated, it binds `<KeyRelease>` to a private method which will update
the list of suggestions. The listbox widget contains the suggestions themselves. When activated, it binds `<<ListboxSelect>>` to a
private method which sets the entry widget to whatever value was selected.<br />

Since an instance of `AutocompleteEntry` is a `tk.Frame` instance too, you can place it by calling its `pack` or `grid` methods with
their respective arguments.

### Quickstart

###### NOTE: These examples will only run under Python 3. To make them Python 2-compatible, replace `tkinter` with `Tkinter`.

To add a new autocompletion frame to our interface, first initialize one:

```python
import tkinter as tk

from tkinter import auto_complete

root = tk.Tk()

frame = tk.Frame(root)
frame.pack()

entry = auto_complete.AutocompleteEntry(frame)
# You can pass additional parameters to further customize the window;
# all parameters that you can pass to tk.Frame, are valid here too.
```

Now you need to configure the instance by passing it an iterable containing all autocompletion entries.<br />
Do this by calling its `build` method:

```python
ENTRIES = (
    "Foo",
    "Bar"
)

entry.build(ENTRIES)
```

You can pass additional arguments to `build`:

* `max_entries` (integer):<br />
  The maximum number of entries to display at once. This value directly corresponds to the listbox widget's `height` attribute. Defaults to `5`.

* `case_sensitive` (boolean):<br />
  If `True`, only autocomplete entries that enforce the same capitalization as the current entry will be displayed.<br />
  If `False`, all autocomplete entries that match with the current entry will be displayed.<br />
  Defaults to `False`.

* `no_results_message` (string or `None`):<br />
  The message to display if no suggestions could be found for the current entry.<br />
  This argument may include a formatting identifier (`{}`) which, at runtime, gets formatted as the current entry. If `None` is specified, the listbox will instead be hidden until the next `<KeyRelease>` event.

Let's play around with these arguments:

```python
entry.build(
    entries=ENTRIES,
    no_results_message="< No results found for '{}' >"
    # Note that this is formatted at runtime
)
```

###### NOTE: You may call the `build` method multiple times on an instance of `AutocompleteEntry`, to dynamically change the available suggestions.

With that out of the way, you can display `entry`:

```python
entry.pack()
```

Now, each time a user presses a key while the entry widget has focus, a list of suggestions will display below it.

---

### Additional options

By default, the `tk.Listbox` widget has a width of `25` pixels and a height of `5` (items). The `tk.Entry` widget also has a default width of `25` pixels. These settings can be modified through the following class attributes:

* `auto_complete.AutocompleteEntry.LISTBOX_HEIGHT`: The height to specify when creating the `tk.Listbox` widget. There's no need to modify this, since the maximum number of entries to be displayed can be passed as an argument to `build`.

* `auto_complete.AutocompleteEntry.LISTBOX_WIDTH`: The width to specify when creating the `tk.Listbox` widget. Any positive integer is valid.

* `auto_complete.AutocompleteEntry.ENTRY_WIDTH`: The width to specify when creating the `tk.Entry` widget. Any positive integer is valid.

###### NOTE: You almost always want to keep the 1:1 `LISTBOX_WIDTH`:`ENTRY_WIDTH` ratio.

You can retrieve the current entry by accessing the instance's `text` attribute (which is a `tk.StringVar` instance):

```python
text = entry.text.get()
```

To further customize the entry widget, you may set its font options, for example:

```python
entry.entry["font"] = (<FONT NAME>, <FONT SIZE>, <FONT WEIGHT>)
```

Or to change the background color for the listbox widget:

```python
entry.listbox["background"] = "#cfeff9"
# Light blue
```


## This the demo

```python
    try:
        import tkinter as tk
        from tkinter import ttk
        from tkinter import auto_complete
    except ImportError:
        # Python 2
        import Tkinter as tk
        import ttk
        from Tkinter import auto_complete

    COUNTRIES = ['Australia','Switzerland','India','Canada','Japan','Germany','United Kingdom','United States','Sweden','Netherlands','Norway']


    class Application(tk.Frame, object):
        def __init__(self, *args, **kwargs):
            super(Application, self).__init__(*args, **kwargs)

            label = tk.Label(self, text="Select a country: ")
            label.pack()

            self.entry = auto_complete.AutocompleteEntry(self)
            self.build(case_sensitive=False,
                    no_results_message=auto_complete.NO_RESULTS_MESSAGE)
            self.entry.pack(after=label)

            self.nr = tk.StringVar()
            tk.Label(
                self,
                text="\n\nAlternative message (<Return> to set): "
            ).pack()
            nr = tk.Entry(self, textvariable=self.nr)
            nr.pack()
            nr.bind("<Return>", self._update)

            self.cs = tk.StringVar()
            cb = tk.Checkbutton(
                self,
                text="Case sensitive",
                variable=self.cs,
                state="normal",
                command=self._update
            )
            cb.deselect()
            cb.pack()

        def _update(self, *args):
            case_sensitive = False
            if self.cs.get() == "1":
                case_sensitive = True
            no_results_message = self.nr.get()
            self.build(
                case_sensitive=case_sensitive,
                no_results_message=no_results_message
            )

        def build(self, *args, **kwargs):
            self.entry.build(
                COUNTRIES,
                kwargs["case_sensitive"],
                kwargs["no_results_message"]
            )


    if __name__ == "__main__":
        root = tk.Tk()
        root.title("DEMO")
        root.resizable(False, False)
        root.tk_setPalette("white")

        application = Application(root)
        application.pack()

        root.mainloop()
```

### This the repo [here](https://github.com/RajvirSingh1313/Tkinter_Autocomplete_DropBox)

----------
components: Tkinter
files: auto_complete.py
messages: 380639
nosy: RajvirSingh1313
priority: normal
pull_requests: 22114
severity: normal
status: open
title: Added Auto_Complete DropBox Suggestion For Tkinter
type: enhancement
versions: Python 3.7
Added file: https://bugs.python.org/file49587/auto_complete.py

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue42305>
_______________________________________


More information about the New-bugs-announce mailing list