2

I've started learning Tkinter recently and yesterday I've noticed a strange behavioural difference of the same code with the same Python 2.7 when running it on a Win 10 and Xubuntu 16.04 systems.

Here is the code I'm working on (which means there are probably many other bugs :)):

from random import choice
from string import ascii_uppercase

import Tkinter as tk

class Manager(tk.Canvas):

    counter = 0
    previously_focused = 0

    def __init__(self, master=None, **kwargs):
        tk.Canvas.__init__(self,master,**kwargs)
        self.frame = tk.Frame(self)
        self.create_window(0,0,anchor=tk.N+tk.W,window=self.frame)
        self.row = 0
        self.widgets = {}
        self.lookup_entry = None

        self.frame.bind("<Configure>", lambda event, canvas=self: self.onFrameConfigure())

    def onFrameConfigure(self):
        '''
        Reset the scroll region to encompass the inner frame
        '''
        self.configure(scrollregion=self.bbox("all"))

    def __set__(self, e_id):
        '''
        Dummy that "sets" the value that the user has entered in the entry.
        In addition it also resets the background of the entry
        '''
        print("Setting \"" + self.widgets[e_id]["label"].cget("text") + "\" to \"" + str(self.widgets[e_id]["value"].get()) + "\"")
        self.widgets[e_id]["value"]["background"]="white"

    def __select_all__(self, event):
        entry = event.widget
        entry.select_range(0, tk.END)
        entry.icursor(0)

    def add_entry(self):
        '''
        Creates an entry conisting of a label, entry and button, adds it to the grid and stores
        it in a dictionary for easier access
        '''
        label = tk.Label(self.frame, text="".join(choice(ascii_uppercase) for i in range(12)) + "_" +str(self.counter))
        label.grid(row = self.row,column = 0)
        entry = tk.Entry(self.frame, background="white")
        entry.bind("<Control-KeyRelease-a>", self.__select_all__)
        entry.grid(row = self.row,column = 1)
        button = tk.Button(self.frame, text="Set", command=lambda counter=self.counter: self.__set__(str(counter)))
        button.grid(row = self.row,column = 2)
        self.widgets[str(self.counter)] = {"label": label, "value":entry, "button":button, "position":self.row}
        self.row += 1
        self.counter += 1

    def lookup(self, e_id):
        '''
        Automatically focuses and scrolls to the entry of the given id
        if found. In addition it also changes the background of that entry.

        If user enters an id that cannot be parsed (to int), nothing happens
        '''
        try:
            if self.previously_focused != int(e_id):
                self.widgets[str(self.previously_focused)]["value"]["background"]="white"

            if e_id not in self.widgets:
                print("Unable to find entry with id \"" + e_id + "\"")
                return

            print(self.widgets[e_id]["label"].cget("text"))
            self.widgets[e_id]["value"]["background"]="orange"
            self.widgets[e_id]["value"].focus()
            self.yview_moveto(0) # Adjust the Y offset of the canvas so that we always start from the top
            self.yview_scroll(self.widgets[e_id]["position"], tk.UNITS) # Scroll downwards to the given entry
            self.previously_focused = int(e_id)
        except ValueError:
            print("Id needs to be an integer")

if __name__ == "__main__":
    root = tk.Tk()

    scroll = tk.Scrollbar(root)
    scroll.grid(row=0,column=0,sticky=tk.N+tk.S)
    manager = Manager(root)
    manager.grid(row=0,column=1)
    manager.config(yscrollcommand = scroll.set)
    scroll.config(command=manager.yview)

    add_button = tk.Button(root, text = "+", command=manager.add_entry)
    add_button.grid(row=1,column=0)

    frame_lookup = tk.Frame(root)
    lookup_entry = tk.Entry(frame_lookup)
    lookup_entry.grid(row=0,column=0)
    lookup_button = tk.Button(frame_lookup, text="Find, focus & scroll to", command=lambda: manager.lookup(lookup_entry.get()))
    lookup_button.grid(row=0,column=1)
    frame_lookup.grid(row=1, column=1)

    root.mainloop()

I've adapted the code found here on SO (sorry, forgot where I got it from). Basically upon clicking the + button you add an element to the grid above (which is inside a canvas that allows me to use the vertical scrollbar). Each element consists of a label (<random-12-characters-sequence>_<increment-counter>), entry and a dummy button that does almost nothing. The important part is the field at the bottom along with the button Find, focus & scrollto. Whenever the user enters a valid ID the application automatically focuses the entry of the element the ID belongs to and scrolls to it so that it's within sight. The rest of the code is not that important.

The occurrence of visual differences is something I'm well aware of (right: Linux, left: Win):

enter image description here enter image description here

My problem is with the way the application acts when it comes to the autoscrolling feature. As you can see above on Linux I always get a full view of the element with the focused entry inside. On Win that happens only if there is no scrolling room up-/downwards from that element.

The way the autoscrolling works is that I first reset the offset of the canvas to (0, 0) and from there scroll X UNITS, where X is the increment counter that also acts as a source of information for the position of the element in the grid.

Any idea why this is happening? Is it possible that UNITS on Win is different from UNITS on Linux?

rbaleksandar
  • 8,713
  • 7
  • 76
  • 161
  • if you wan to know if `UNITS` is different on the two platforms, why not just print them out to see what they are? – Bryan Oakley Aug 10 '17 at 11:59
  • I know the string behind `UNITS`. I'm asking if internally this setting is handled differently based on the platform it is used on. – rbaleksandar Aug 10 '17 at 12:58

0 Answers0