我尝试使用tkinter
在屏幕的特定点显示窗口(0.0 =上/左,1.0 =下/右)。不幸的是,显示器通常偏离其应有位置约8个像素。(不是其左上点),我已经写了一个函数来计算x
和y
的位置与窗体的尺寸。的大小,因此不会在任务栏下生成窗体。)
由于tkinter
允许使用geometry("form_width x form_height + x_offset + y_offset")
进行定位,因此每当我尝试让它在偏移量(0,0)它生成稍微向右偏远的位置-需要(-8,0)来加载屏幕左上角的窗口,没有间隙。在左下方加载(0,1)生成的值稍高(窗体和任务栏之间有间隙)和太靠右。右上角和右下角也存在类似的问题。总之,它总是生成大约8个像素太靠右,如果它试图在监视器工作区的底部生成,它会生成太高的8。(在顶部生成不会把它放得太高。)
当所有元素都添加到表单后调用定位函数时,它会调用表单上的.update()
来重新计算所需的空间,然后使用.winfo_reqwidth()
和.winfo_reqheight()
执行所有必要的计算,然后将结果传递给窗口的geometry()
。
为什么会出现像素偏移问题?是因为update()
没有考虑到表单元素的某些填充,还是我的计算机显示器有问题?(我不认为是屏幕问题-所有其他应用程序都正常工作,但我可能错了。)
计算窗体位置的函数如下。参数:window
-计算位置的形式/顶层,pos_xy
-屏幕中位置的列表/元组或枚举(包含元组)(左上角0,0;右下角1,1)。
def new_calc_position(self, window, pos_xy):
# if size of desktop minus taskbar has not been calculated, calculate it
if self.work_area is None:
monitor_info = GetMonitorInfo(MonitorFromPoint((0, 0)))
workspace = monitor_info.get("Work")
self.work_area = [workspace[2], workspace[3]] # [width, height]
print(f"Work area: {workspace[2]}, {workspace[3]}")
monitor_area = monitor_info.get("Monitor")
self.taskbar_height = monitor_area[3] - workspace[3]
print(f"Monitor area: {monitor_area[2]}, {monitor_area[3]}")
print(f"Taskbar height: {self.taskbar_height}")
# test that pos_xy is enum Position or list containing two floats 0.0 <= x <= 1.0
if type(pos_xy) is Position:
pos_xy = pos_xy.value # convert enum to list for use
elif isinstance(pos_xy, (list, tuple)) and len(pos_xy) == 2 and all(isinstance(el, float) and
0.0 <= el <= 1.0 for el in pos_xy):
pass # is list/tuple, length of 2, and all numbers are floats 0.0 <= x <= 1.0
else:
raise TypeError("pos_xy must be of type Position or a list containing two numbers between 0.0 and 1.0")
window.withdraw() # stop window from showing
window.update() # force it to update its required size; would flash to screen if not withdrawn
window.deiconify() # allow window to show
# calculate targeted position
target_width = self.work_area[0] * pos_xy[0]
target_height = self.work_area[1] * pos_xy[1]
print("Monitor width: " + str(self.work_area[0]))
print("Monitor height: " + str(self.work_area[1]))
print("Width percent: " + str(pos_xy[0]))
print("Height percent: " + str(pos_xy[1]))
print("Width target: " + str(target_width))
print("Height target: " + str(target_height))
# calculate required width and height
width = window.winfo_reqwidth()
height = window.winfo_reqheight()
print("Form width: " + str(width))
print("Form height: " + str(height))
# TODO create a lock parameter to allow a certain generation point
x_offset = int(target_width - (width / 2))
y_offset = int(target_height - (height / 2))
print("Initial xoffset: " + str(x_offset))
print("Initial yoffset: " + str(y_offset))
# bounce window to display entirely in screen; assume will not overlap both sides in one dimension
if x_offset < 0: # too far to left
x_offset = 0
elif x_offset + width > self.work_area[0]: # too far to right
x_offset = self.work_area[0] - width
if y_offset < 0:
y_offset = 0
elif y_offset + height > self.work_area[1]:
y_offset = self.work_area[1] - self.taskbar_height - height
print("Ending xoffset: " + str(x_offset))
print("Ending yoffset: " + str(y_offset))
print(f"{width}x{height}+{x_offset}+{y_offset}")
return f"{width}x{height}+{x_offset}+{y_offset}"
1条答案
按热度按时间atmip9wb1#
我不能告诉你为什么x偏移问题会发生,但我至少可以确认你是对的。
我以前从未注意到这一点,但在我的Windows10机器上,x偏移量为0,y偏移量为0将根窗口正确地放置在屏幕顶部。但它位于大约7像素我的右边,在屏幕左手留下一个小间隙。将x偏移设置为-7将根窗口正确地定位在屏幕的左侧,没有间隙。
注意,你可以用鼠标抓取根窗口并将其移动到屏幕的左侧。因此,无论你是使用负偏移量,还是手动移动窗口,当被迫这样做时,它都没有问题正确地位于屏幕的左侧。
其他Windows应用程序在最大化时确实正确地位于屏幕的左手,因此这将其缩小到tkinter的怪癖,或者Windows和tkinter之间的交互。
如果这种行为在Linux和Mac上是一样的,那么这是tkinter的怪癖。如果不是,那么这是Windows + tkinter的问题。
最重要的是,你的代码不是问题所在。