Reputation: 1062
I have a programme with various controls, a live webcam feed and a matplotlib figure based on the webcam data. I would like all the controls to be located in a left column, and the webcam and matplotlib figure to be located in a right column.
Attempts to use .grid() methods, canvases and frames etc don't work - the python script just fails to execute and hangs indefinitely.
How can this be achieved?
Minimum working example:
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()
For the minimum working example I am trying to get the 'plot' and 'exit' buttons on the left hand side, and the webcam view with the matplotlib figure on the right. Currently it just places the widgets in a long column that spills off the screen.
Upvotes: 1
Views: 176
Reputation: 6214
The line
labelframe = tk.LabelFrame(parent, text="This is a LabelFrame")
probably should have self
instead of parent
. After this
labelframe.pack(fill="both", expand="yes", tk.LEFT)
should work. Since the Controller and the labelframe had the same parent and pack
method for the Controller was called first, it placed restrictions where the labelframe could appear.
In Controller.__init__()
there is a call to self.pack()
in a little bit unusual place, it is usually left to be called after the widget has been instantiated i.e.
c = Controller(root)
c.pack()
root.mainloop()
Upvotes: 1