在次要显示器上,Tkinter窗口未在缩放状态下填充屏幕(Tkinter window not filling screen in zoomed state on secondary display)

我正在windows(10)上构建一个小的python 3 tkinter程序。 从主窗口(root)我正在创建一个辅助窗口(wdowViewer)。 我希望它在我的辅助显示器上全屏(缩放)。 下面的代码适用于我的主要设置,有两个相同的屏幕。 但是,如果我将笔记本电脑从扩展坞中取出并将其连接到(任何)外部显示器,则新窗口仅填充辅助显示器的大约2/3。

需要注意两点: - 笔记本电脑和外接显示器具有相同的分辨率。 - 当overrideredirect设置为0时,窗口会适当缩放。

mon_primary_width = str(app.root.winfo_screenwidth()) # width of primary screen self.wdowViewer = Toplevel(app.root) # create new window self.wdowViewer.geometry('10x10+' + mon_primary_width + '+0') # move it to the secondary screen self.wdowViewer.wm_state('zoomed') # full screen self.wdowViewer.overrideredirect(1) # remove tool bar app.root.update_idletasks() # Apply changes

I'm building a small python 3 tkinter program on windows (10). From a main window (root) I'm creating a secondary window (wdowViewer). I want it to be full screen (zoomed) on my secondary display. The code below works on my main setup with two identical screens. If I however take my laptop out of the dock and connect it to (any) external display, the new window only fills about 2/3 of the secondary display.

Two things to note: - The laptop and external monitor have same resolution. - The window is appropriately zoomed when overrideredirect is set to 0.

mon_primary_width = str(app.root.winfo_screenwidth()) # width of primary screen self.wdowViewer = Toplevel(app.root) # create new window self.wdowViewer.geometry('10x10+' + mon_primary_width + '+0') # move it to the secondary screen self.wdowViewer.wm_state('zoomed') # full screen self.wdowViewer.overrideredirect(1) # remove tool bar app.root.update_idletasks() # Apply changes

最满意答案

经过两天的实验,我终于找到了解决办法。

请考虑以下示例:使用以下代码进行顶层放大,在任何辅助显示器上都能正常工作:

from tkinter import * # Make tkinter window root = Tk() sw = str(root.winfo_screenwidth()) Label(root, text="Hello Main Display").pack() # Make a new toplevel w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() root.mainloop()

但是,在我的代码中,我在运行mainloop命令后创建了一个新的Toplevel。 然后,问题就出现了。 问题的代码示例:

from tkinter import * # New Tkinter root = Tk() sw = str(root.winfo_screenwidth()) # Function for new toplevel def new_wdow(): w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() # Make button in main window Button(root, text="Hello", command=new_wdow).pack() root.mainloop()

问题:仅当Windows中的DPI缩放未设置为100%时,才会出现该错误。 因此,在运行mainloop之后,tkinter如何处理DPI扩展似乎存在一个错误。 它不能正确缩放窗口,但Windows正在将其视为一样。

修复:告诉Windows该应用程序单独负责DPI扩展,并且不调整窗口大小。 这可以使用ctypes实现。 在python脚本中提前输入以下代码:

import ctypes ctypes.windll.shcore.SetProcessDpiAwareness(2)

希望其他人会发现解决方案很有帮助。 希望有人可以解释更多这里发生的事情!

After two days of experimenting I finally found a fix.

Consider the following example: Making a toplevel zoomed, works fine on any secondary display when using the following code:

from tkinter import * # Make tkinter window root = Tk() sw = str(root.winfo_screenwidth()) Label(root, text="Hello Main Display").pack() # Make a new toplevel w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() root.mainloop()

However, in my code I'm making a new Toplevel after running the mainloop command. Then, the issue arises. A code example with the issue:

from tkinter import * # New Tkinter root = Tk() sw = str(root.winfo_screenwidth()) # Function for new toplevel def new_wdow(): w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() # Make button in main window Button(root, text="Hello", command=new_wdow).pack() root.mainloop()

Problem: The bug is only present if the DPI scaling in Windows is not set to 100%. Hence, there seems to be a bug in how tkinter handles the DPI scaling subsequent to running mainloop. It does not scale the window properly, but Windows is treating it as if it does.

Fix: Tell Windows that the app takes care of DPI scaling all by itself, and to not resize the window. This is achievable using ctypes. Put the following code early in your python script:

import ctypes ctypes.windll.shcore.SetProcessDpiAwareness(2)

Hopefully others will find the solution helpful. Hopefully, someone may explain more of what is going on here!

在次要显示器上,Tkinter窗口未在缩放状态下填充屏幕(Tkinter window not filling screen in zoomed state on secondary display)

