我在使用Tkinter GUI控件时遇到问题

时间:2016-06-29 10:53:03

标签: python tkinter

我有一个程序,包含各种控件,实时网络摄像头和基于网络摄像头数据的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()

对于最小工作示例,我试图在左侧获得“情节”和“退出”按钮,并在右侧显示带有matplotlib图的网络摄像头视图。目前,它只是将小部件放在一个溢出屏幕的长列中。

1 个答案:

答案 0 :(得分:1)

该行

labelframe = tk.LabelFrame(parent, text="This is a LabelFrame")

可能应该self而不是parent。在此之后

labelframe.pack(fill="both", expand="yes", tk.LEFT)

应该有效。由于Controller和labelframe具有相同的父级,并且首先调用了Controller的pack方法,因此它会在labelframe可能出现的地方设置限制。

Controller.__init__()中,在一个不寻常的地方有一个self.pack()的调用,通常在实例化小部件之后调用它,即

c = Controller(root)
c.pack()
root.mainloop()