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

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

Related

Why is my Python turtle screen asymmetrical?

I created a pong game where I noticed the paddles are not placed equally at the screen edges.
I created an 800 pixel wide screen, and placed paddles at xcor = 380 and xcor = -380 but on the screen left paddle shows some gap but right paddle doesn't. Is my screen unsymmetrical? How do I fix it?
screen.setup(width=800, height=600)
screen.bgcolor("black")
screen.title("PONG")
screen.tracer(0)
l_paddle = Paddle()
l_paddle.create_paddle((-380, 0))
r_paddle = Paddle()
r_paddle.create_paddle((380, 0))
screenshot of screen
When we specify a window size to setup(), we're talking about total pixels used on the screen. Since there is chrome around the window (edges, title bar, etc.) the actual area we have to work with is slightly smaller. Trying to place two turtles at exactly the left and right edge, ignoring chrome:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
WIDTH, HEIGHT = 600, 400
screen = Screen()
screen.setup(WIDTH, HEIGHT)
l_paddle = Turtle('square')
l_paddle.fillcolor('white')
l_paddle.setx(CURSOR_SIZE/2 - WIDTH/2)
r_paddle = Turtle('square')
r_paddle.fillcolor('white')
r_paddle.setx(WIDTH/2 - CURSOR_SIZE/2)
screen.exitonclick()
We get a result similar to yours:
If we compensate for the internal and external chrome elements:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
BORDER_SIZE = 2 # inside the window
CHROME_SIZE = 9 # around the window
WIDTH, HEIGHT = 600, 400
screen = Screen()
screen.setup(WIDTH, HEIGHT)
l_paddle = Turtle('square')
l_paddle.fillcolor('white')
l_paddle.setx(CURSOR_SIZE/2 - WIDTH/2 + BORDER_SIZE)
r_paddle = Turtle('square')
r_paddle.fillcolor('white')
r_paddle.setx(WIDTH/2 - CURSOR_SIZE/2 - BORDER_SIZE - CHROME_SIZE)
screen.exitonclick()
We can get a more precise result:
The problem here is that the amount of chrome is system dependent but turtle doesn't tell us how much to compensate. You might be able to find out from the underlying tkinter code.
My recommendation is you estimate the best you can, assume it's not accurate on all systems, and stay away from the edges so it's less of an issue. The error can be greater in the Y dimension when the title bar is part of the chrome.

Is there a way to make a windowed fullscreen mode in pygame?

I want the window to be my resolution but still have the top bar appear. Just like you maximise a window.
This is what I have so far.
os.environ['SDL_VIDEO_CENTERED'] = '1'
display_info = pygame.display.Info()
self.width, self.height = display_info.current_w, display_info.current_h
self.screen = pygame.display.set_mode((self.width, self.height), pygame.NOFRAME)
but it seems to not work and only fullscreen the window to my resolution. What am I missing?
You can make the window to be in fullscreen mode using this:
pygame.display.set_mode(screen_size, FULLSCREEN)
If you have black borders around, you can make the window to fill the entire screen, leaving as few black borders as possible (depending of the relative screen and window ratio), by the use of the pygame 2.0.0 flag SCALED:
pygame.display.set_mode(screen_size, FULLSCREEN|SCALED)
If you still want to delete the remaining borders, rescale your window:
import pygame
pygame.init()
info = pygame.display.Info()
w = info.current_w
h = info.current_h
screen = pygame.display.set_mode((w, h), FULLSCREEN|SCALED)

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")

Function called by window maximise

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()

How to detect resizeable window state in pygame and de-maximize it in Linux?

