Python 我在Tkinter GUI控制方面遇到问题
我有一个带有各种控件的程序,一个实时网络摄像头提要和一个基于网络摄像头数据的matplotlib图。我希望所有控件都位于左列,而网络摄像头和matplotlib图位于右列 尝试使用.grid()方法、画布和框架等都不起作用-python脚本无法执行并无限期挂起 如何做到这一点 最低工作示例:Python 我在Tkinter GUI控制方面遇到问题,python,tkinter,Python,Tkinter,我有一个带有各种控件的程序,一个实时网络摄像头提要和一个基于网络摄像头数据的matplotlib图。我希望所有控件都位于左列,而网络摄像头和matplotlib图位于右列 尝试使用.grid()方法、画布和框架等都不起作用-python脚本无法执行并无限期挂起 如何做到这一点 最低工作示例: import Tkinter as tk import cv2 from PIL import Image, ImageTk import numpy as np import matplotlib m
import Tkinter as tk
import cv2
from PIL import Image, ImageTk
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
root = tk.Tk()
root.bind('<Escape>', lambda e: root.quit())
lmain = tk.Label(root)
lmain.pack()
class Controller(tk.Frame):
def __init__(self, parent=root, camera_index=0):
self.camera_index = 0
frame = tk.Frame.__init__(self, parent,relief=tk.GROOVE,width=100,height=100,bd=1)
self.pack()
self.parent = parent
self.var = tk.IntVar()
self.parent.title('Laser Beam Profiler')
labelframe = tk.LabelFrame(parent, text="This is a LabelFrame")
labelframe.pack(fill="both", expand="yes") #.grid(row=0, column=0)
self.plot = tk.Button(labelframe, text = "Plot", command = self.refresh_plot)
self.plot.pack()
self.exit = tk.Button(labelframe, text = "Exit", command = self.close_window, compound = tk.BOTTOM)
self.exit.pack()
self.init_camera()
self.show_frame() #initialise camera
self.make_fig()
def make_fig(self):
self.fig = Figure(figsize=(4,4), dpi=100)
self.ax = self.fig.add_subplot(111)
canvas = FigureCanvasTkAgg(self.fig, self)
canvas.show()
canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
toolbar = NavigationToolbar2TkAgg(canvas, self)
toolbar.update()
canvas._tkcanvas.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
def refresh_plot(self):
self.ax.plot(self.img[0])
self.fig.canvas.draw()
self.ax.clear()
print 'updated plot'
def init_camera(self):
width, height = 400, 300
self.cap = cv2.VideoCapture(self.camera_index)
if not self.cap:
raise Exception("Camera not accessible")
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
def show_frame(self):
_, frame = self.cap.read()
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
cv2.putText(cv2image,"Laser Beam profiler", (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255))
dim = np.shape(cv2image)
img = Image.fromarray(cv2image)
imgtk = ImageTk.PhotoImage(image=img)
lmain.imgtk = imgtk
lmain.configure(image=imgtk)
lmain.after(10, self.show_frame)
self.img = frame
def close_window(self):
self.parent.quit()
self.parent.destroy()
Controller().mainloop()
将Tkinter作为tk导入
进口cv2
从PIL导入图像,ImageTk
将numpy作为np导入
导入matplotlib
matplotlib.use('TkAgg')
从matplotlib.backends.backend_tkagg导入图CAVASTKAGG,导航工具栏2TKAGG
将matplotlib.pyplot作为plt导入
从matplotlib.figure导入图形
root=tk.tk()
root.bind(“”,lambda e:root.quit())
lmain=tk.标签(根)
l主要包装
类控制器(tk.Frame):
def uu init uu(self,parent=root,camera_index=0):
self.camera_索引=0
框架=tk.frame.\uuuuu初始(自、父、浮雕=tk.GROOVE,宽度=100,高度=100,bd=1)
self.pack()
self.parent=parent
self.var=tk.IntVar()
self.parent.title(“激光束轮廓仪”)
labelframe=tk.labelframe(父级,text=“这是一个labelframe”)
labelframe.pack(fill=“both”,expand=“yes”)#.grid(行=0,列=0)
self.plot=tk.Button(labelframe,text=“plot”,command=self.refresh\u plot)
self.plot.pack()
self.exit=tk.按钮(labelframe,text=“exit”,command=self.close\u窗口,composite=tk.BOTTOM)
self.exit.pack()
self.init_摄影机()
self.show_frame()#初始化摄像头
self.make_fig()
def制造图(自身):
self.fig=图(figsize=(4,4),dpi=100)
self.ax=self.fig.add_子批次(111)
画布=图CAVASTKAGG(self.fig,self)
canvas.show()
canvas.get_tk_widget().pack(side=tk.BOTTOM,fill=tk.BOTH,expand=True)
工具栏=导航工具栏2TKAGG(画布,自我)
toolbar.update()
canvas.\u tkcanvas.pack(side=tk.BOTTOM,fill=tk.BOTTOM,expand=True)
def刷新图(自):
self.ax.plot(self.img[0])
self.fig.canvas.draw()
self.ax.clear()
打印“更新的绘图”
def初始摄像头(自身):
宽度,高度=400300
self.cap=cv2.VideoCapture(self.camera\u索引)
如果不是self.cap:
引发异常(“摄影机不可访问”)
自盖套件(cv2.cap\U PROP\U FRAME\U WITH,WITH)
自盖套件(cv2.cap\U支架\U框架高度,高度)
def显示_帧(自身):
_,frame=self.cap.read()
cv2image=cv2.CVT颜色(帧,cv2.COLOR_BGR2RGBA)
cv2.putText(cv2image,“激光束轮廓仪”(50,50),cv2.FONT_HERSHEY_SIMPLEX,1,(255255))
尺寸=np.形状(cv2image)
img=Image.fromarray(cv2image)
imgtk=ImageTk.PhotoImage(image=img)
lmain.imgtk=imgtk
lmain.configure(image=imgtk)
主后(10,自我展示画面)
self.img=帧
def关闭_窗口(自):
self.parent.quit()
self.parent.destroy()
控制器().mainloop()
对于最简单的工作示例,我尝试在左侧获取“绘图”和“退出”按钮,并在右侧获取带有matplotlib图的网络摄像头视图。目前,它只是将小部件放在一个长长的列中,从屏幕上溢出。行
labelframe = tk.LabelFrame(parent, text="This is a LabelFrame")
可能应该有self
而不是parent
。此后
labelframe.pack(fill="both", expand="yes", tk.LEFT)
应该有用。由于控制器和labelframe具有相同的父对象,并且首先调用了控制器的pack
方法,因此它对labelframe可能出现的位置进行了限制
在Controller.\uuuu init\uuuuu()
中有一个对self.pack()
的调用,在一个有点不寻常的地方,它通常在小部件实例化后被调用,即
c = Controller(root)
c.pack()
root.mainloop()
虽然我同意应该移动
pack
语句,但移动它不会产生任何效果。感谢您的帮助,但它仍然无法解决所描述的问题。@BryanOakley在本例中,它确实产生了我在测试代码时观察到的效果。我的回答仍然是错误的,因为我错过了labelframe
的父对象。我想说的是,移动pack
不会对无限期挂起的gui产生任何影响。移动它肯定会影响视觉效果。在我的回答中解释了修改后,我测试了这段代码,我能够从我的网络摄像头看到视频输入,即没有挂起。如果这个python脚本只是挂起,那么最好验证视频源是否工作。