如何实时更新tkinter标签文本

3

我有一个应用程序,可以获取您的光标所在像素的CSS3颜色,并且我想使用Tkinter在一个小窗口中显示文本。以下是我的代码中Tkinter的部分:

import pyautogui, PIL
import tkinter as tk

def cursorpixel():
    x,y = pyautogui.position()
    pixel = (x,y,x+1,y+1)
    return pixel

def grabColor(square, max_colors=256):
    img=PIL.ImageGrab.grab(square)
    color = img.getcolors(max_colors)
    return color

def main():
    root=tk.Tk()
    root.minsize(150, 50)
    color = tk.Label(root,
                     text= grabColor(cursorpixel()),
                     fg = "black",
                     font = "Arial").pack()
    root.mainloop()

while __name__ == "__main__":
    main()

这个程序已经按照我的预期运行,但它不能在每次光标移动时更新标签文本。它只在应用程序启动时执行一次,并且标签文本保持不变。我应该怎么做才能让标签文本随着光标的移动而更新?我的python版本是3.7

谢谢


您的代码目前无法运行,请包含您的 grabColor() 函数。 - DapperDuck
该函数已被添加。 - Logan
谢谢@Logan!请同时包含您的导入语句。 - DapperDuck
刚刚添加,感谢你的帮助! - Logan
3个回答

3

将变量赋值给text参数并不能帮助,因为即使变量的值发生了改变,标签中也不会反映出来。这是我的解决方案之一(这只是众多可能方法中的一个)

import pyautogui, PIL
import tkinter as tk
from threading import Thread

def cursorpixel():
    x,y = pyautogui.position()
    pixel = (x,y,x+1,y+1)
    grabColor(pixel)

def grabColor(square, max_colors=256):
    global color_label,root
    img=PIL.ImageGrab.grab(square)
    color = img.getcolors(max_colors)
    color_label.config(text=color)

def refresh():
    while True:
        cursorpixel()

def main():
    global color_label,root
    root=tk.Tk()
    root.minsize(150, 50)
    color_label = tk.Label(root,
                     fg = "black",
                     font = "Arial")
    color_label.pack()
    Thread(target=refresh).start()
    root.mainloop()

if __name__ == "__main__":
    main()

注意事项

  • 我使用了多线程,创建了一个名为refresh()的函数,它会在一个无限循环中触发cursorpixel()
  • 我从cursorpixel()函数中调用了带有pixel参数的grabColor()函数。
  • 我使用了color_label.config()方法来更改标签中的文本,您也可以使用color_label ['text']或者将var=StringVar()赋值给标签,然后在其上使用var.set()
  • 我不确定将__name__='__main__'放入while循环中是否是一个好选择,因为这样做将无法关闭窗口,而且每次尝试这样做时都会弹出新窗口。

如果这段代码被扩展了,多线程还能正常工作吗? - Delrius Euphoria
@CoolCloud 根据我的知识,我认为它应该可以,如果您有任何具体情况,请告诉我,我很乐意学习。 - astqx
@CoolCloud 不一定,因为tkinter是单线程的。但是使用tk.StringVar()并跟踪它对我来说似乎很稳定。 - Thingamabobs
我在一些地方看到过这个问题,就像@martineau所说的“多线程不能与Tkinter对象交互。在Tkinter应用程序中安全地进行多线程的好方法是使用队列对象来通信(传递数据)从辅助线程到主线程。通常使用self.after()来安排定期检索其他线程正在生成的数据。” - Delrius Euphoria
1
@CoolCloud 如果他们有多个辅助线程需要处理,那么他们可能需要进行一些优化。但如果只有这一个线程,我认为应该没有问题。 - astqx

3

答案

我将.after命令添加到grabColor()函数中,并将cursorpixelgrabColor()函数组合在一起。 我使用.config来更新颜色。以下是代码:

import pyautogui, PIL
from tkinter import *

root=Tk()
root.minsize(150, 50)
colortext = Label(root)
colortext.pack()

def grabColor():
    x,y = pyautogui.position()
    pixel = (x,y,x+1,y+1)
    img=PIL.ImageGrab.grab(bbox=pixel)
    color = img.getcolors()
    colortext.config(text=str(color))
    root.after(100, grabColor)

grabColor()

root.mainloop()

来源/其他资源
如何使用Tkinter创建自动更新GUI?


0

您可以使用after()定期获取颜色:

import tkinter as tk
from PIL import ImageGrab

def grab_color(label):
    x, y = label.winfo_pointerxy()
    color = ImageGrab.grab((x, y, x+1, y+1)).getpixel((0, 0))
    label.config(text=str(color))
    label.after(100, grab_color, label)

def main():
    root = tk.Tk()
    color_label = tk.Label(root, width=20)
    color_label.pack(padx=10, pady=10)
    grab_color(color_label)
    root.mainloop()

if __name__ == "__main__":
    main()

请注意,使用winfo_pointerxy()而不是pyautogui.position()来减少对外部模块的依赖。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接