I have an application built in python with use of pygame that initially displays a login screen at a set size which is not RESIZABLE and then when user logs into the game the saved settings are being used to transform the window size. The window is turned into RESIZABLE after login. If user logs out the window is changed back to the initial size without RESIZABLE flag. Everything is OK as long as the user logs out from normal window, but when user hits the maximize button and then logs out in some distros the window still stays maximized and the login screen is being painted in a top left corner of the window.
And here comes the question, is there a way of detecting whether the window has been maximized so I can de-maximize it before sizing down?
I couldn't find anything that would help me with this in the pygame docs or anywhere online. I have found a way of getting a "handle" to the window by using:
pygame.display.get_wm_info()['window']
but not sure where to take it from here.
The way I set the sizes:
self.screen = pygame.display.set_mode((800, 480)) #login screen
self.screen = pygame.display.set_mode(user_saved_size, pygame.RESIZABLE) #game screen
get_wm_info()['wmwindow'] gives you windowID in Windows Manager (X.org) but it is "outside" of PyGame. Maybe with python library Xlib you could do something.
EDIT:
I tried example in Setting the window dimensions of a running application to change terminal size and it works but it don't change PyGame window size. I tried xlib to get PyGame window caption and it works but I could not set PyGame window caption.It seems PyGame doesn't respect new caption.
I use this code to test PyGame window caption - it can get caption but it can't set caption.
import sys
import pygame
from pygame.locals import *
import Xlib
import Xlib.display
WIDTH, HEIGHT = 1500, 300
pygame.init()
screen = pygame.display.set_mode((800,600),0,32)
print "wm_info:", pygame.display.get_wm_info()
print " window:", pygame.display.get_wm_info()['window']
print "fswindow:", pygame.display.get_wm_info()['fswindow']
print "wmwindow:", pygame.display.get_wm_info()['fswindow']
display = Xlib.display.Display()
root = display.screen().root
#windowID = root.get_full_property(display.intern_atom('_NET_ACTIVE_WINDOW'), Xlib.X.AnyPropertyType).value[0]
#print "Xlib windowID:", windowID
#window = display.create_resource_object('window', windowID)
window = display.create_resource_object('window', pygame.display.get_wm_info()['window'])
window.configure(width = WIDTH, height = HEIGHT)
print "Xlib window get_wm_name():", window.get_wm_name()
window = display.create_resource_object('window', pygame.display.get_wm_info()['fswindow'])
window.configure(width = WIDTH, height = HEIGHT)
print "Xlib fswindow get_wm_name():", window.get_wm_name()
window = display.create_resource_object('window', pygame.display.get_wm_info()['wmwindow'])
window.configure(width = WIDTH, height = HEIGHT)
print "Xlib wmwindow get_wm_name():", window.get_wm_name()
print
print "Xlib wmwindow set_wm_name(hello world of xlib)"
window.set_wm_name("hello world of xlib")
display.sync()
print "Xlib wmwindow get_wm_name():", window.get_wm_name()
# --------------
fpsClock = pygame.time.Clock()
RUNNING = True
while RUNNING:
for event in pygame.event.get():
if event.type==QUIT:
RUNNING = False
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
RUNNING = False
fpsClock.tick(25)
# --------------
pygame.quit()
sys.exit()
I use this code to change window size - it works in terminal and DreamPie (python shell):
# https://unix.stackexchange.com/questions/5999/setting-the-window-dimensions-of-a-running-application
WIDTH, HEIGHT = 1500, 300
import Xlib
import Xlib.display
display = Xlib.display.Display()
root = display.screen().root
windowID = root.get_full_property(display.intern_atom('_NET_ACTIVE_WINDOW'), Xlib.X.AnyPropertyType).value[0]
window = display.create_resource_object('window', windowID)
window.configure(width = WIDTH, height = HEIGHT)
display.sync()
#windowIDs = root.get_full_property(display.intern_atom('_NET_CLIENT_LIST'), Xlib.X.AnyPropertyType).value
#for windowID in windowIDs:
# window = display.create_resource_object('window', windowID)
# name = window.get_wm_name() # Title
# pid = window.get_full_property(display.intern_atom('_NET_WM_PID'), Xlib.X.AnyPropertyType) # PID

Categories