Function called by window maximise - python

I was wondering if there is a way of binding a function to a Tkinter window's maximise button. At first I tried the English way of spelling it root.protocol('WM_MAXIMISE_WINDOW', callback) (with callback being a simple function). Then I tried spelling it the American way: root.protocol('WM_MAXIMIZE_WINDOW', callback), all with no success. What is the correct way of doing this, if any? Thank you in advance for any help.

I don't think there is a protocol for maximizing the window. I can't find it, at least. You could try something like this, though:
def check_maximize(event):
screen_w, screen_h = root.winfo_screenwidth(), root.winfo_screenheight()
window_w, window_h = root.winfo_width(), root.winfo_height()
# check if window is as wide as screen and between height of screen and 100 pixels
# to compensate for task bar
if screen_w == window_w and screen_h > window_h > screen_h - 100:
print('Maximized or Maximised')
root = Tk()
root.bind('<Configure>', check_maximize) # callback on window move/resize
mainloop()

Related

Kivy. Python. It is possible to resize the main window such as the ratio between width and height remains constant during the process?

I try to create a video player in kivy and I need that this player to maintain its main window's initial proportions between width and height when the user performs the resize event over it.
I tried this piece of code:
from kivy.core.window import Window
#These are the initial values and I need to maintain this ratio, w/h, constant all the way as long as the resize event is kicked on by my mouse.
w = 350
h = round(w/16*9) + 60
Window.size = (w,h)
def reSize(*args):
# print(f'{args[1]} ;{args[2]}')
w = args[1]
h = w/16*9 + 60
Window.size = (w,h)
return True
Window.bind(on_resize = reSize)
Window.minimum_height = round(w/16*9) + 60
Window.minimum_width = w
and the result is hideous.
A huge window appears filling half of my screen and is completely inoperable.
I tried to find an event like onSizeChanged, like in matplot for example, but there isn't one in kivy framework.
Any suggestions or hints, please?

How to center window on the primary monitor only, on tkinter

I have multiple monitors, and when I try to center the window on the screen, it goes to the left edge of the screen.
Code:
def center_window(window, window_width, window_height, offset_x=0, offset_y=0):
s_width = window.winfo_screenwidth()
s_height = window.winfo_screenheight()
x_cordinate = int((s_width/2) - (window_width/2))
y_cordinate = int((s_height/2) - (window_height/2))
window.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate+offset_x, y_cordinate+offset_y))
If I disable a monitor, this doesn't happen, and the window gets centered correctly.
I tried other solutions, as explained in this question: How to center a window on the screen in Tkinter?
None of the answers work with a multiple-monitors setup.
By the way I'm on Ubuntu22-04.
Thanks for any help, I'll appreciate it.
Most commonly the Monitor with the upper left corner (0,0) is the primary screen. With that in mind, you can simply position your window with geometry('+0+0'), call update_idletasks() and then ask with winfo_screenwidth() for window's screen width and height and do the usual calculation.
Pro tipp: while you dont want to see a window flipping arround in your screen for the setup, you can use wm_attributes('-alpha') to make your actions invisible.
def center_window(window, window_width, window_height, offset_x=0, offset_y=0):
window.wm_attributes('-alpha',0)#hide window
window.geometry("{}x{}+{}+{}".format(window_width, window_height, 0,0) #0,0 primary Screen
window.update_idletasks() #make sure the properties are updated
s_width = window.winfo_screenwidth()
s_height = window.winfo_screenheight()
x_cordinate = int((s_width/2) - (window_width/2))
y_cordinate = int((s_height/2) - (window_height/2))
window.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate+offset_x, y_cordinate+offset_y))
window.wm_attributes('-alpha',1)#show window

Why is the button moving incorrectly

