Search code examples
pythontkintertkinter-canvas

How to prevent canvas selection in tkinter?


I am currently developping an application using tkinter and I struggle with a cosmetic issue. When adding an entry to a canvas, tkinter displays a selection cursor around the entry and the canvas. I would like to avoid this behavior for the canvas because I am using it to create a scrollable frame which create a very unpleasant effect, the selection being displayed only on the sides because the rest of the canvas is out of the screen.

I created a small code sample to experiment with this.

Here is the display without selection: without selection

Here is the display with the selection: with the selection

I would like to avoid having the dark grey rectangle around the canvas, would you please know how to do it?

Here is my code sample:

###########
# Imports #
###########

import tkinter as tk
from tkinter import ttk

#########
# Class #
#########

class ScrollableFrame(ttk.Frame):
    def __init__(self, container, *args, **kwargs):
        super().__init__(container, *args, **kwargs)
        canvas = tk.Canvas(self, takefocus=0)
        self.canvas = canvas
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas, takefocus=0)
        self.scrollable_frame.columnconfigure(index=0, weight=1)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        self.scrollable_frame_id = canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        canvas.configure(yscrollcommand=scrollbar.set)
        self.canvas.bind('<Configure>', self.on_width_change)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
    def on_mousewheel(self, event):
        shift = (event.state & 0x1) != 0
        scroll = -1 if event.delta > 0 else 1
        if shift:
            self.canvas.xview_scroll(scroll, "units")
        else:
            self.canvas.yview_scroll(scroll, "units")

    def on_width_change(self, event):
        canvas_width = event.width
        self.canvas.itemconfig(self.scrollable_frame_id, width=canvas_width * 0.99)

    def bind_tree(self, event, callback, widget=None):
        """
        Binds an event to a widget and all its descendants.
        """

        if widget is None:
            widget = self

        if isinstance(widget, ttk.Combobox):
            return

        widget.bind(event, callback, "")

        for child in widget.children.values():
            self.bind_tree(widget=child, event=event, callback=callback)

    def bind_list(self, widgets, event, callback):
        for widget in widgets:
            self.bind_tree(widget=widget, event=event, callback=callback)

    def set_mouse_scroll_on_list(self, widgets):
        self.bind_list(widgets, "<MouseWheel>", self.on_mousewheel)


###########
# Process #
###########

root = tk.Tk()

frame = ScrollableFrame(root)
frame.grid(row=0,column=0,sticky="nsew")

entry = ttk.Entry(frame.scrollable_frame)
entry.pack()

root.mainloop()

Solution

  • It is caused by highlightthickness not setting to zero. Set it to zero to fix it:

    canvas = tk.Canvas(self, takefocus=0, highlightthickness=0)