我正在windows(10)上构建一个小的python 3 tkinter程序。 从主窗口(root)我正在创建一个辅助窗口(wdowViewer)。 我希望它在我的辅助显示器上全屏(缩放)。 下面的代码适用于我的主要设置,有两个相同的屏幕。 但是,如果我将笔记本电脑从扩展坞中取出并将其连接到(任何)外部显示器,则新窗口仅填充辅助显示器的大约2/3。

需要注意两点: - 笔记本电脑和外接显示器具有相同的分辨率。 - 当overrideredirect设置为0时,窗口会适当缩放。

mon_primary_width = str(app.root.winfo_screenwidth()) # width of primary screen self.wdowViewer = Toplevel(app.root) # create new window self.wdowViewer.geometry('10x10+' + mon_primary_width + '+0') # move it to the secondary screen self.wdowViewer.wm_state('zoomed') # full screen self.wdowViewer.overrideredirect(1) # remove tool bar app.root.update_idletasks() # Apply changes

I'm building a small python 3 tkinter program on windows (10). From a main window (root) I'm creating a secondary window (wdowViewer). I want it to be full screen (zoomed) on my secondary display. The code below works on my main setup with two identical screens. If I however take my laptop out of the dock and connect it to (any) external display, the new window only fills about 2/3 of the secondary display.

Two things to note: - The laptop and external monitor have same resolution. - The window is appropriately zoomed when overrideredirect is set to 0.

mon_primary_width = str(app.root.winfo_screenwidth()) # width of primary screen self.wdowViewer = Toplevel(app.root) # create new window self.wdowViewer.geometry('10x10+' + mon_primary_width + '+0') # move it to the secondary screen self.wdowViewer.wm_state('zoomed') # full screen self.wdowViewer.overrideredirect(1) # remove tool bar app.root.update_idletasks() # Apply changes

最满意答案

经过两天的实验,我终于找到了解决办法。

请考虑以下示例:使用以下代码进行顶层放大,在任何辅助显示器上都能正常工作:

from tkinter import * # Make tkinter window root = Tk() sw = str(root.winfo_screenwidth()) Label(root, text="Hello Main Display").pack() # Make a new toplevel w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() root.mainloop()

但是,在我的代码中,我在运行mainloop命令后创建了一个新的Toplevel。 然后,问题就出现了。 问题的代码示例:

from tkinter import * # New Tkinter root = Tk() sw = str(root.winfo_screenwidth()) # Function for new toplevel def new_wdow(): w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() # Make button in main window Button(root, text="Hello", command=new_wdow).pack() root.mainloop()

问题:仅当Windows中的DPI缩放未设置为100%时,才会出现该错误。 因此,在运行mainloop之后,tkinter如何处理DPI扩展似乎存在一个错误。 它不能正确缩放窗口,但Windows正在将其视为一样。

修复:告诉Windows该应用程序单独负责DPI扩展,并且不调整窗口大小。 这可以使用ctypes实现。 在python脚本中提前输入以下代码:

import ctypes ctypes.windll.shcore.SetProcessDpiAwareness(2)

希望其他人会发现解决方案很有帮助。 希望有人可以解释更多这里发生的事情!

After two days of experimenting I finally found a fix.

Consider the following example: Making a toplevel zoomed, works fine on any secondary display when using the following code:

from tkinter import * # Make tkinter window root = Tk() sw = str(root.winfo_screenwidth()) Label(root, text="Hello Main Display").pack() # Make a new toplevel w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() root.mainloop()

However, in my code I'm making a new Toplevel after running the mainloop command. Then, the issue arises. A code example with the issue:

from tkinter import * # New Tkinter root = Tk() sw = str(root.winfo_screenwidth()) # Function for new toplevel def new_wdow(): w = Toplevel(root) w.geometry("0x0+" + sw + "+0") w.state('zoomed') w.overrideredirect(1) Label(w, text='Hello Secondary Display').pack() # Make button in main window Button(root, text="Hello", command=new_wdow).pack() root.mainloop()

Problem: The bug is only present if the DPI scaling in Windows is not set to 100%. Hence, there seems to be a bug in how tkinter handles the DPI scaling subsequent to running mainloop. It does not scale the window properly, but Windows is treating it as if it does.

Fix: Tell Windows that the app takes care of DPI scaling all by itself, and to not resize the window. This is achievable using ctypes. Put the following code early in your python script:

import ctypes ctypes.windll.shcore.SetProcessDpiAwareness(2)

Hopefully others will find the solution helpful. Hopefully, someone may explain more of what is going on here!