tkinter:同步 Geometry() 和 GNOME 3

问题描述 投票:0回答:1

对于某些 tkinter 应用程序想要保存/恢复 Windows 配置。使用geometry()方法。得到我无法理解的结果,我在下面编写了一个例子来说明问题。

$ python
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tkinter import *
>>> t1 = Toplevel()
>>> t1.title('T1')
''
>>> m = Menu(t1)
>>> t1.config(menu=m)
>>> m.add_command(label='Save')
>>> t2 = Toplevel()
>>> t2.config(menu=m)
>>> t2.title('T2')
''

用鼠标将T1移动到屏幕上的任意位置(最好不要在左上角)。

>>> t2.geometry(t1.geometry())
''
>>> 

尽管 Geometry() 报告相同的大小/位置,但窗口在屏幕上的放置方式不同(x、y 相差 10 个像素)。 “手动”移动 T1 窗口至关重要,如果通过 Geometry() 移动,则不会观察到位移。

使用 Debian GNU/Linux 11(靶心)、GNOME Shell 3.38.6

9/20 更新

在执行以下命令之前,通过鼠标使T1、T2具有相同的大小/位置:

>>> t2.geometry(t1.geometry())

该命令按预期工作,窗口[继续]具有相同的大小/位置,并且 .geometry() 报告相同的结果。

PS 当 OP 中的示例在没有任何位移的情况下工作时发现异常。当窗口设置完毕后,发出命令就足够了:

>>> t1.geometry('200x200+-10+19')

PPS 如果在其他平台尝试一下会有很大帮助。

更新9/21

找到了一种从另一个侧面说明问题的方法。

以下代码使 T1、T2 窗口在屏幕上的大小/位置相同:

import tkinter as tk
r = tk.Tk()
r.withdraw()
t1, t2 = tk.Toplevel(r), tk.Toplevel(r)
t1.title('T1')
t2.title('T2')


def reset2(w):
    '''Kind of sync window manager and geometry function'''

    def pos(w):
        g = w.geometry()
        return g[g.find('+'):]

    r.update_idletasks()
    p = pos(w)
    r.update_idletasks()
    w.geometry('+-10+19')
    r.update_idletasks()
    w.geometry(p)


reset2(t1)
reset2(t2)
t2.geometry(t1.geometry())
tk.mainloop()

更新9/24

问题简而言之:通过鼠标移动窗口(与通过调用 .geometry() 方法移动)后, .geometry() 方法报告错误的位置(x、y 相差 10 像素)

更新9/25

>>> from tkinter import Tk,Toplevel
>>> r = Tk()
>>> r.withdraw()
''
>>> t1 = Toplevel(r)
>>> t1.title('T1')
''
>>> t2 = Toplevel(r)
>>> t2.title('T2')
''
>>> g1 = t1.winfo_geometry()
>>> x, y = map(int, g1.split('+')[1:])
>>> y -= 37
>>> t2.geometry(f'+{x}+{y}')
''

现在 T1、T2 窗口在屏幕上视觉上无法区分

>>> t1.winfo_geometry(), t2.winfo_geometry()
('200x200+88+152', '200x200+88+152')
>>> 
>>> t1.geometry(), t2.geometry()
('200x200+78+107', '200x200+88+115')

我想我需要更好地理解 .geometry() 是如何工作的

python-3.x tkinter tk-toolkit gnome tkinter-layout
1个回答
0
投票

这是一个解决方法。

class T1(tk.Toplevel):
    def __init__(self):
        super().__init__()
        menu = tk.Menu(self, tearoff=0)
        self.config(menu=menu)
        menu.add_command(label='Sway', command=self.sway)

    def getxy(self, g=None):
        if g is None:
            g = self.geometry()
        return map(int, g.split('+')[1:])

    def sway_needed(self):
        xg, _ = self.getxy()
        xw, _ = self.getxy(self.winfo_geometry())
        return xw != xg

    def sway(self):
        if not self.sway_needed():
            return
        x0, y0 = self.getxy()
        self.geometry(f'+{x0 + 1}+{y0}')
        self.update_idletasks()
        self.geometry(f'+{x0 - 1}+{y0}')
        self.geometry(f'+{x0}+{y0}')
        self.update_idletasks()

用鼠标移动T1窗口后(到任意位置):

>>> t1 = T1()
>>> t1.geometry()
'200x200+776+535'

报告的位置是+776+535,但t1在屏幕上的实际位置是+786+545。调用“Sway”菜单项后,窗口明显移动,实际位置 (+776+535) 和报告的位置变得相同(由 screenruler 验证)

sway_needed()方法用于检测报告位置与实际位置不匹配。 sway() 方法——希望“修复”这个问题

我最初的目标是保存Toplevel Windows 配置。因为它是按需完成的,所以我可以调用 sway().sway() 不影响窗口几何形状。我测试了 sway().after()

安排
© www.soinside.com 2019 - 2024. All rights reserved.