如何解决如何使子Tkinter对象触发父窗口小部件中的更改
编辑:由于下面@jasonharper的评论,我可以问一个更明智的问题:
我有一个主应用程序,还有一个单独的模块snipping_tool.py
,该模块处理创建带有窗口截图或选择图像文件选项的新窗口。我希望snipping_tool.py
向主应用提供图像,但是目前我试图检索图像太早(甚至在snipping_tool
窗口打开之前)。
在尝试分配MyNewObject.selected_image
之前,如何等待用户选择或抓取图像?我应该使用binding
还是某些事件处理程序? (我对两者的经验都有限)。还是有更简单的方法?
简化的主应用程序:
import tkinter as tk
import snipping_tool
class MinCodeEx:
def __init__(self,master):
self.master = master
self.ButtonA = tk.Button(width=60,height=40,command = lambda: self.UpdateImg(master))
self.ButtonA.pack()
def UpdateImg(self,master):
newDialog = snipping_tool.AcquireImage(self.master)
# self.ButtonA['image'] = newDialog.image_selected
#if newDialog.image_selected:
self.ButtonA.config(image=newDialog.image_selected)
print(newDialog.image_selected)
def main():
root = tk.Tk()
MinCodeEx(root)
root.mainloop()
if __name__ == '__main__':
main()
snipping_tool.py
返回 None 而不是图像文件,因为我尝试过早检索selected_image
。
import tkinter as tk
from PIL import ImageGrab,ImageTk,Image
import cv2
import numpy as np
from tkinter import filedialog
class ScreenSnip(tk.Toplevel):
def __init__(self,master):
super().__init__(master)
self.image = None
def get_snip(self):
self.configure(cursor='cross')
self.attributes('-fullscreen',True)
self.attributes('-alpha',0.4)
self.canvas = tk.Canvas(self,bg='dark gray')
self.canvas.pack(fill='both',expand=True)
self.begin_x = 0
self.begin_y = 0
self.end_x = 0
self.end_y = 0
self.click_drag = False
self.canvas.create_rectangle(0,outline='#0052d6',width=2,fill='white',tags='snip_rect')
self.canvas.bind('<ButtonPress-1>',self.mousePressEvent)
self.canvas.bind('<B1-Motion>',self.mouseMoveEvent)
self.canvas.bind('<ButtonRelease-1>',self.mouseReleaseEvent)
print('Capture the screen...')
def mousePressEvent(self,event):
self.begin_x = event.x
self.begin_y = event.y
print(self.begin_x,self.begin_y)
def mouseMoveEvent(self,event):
self.click_drag = True
self.end_x = event.x
self.cur_y = event.y
width = self.end_x - self.begin_x
height = abs(width * 2/3)
if self.cur_y < self.begin_y:
height *= -1
self.end_y = self.begin_y + height
self.canvas.coords('snip_rect',self.begin_x,self.begin_y,self.end_x,self.end_y)
def mouseReleaseEvent(self,event):
self.destroy()
self.master.update_idletasks()
self.master.after(100) # give time for screen to be refreshed so as not to see the blue box on the screenshot
if not self.click_drag: # if the user just clicks,instead of clicking and dragging
self.begin_x -= 300
self.begin_y += 200
self.end_x = self.begin_x + 600
self.end_y = self.begin_y - 400
x1 = min(self.begin_x,self.end_x)
y1 = min(self.begin_y,self.end_y)
x2 = max(self.begin_x,self.end_x)
y2 = max(self.begin_y,self.end_y)
self.img = ImageGrab.grab(bbox=(x1,y1,x2,y2))
self.image = ImageTk.PhotoImage(self.img)
#self.img = cv2.cvtColor(np.array(img),cv2.COLOR_BGR2RGB)
#cv2.imshow('Captured Image',self.img)
#cv2.waitKey(0)
font1 = ("arial",18,"bold")
class AcquireImage:
def __init__(self,master):
self.master = master
self.nWin = tk.Toplevel(master)
self.fontA = ("arial",20,"bold")
self.frame = tk.Frame(self.nWin,bg="#1B2631")
self.frame.pack(fill="both",expand=True)
self.button1 = tk.Button(self.frame,text="Select Image File",padx=10,pady=10,bg="#d9a193",font = self.fontA,command =lambda: self.show_dialogs(1))
self.button1.grid(row=0,column=0,sticky="nsew")#,pady=10)
self.button2 = tk.Button(self.frame,text="Get Screen Snip",command=lambda: self.show_dialogs(2))
self.button2.grid(row=0,column=1,pady=10)
self.image_selected = None
def show_dialogs(self,method): ################### THIS IS WHERE THE IMAGE IS SELECTED ###########
if method == 1:
ret = filedialog.askopenfilename()
if ret:
self.image_selected = ImageTk.PhotoImage(file = ret)
self.nWin.destroy()
elif method == 2:
newWin = ScreenSnip(self.nWin)
newWin.get_snip()
ret = newWin.image
if ret:
self.image_selected = ret
def main():
root = tk.Tk()
AcquireImage(root)
root.mainloop()
if __name__ == '__main__':
main()
解决方法
@jasonharper是正确的。此解决方案来自他的评论。
在创建AcquireImage
的实例时,我还传递了ButtonA
作为参数,以便可以修改其图像。在AcquireImage
中,我首先获得一个新图像(通过剪裁或使用文件资源管理器),然后为避免垃圾回收立即删除它,我将其分配给ButtonA.img
进行保存。 (我首先在主程序中创建ButtonA的.img
部分)。有了图片后,就可以分配它了。
我可能还可以通过创建一个函数来解决此问题 在主程序中更改任何小部件的图像 传递给它作为参数。然后,我可以将此功能传递给 以
AcquireImage
为参数的ButtonA
实例。它可能 在主程序中看起来像这样:def callback(i_file): ButtonA['image'] = i_file newDialog = snipping_tool.AcquireImage(self.master,self.callback)
后来我 将用AcquireImage
初始化/定义self.some_function
作为第二个参数(仅次于master),我 可以将图像文件传递给它。至少那是我可能的方式 已经做到了。
这是我实际解决的方式:
主要应用
import tkinter as tk
import snipping_tool
waitingforImage = True
class MinCodeEx:
global waitingforImage
def __init__(self,master):
self.master = master
self.ButtonA = tk.Button(width=60,height=40,command = lambda: self.UpdateImg())
self.ButtonA.pack()
self.ButtonA.img = None
def UpdateImg(self):
newDialog = snipping_tool.AcquireImage(self.master,self.ButtonA)
def main():
root = tk.Tk()
MinCodeEx(root)
root.mainloop()
if __name__ == '__main__':
main()
snipping_tool.py
import tkinter as tk
from PIL import ImageGrab,ImageTk,Image
from tkinter import filedialog
class ScreenSnip(tk.Toplevel):
def __init__(self,master,changeThis):
super().__init__(master)
self.image = None
self.master = master
self.changeThis = changeThis
def get_snip(self):
self.configure(cursor='cross')
self.attributes('-fullscreen',True)
self.attributes('-alpha',0.4)
print("attempting to create tk.Canvas for get_snip")
self.canvas = tk.Canvas(self,bg='dark gray')
self.canvas.pack(fill='both',expand=True)
self.begin_x = 0
self.begin_y = 0
self.end_x = 0
self.end_y = 0
self.click_drag = False
self.canvas.create_rectangle(0,outline='#0052d6',width=2,fill='white',tags='snip_rect')
self.canvas.bind('<ButtonPress-1>',self.mousePressEvent)
self.canvas.bind('<B1-Motion>',self.mouseMoveEvent)
self.canvas.bind('<ButtonRelease-1>',self.mouseReleaseEvent)
print('Capture the screen...')
def mousePressEvent(self,event):
self.begin_x = event.x
self.begin_y = event.y
print(self.begin_x,self.begin_y)
def mouseMoveEvent(self,event):
self.click_drag = True
self.end_x = event.x
self.cur_y = event.y
width = self.end_x - self.begin_x
height = abs(width * 2/3)
if self.cur_y < self.begin_y:
height *= -1
self.end_y = self.begin_y + height
self.canvas.coords('snip_rect',self.begin_x,self.begin_y,self.end_x,self.end_y)
def mouseReleaseEvent(self,event):
self.destroy()
self.master.update_idletasks()
self.master.after(100) # give time for screen to be refreshed so as not to see the blue box on the screenshot
if not self.click_drag: # if the user just clicks,instead of clicking and dragging
self.begin_x -= 300
self.begin_y += 200
self.end_x = self.begin_x + 600
self.end_y = self.begin_y - 400
x1 = min(self.begin_x,self.end_x)
y1 = min(self.begin_y,self.end_y)
x2 = max(self.begin_x,self.end_x)
y2 = max(self.begin_y,self.end_y)
self.img = ImageGrab.grab(bbox=(x1,y1,x2,y2))
print("getting image grab")
self.changeThis.img = ImageTk.PhotoImage(self.img)
self.changeThis['image'] = self.changeThis.img
font1 = ("arial",18,"bold")
class AcquireImage:
def __init__(self,changeThis):
self.master = master
self.changeThis = changeThis
self.nWin = tk.Toplevel(master)
self.fontA = ("arial",20,"bold")
self.frame = tk.Frame(self.nWin,bg="#1B2631")
self.frame.pack(fill="both",expand=True)
self.button1 = tk.Button(self.frame,text="Select Image File",padx=10,pady=10,bg="#d9a193",font = self.fontA,command =lambda: self.show_dialogs(1))
self.button1.grid(row=0,column=0,sticky="nsew")#,pady=10)
self.button2 = tk.Button(self.frame,text="Get Screen Snip",command=lambda: self.show_dialogs(2))
self.button2.grid(row=0,column=1,pady=10)
self.image_selected = None
def show_dialogs(self,method):
if method == 1:
ret = filedialog.askopenfilename() #filedialog.askopenfilename(initialdir='/home/user/images/')
self.changeThis.img = ImageTk.PhotoImage(file = ret)
self.changeThis['image'] = self.changeThis.img
elif method == 2:
print("attempting ScreenSnip")
newWin = ScreenSnip(self.master,self.changeThis)
newWin.get_snip()
self.nWin.destroy()
def main():
root = tk.Tk()
bt = tk.Button(root,width = 20,height = 20)
bt.pack()
ScreenSnip(root,bt)
#AcquireImage(root,bt)
root.mainloop()
if __name__ == '__main__':
main()
我仍然需要修复一个不相关的问题-该按钮不适合我选择或抓取的图像的大小。它总是最终变成一个小正方形。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。