Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tkinter on Linux: tk.geometry(f"{d}x{d}") fails when maxsize() is set #92996

Open
chicory-ru opened this issue May 20, 2022 · 11 comments
Open

Tkinter on Linux: tk.geometry(f"{d}x{d}") fails when maxsize() is set #92996

chicory-ru opened this issue May 20, 2022 · 11 comments
Labels
expert-tkinter type-bug

Comments

@chicory-ru
Copy link

@chicory-ru chicory-ru commented May 20, 2022

Issue with Tkinter (python 3.10.4) on Linux/Ubuntu 22.04.

self.minsize(250, 250)
self.maxsize(1900, 1900)
self.resizable(width=False, height=False)

I need to resize a window programmatically and when I limit the upper limit of the window, then self.geometry(f'{width_window}x{width_window}') doesn't save or resize the window. As soon as I comment out self.maxsize(1900, 1900), everything starts working fine. In Windows 10, it also works fine with the lower and upper limits.

Video: https://youtu.be/a1dKwnohMbo

@chicory-ru chicory-ru added the type-bug label May 20, 2022
@chicory-ru chicory-ru changed the title Tkiner Tkinter May 20, 2022
@sweeneyde
Copy link
Member

@sweeneyde sweeneyde commented May 20, 2022

Can you try to post here a minimal reproducible example of the code that is leading to your issue?

@AlexWaygood AlexWaygood added the pending label May 20, 2022
@chicory-ru
Copy link
Author

@chicory-ru chicory-ru commented May 20, 2022

'''Scale the square window with the mouse wheel. For Linux.'''

import tkinter as tk


class ChessBoard(tk.Tk):

    def __init__(self):
        super().__init__()
        self.minsize(250, 250)

        # self.maxsize(1900, 1900) # Uncomment for bug.

        self.resizable(width=False, height=False)
        self.canvas = tk.Canvas(self)
        self.canvas.bind_all("<Button-4>", self.window_size_up)
        self.canvas.bind_all("<Button-5>", self.window_size_down)

    def window_size_up(self, event):
        width = self.winfo_width()
        width_window = width + 20
        self.geometry(f'{width_window}x{width_window}')
        print(width_window)
        print(f'geometry: {self.geometry()}')

    def window_size_down(self, event):
        width = self.winfo_width()
        width_window = width - 20
        self.geometry(f'{width_window}x{width_window}')
        print(width_window)
        print(f'geometry: {self.geometry()}')


if__name__ == "__main__": 
    board = ChessBoard() 
    board.mainloop()

@chicory-ru
Copy link
Author

@chicory-ru chicory-ru commented May 20, 2022

So simpler, but the result is the same.

import tkinter as tk

def window_size_up(event):
    width_window = root.winfo_width() + 20
    root.geometry(f'{width_window}x{width_window}')

def window_size_down(event):
    width_window = root.winfo_width() - 20
    root.geometry(f'{width_window}x{width_window}')


root = tk.Tk()
root.minsize(250, 250)
# root.maxsize(1900, 1900)  # Uncomment for bug.
root.resizable(width=False, height=False)
root.bind_all("<Button-4>", window_size_up)
root.bind_all("<Button-5>", window_size_down)
root.mainloop()

@sweeneyde
Copy link
Member

@sweeneyde sweeneyde commented May 20, 2022

Hm. I could not replicate this on Windows: with that line included, as keys were pressed, my window shrank down to 250 or grew up to 1900.

@sweeneyde sweeneyde changed the title Tkinter Tkinter on Linux: tk.geometry(f"{d}x{d}") fails when maxsize() is set May 20, 2022
@chicory-ru
Copy link
Author

@chicory-ru chicory-ru commented May 20, 2022

I wrote in the first post that there is no such problem in Windows. It says in which OS and which version of Python.

@sweeneyde sweeneyde removed the pending label May 20, 2022
@chicory-ru
Copy link
Author

@chicory-ru chicory-ru commented May 21, 2022

I still have Thonny with built-in python 3.7.9 in ubuntu. I just checked, it has the same bug. It looks like some kind of paleontological mistake from the time of the dinosaurs)

@Akuli
Copy link
Contributor

@Akuli Akuli commented May 23, 2022

Your window manager is what decides how .geometry(), .minsize() and .maxsize() work. Those just send requests to the window manager, and it decides how to handle them. If it wants, it could theoretically even ignore all .geometry() requests, and place and resize your window in whatever way it wants (see: tiling window managers).

On linux, there's many different window managers (xfwm, macro, i3, xmonad, etc). So how exactly .minsize(), .maxsize() and .geometry() work is very platform-specific.

In other words, this is not a bug in tkinter, or in Tcl/Tk; it's how your window manager behaves (and maybe a bug in the window manager, depending on what its developers think).

On my computer, with xfwm4 as the window manager, it works if I temporarily set .resizable(True, True) before the .geometry(), and then immediately set .resizable(False, False) again.

@chicory-ru
Copy link
Author

@chicory-ru chicory-ru commented May 23, 2022

If it works in any of the Linux managers at all ...
In any case, the situation needs to be corrected at least from someone's side :)
In my program, I had to abandon minsize () and maxsize() at all.
I limit the window size in my zoom function like this:

if 250 < width_window < 1900:
    self.geometry(f'{width_window}x{width_window}')

This is how it should work everywhere.

@Akuli
Copy link
Contributor

@Akuli Akuli commented May 24, 2022

Does my suggest not work for you? Which window manager are you using on linux?

To be clear, I'm suggesting:

import tkinter

root = tkinter.Tk()
root.minsize(300, 300)
root.maxsize(500, 500)
root.resizable(False, False)

def bigger(e):
    size = root.winfo_width() + 20
    root.resizable(True, True)
    root.geometry(f'{size}x{size}')
    root.resizable(False, False)

def smaller(e):
    size = root.winfo_width() - 20
    root.resizable(True, True)
    root.geometry(f'{size}x{size}')
    root.resizable(False, False)

root.bind('<Button-4>', bigger)
root.bind('<Button-5>', smaller)
root.mainloop()

@chicory-ru
Copy link
Author

@chicory-ru chicory-ru commented May 24, 2022

I wanted it to work fine on both Linux and Windows. Your version in Windows looks awful! The window flickers a lot and a lot of phantom tasks appear on the taskbar that do not have time to close quickly.
So far I have this option:

import tkinter

def window_size(event):
    if event.delta:   # Windows
        width_window = root.winfo_width() + event.delta // 10
    else:  # Linux
        i = -20
        if event.num == 4:
            i = 20
        width_window = root.winfo_width() + i
    if 250 < width_window < 1000:
        root.geometry(f'{width_window}x{width_window}')

root = tkinter.Tk()
root.resizable(False, False)
root.geometry('400x400')
root.bind_all("<MouseWheel>", window_size)
root.bind_all("<Button-4>", window_size)
root.bind_all("<Button-5>", window_size)
root.mainloop()

@Akuli
Copy link
Contributor

@Akuli Akuli commented May 24, 2022

It's not unusual to write code like "if windows do this, else do that". It's especially common when you need to rely on something very platform-specific, such as how window managers behave :) I still don't think it's a bug in Tk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
expert-tkinter type-bug
Projects
None yet
Development

No branches or pull requests

5 participants