Run this code before answering -
from tkinter import *
root = Tk()
root.geometry('500x500')
def drag(e):
posx,posy = e.x_root,e.y
B1.place(x=posx,y=posy)
def size(event):
W,H,X,Y = event.width,event.height,event.x,event.y
root.title(f'W: {W}, H: {H}, X: {X}, Y: {Y}')
root.bind('<Configure>',size)
B1 = Button(root,text='Hi')
B1.place(x=0,y=0)
B1.bind("<B1-Motion>",drag)
Result:
When I try to move the button, it goes smoothly. But if I move the whole Tkinter window and then move the button, it goes somewhere else.
So, how do I fix it so that it is smooth?
EDIT: When I use e.x ..., 2 buttons are shown
Problem is because functions use different coordinates - event.x_root gives position on screen, not in window, and place() needs position in window, not on screen. There is also event.x which gives position inside button so it may not be useful.
You can use root.winfo_rootx() (which gives window position) to correct it.
You could also get mouse position on Button when you click it to correct its position when you move Button.
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def start(e):
global offsetx
global offsety
offsetx = e.x
offsety = e.y
print(offsetx, offsety)
def drag(e):
posx = e.x_root - root.winfo_rootx() - offsetx
posy = e.y_root - root.winfo_rooty() - offsety
button1.place(x=posx, y=posy)
# --- main ---
root = tk.Tk()
root.geometry('500x500')
button1 = tk.Button(root, text='Hi') # PEP8: `lower_case_names` for variables
button1.place(x=0, y=0)
button1.bind("<ButtonPress-1>", start)
button1.bind("<Button1-Motion>", drag)
root.mainloop()
PEP 8 - Style Guide for Python Code
EDIT:
Other method using e.widget to get widget position and relative e.x,e.y
def drag(e):
widget = e.widget
posx = widget.winfo_x() + e.x - offsetx
posy = widget.winfo_y() + e.y - offsety
button1.place(x=posx, y=posy)
This answer should help you fix it.
event.x_root is taking the screen coordinates and not the widget coordinates. Use event.x instead.

Use onkey() to do multiple functions with Python turtle

I'm trying to write a basic turtle drawing game/program and I've been using onkey(function, "key") to have the user input keystrokes. Well I wanted the user to be able to change the width of the pen by either hitting the up key to increase the width by one, or the down key to decrease the width by one. I know I need some kind of loop, but I don't really know where to implement it.
Here's a simple example that will make the turtle walk in a continuous circle while you press up and down arrows to change the pen width:
from turtle import Turtle, Screen
def larger():
size = turtle.pensize()
if size < 10:
turtle.pensize(size + 1)
def smaller():
size = turtle.pensize()
if size > 1:
turtle.pensize(size - 1)
def move():
turtle.circle(150, extent=3)
screen.ontimer(move, 100)
turtle = Turtle()
screen = Screen()
screen.onkey(larger, "Up")
screen.onkey(smaller, "Down")
screen.listen()
move()
screen.mainloop()
Make sure you click on the window first to make it the key listener.
I think you can't, but you can call the function insde the function you bind to the key:
from turtle import *
def function1():
do_that = "do that"
print(do_that)
def function2():
do_this = "do this"
print(do_this)
function1()
onkey(function2, "space")
do this
do that
It worked for me ;)

Tkinter won't allow for me to use variables to define window size

I am currently trying to add a feature to my program where the programs resolution will change at every launched based on your screen resolution. I have run into an issue though.
It first states that my variables, width and height are undefined. I then modified my code and it then says bad geometry specifier.
Undefined Variables:
pygame.mixer.init()
app = minecraftGuideApp()
#Window Definitions
screen_width = app.winfo_screenwidth()
screen_height = app.winfo_screenheight()
if screen_width == "1366" and screen_height == "768":
width = "1280"
height = "720"
app.geometry(width, height)
app.mainloop()
Bad Geometry Specifier:
pygame.mixer.init()
app = minecraftGuideApp()
#Window Definitions
screen_width = app.winfo_screenwidth()
screen_height = app.winfo_screenheight()
width = screen_width
height = screen_height
app.geometry((width, height))
app.mainloop()
I am still learning Python, so please excuse any dumb mistakes I am making.
What am I doing wrong though?
The syntax for a call to the Tkinter geometry method is given at this reference. You need to compose a geometry string in the proper syntax
which is:
"%dx%d%+d%+d" % (width, height, xoffset, yoffset)
In your case the call should look like
app.geometry("1280x720")

Categories