Python 我在Tkinter GUI控制方面遇到问题

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

我有一个带有各种控件的程序,一个实时网络摄像头提要和一个基于网络摄像头数据的matplotlib图。我希望所有控件都位于左列,而网络摄像头和matplotlib图位于右列

尝试使用.grid()方法、画布和框架等都不起作用-python脚本无法执行并无限期挂起

如何做到这一点

最低工作示例:

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脚本只是挂起,那么最好验证视频源是否工作。