I have two GUIs and I want these guis to be able communicate together. I used Matlab in the past and in Matlab I was using addlistener and basically communicate between multiple guis. I am new to python and I want when I am clicking on the show button on my second gui it update the axes on my first gui. Basically, plot the image on the other gui based on the path I choose on another.
Here is the image for better understanding
Here is the code:
from tkinter import *
from PIL import Image, ImageTk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import
FigureCanvasTkAgg
import PySimpleGUI as sg
import tkinter.filedialog as fdialog
from natsort import natsorted
import os
import cv2
class MyCanvas(Canvas):
def __init__(self, parent=None, img=None, *parms, **kparms):
Canvas.__init__(self, parent, *parms, **kparms)
self._width = 20;
self._height = 10;
self._starting_drag_position = ()
self.config(width=self._width, height=self._height, bg='white')
self._draw_some_example_objects()
self.pack(fill=BOTH, expand=YES)
def _draw_some_example_objects(self):
self.fig = Figure()
gs = self.fig.add_gridspec(5, 2)
self.axis= self.fig.add_subplot(gs[0:4, 0])
self.canvas = FigureCanvasTkAgg(self.fig, master=self)
self.canvas.get_tk_widget().pack(side="top", fill='both', expand=True)
colors = dict(outline="black")
class MyGUI(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
self.title("Drag canvas with mouse")
self.geometry("700x700")
"""For some reason menu should be added here"""
self.menuBar = Menu(master=self)
self.filemenu = Menu(self.menuBar, tearoff=0)
self.filemenu.add_command(label="listview!", command=self.list)
self.menuBar.add_cascade(label="File", menu=self.filemenu)
self.config(menu=self.menuBar)
self._addWidgets()
def _addWidgets(self):
my_canvas = MyCanvas(self)
def list(self):
listView(self)
def listView(self):
sg.ChangeLookAndFeel('GreenTan')
dir = fdialog.askdirectory()
filesList = os.listdir(dir)
filesList = natsorted(filesList)
layout = [
[sg.Listbox(values=(filesList), size=(60, 30), key='_IN_')],
[sg.Button('Show')]
]
window = sg.Window('Everything bagel', default_element_size=(40, 1), grab_anywhere=False).Layout(layout)
while True:
event, values = window.Read()
if event is None or event == 'Exit':
break
print(dir + values.get('_IN_')[0])
if __name__ == '__main__':
MyGUI().mainloop()`
Take a look at this demo program.
Drop your code into the section where it says:
#------------------------ PASTE YOUR MATPLOTLIB CODE HERE ----------------------
Make sure your drawing is in the variable 'fig'. It will create a window with GUI options and your Matplotlib plot embedded in it.
Related
I followed a few tutorials and I am trying to implement a clean object oriented code for python gui. The idea of my project is opening an image and drawing circles on it with mouse click.
There are 2 issues:
1)
In the code below, the canvas does not render the image.the image should be taken from the user
In java there is a repaint function that is called by VM so that the contents of the frame can be updated. I couldn't find something in python (No, I am not willing to try adding timer function to redraw every second.)
2)
Besides HELLO is not printed even I press f key. The keylistener is also not working
I have done GUI with Java before but Python code looks very dirty comparing Java.
I would be grateful if you can help.
from tkinter import *
from PIL import Image, ImageTk
from tkinter import Tk, Canvas, Frame, BOTH
from tkinter import filedialog
class Example(Frame):
def __init__(self, container):
super().__init__()
self.container = container
self.canvas = None
self.initUI()
def initUI(self):
fname=filedialog.askopenfilename(title='"pen')
self.canvas = Canvas(self.container)
self.canvas.pack(anchor='nw', fill='both', expand=1)
self.canvas.focus_set()
self.canvas.bind("<ButtonRelease-1>", self.mouseReleased)
self.canvas.bind("<Key>", self.pressedkey)
image = Image.open(fname)
image = image.resize((400, 400))
image = ImageTk.PhotoImage(image)
image_id=self.canvas.create_image(0, 0, image=image, anchor='nw')
def mouseReleased(self, event):
self.canvas.create_oval(event.x-10, event.y-10, event.x+10, event.y+10, width=2, fill='blue')
def pressedkey(self,event):
pressedkey=str(repr(event.char))
print(pressedkey,type(pressedkey))
if pressedkey.__eq__("f"):
print("HELLO")
def main():
root = Tk()
ex = Example(root)
root.geometry("400x250+300+300")
root.mainloop()
if __name__ == '__main__':
main()
I wrote a code that allows to click inside an entry widget and activate a function that returns the mouse coordinates if clicked on a figure. The problem is that I want to click somewhere else than the figure or entry widget to deactivate the function but I don't know how to do that.
What I tried so far is binding (with bind) a callback function that deactivates the select_marker function to master (what obviously makes no sense) or to a certain Frame (didn't help). I couldn't find any solution by browsing SO or the web.
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
class Application():
def __init__(self, master):
self.master = master
master.iconify
self.entry_frame = Tk.Frame(master)
self.entry_frame.pack(side=Tk.TOP, fill=Tk.BOTH, expand=0)
self.m1_label = Tk.Label(self.entry_frame, text='Mouse Coordinates: ')
self.m1_label.pack(side=Tk.LEFT)
self.m1_entry = Tk.Entry(self.entry_frame, width=10)
self.m1_entry.pack(side=Tk.LEFT)
self.m1_entry.bind('<Button-1>', lambda e:self.callback(1))
self.image_frame = Tk.Frame(master)
self.image_frame.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
self.image_frame.bind('<Button-1>', lambda e:self.callback(0)) # something like this
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
self.ax.set_aspect('equal')
self.canvas = FigureCanvasTkAgg(self.fig, self.image_frame)
self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
self.widget_active = 0
self.fig.canvas.mpl_connect('button_press_event', self.select_marker)
def callback(self, state):
self.widget_active = state
print(state)
def select_marker(self, event):
if self.widget_active == 1:
if event.button == 1:
x = np.round(event.xdata,2)
y = np.round(event.ydata,2)
print(x,y)
self.m1_entry.delete(0,'end')
self.m1_entry.insert(0,(str(x)+', '+str(y)))
else:
pass
if self.widget_active == 0:
pass
root = Tk.Tk()
Application(root)
root.mainloop()
I would really appreciate if someone knows a way to get a callback if clicked somewhere except the entry widget or the figure. Thanks a lot!
I have written a piece of code where I have a simple GUI with an canvas. On this canvas I draw a Matplot. The Matplot is updated every second with data from an SQ Lite DB which I fill with some fake Sensor information (just for testing at the moment).
My Problem was that the redrawing of the canvas causes my window/gui to lag every second. I even tried to update the plot in another thread. But even there I get an lag.
With my newest Code i got most of my things working. Threading helps to prevent my GUI/Window from freezing while the Canvas is updated.
The last thing I miss is to make it Thread safe.
This is the message I get:
RuntimeError: main thread is not in main loop
Here is my newest working code with threading:
from tkinter import *
import random
from random import randint
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import time
import threading
from datetime import datetime
continuePlotting = False
def change_state():
global continuePlotting
if continuePlotting == True:
continuePlotting = False
else:
continuePlotting = True
def data_points():
yList = []
for x in range (0, 20):
yList.append(random.randint(0, 100))
return yList
def app():
# initialise a window and creating the GUI
root = Tk()
root.config(background='white')
root.geometry("1000x700")
lab = Label(root, text="Live Plotting", bg = 'white').pack()
fig = Figure()
ax = fig.add_subplot(111)
ax.set_ylim(0,100)
ax.set_xlim(1,30)
ax.grid()
graph = FigureCanvasTkAgg(fig, master=root)
graph.get_tk_widget().pack(side="top",fill='both',expand=True)
# Updated the Canvas
def plotter():
while continuePlotting:
ax.cla()
ax.grid()
ax.set_ylim(0,100)
ax.set_xlim(1,20)
dpts = data_points()
ax.plot(range(20), dpts, marker='o', color='orange')
graph.draw()
time.sleep(1)
def gui_handler():
change_state()
threading.Thread(target=plotter).start()
b = Button(root, text="Start/Stop", command=gui_handler, bg="red", fg="white")
b.pack()
root.mainloop()
if __name__ == '__main__':
app()
Here the idea without a thread:
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import sqlite3
from datetime import datetime
from random import randint
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
root.update_idletasks()
f = Figure(figsize=(5,5), dpi=100)
x=1
ax = f.add_subplot(111)
line = ax.plot(x, np.sin(x))
def animate(i):
# Open Database
conn = sqlite3.connect('Sensor_Data.db')
c = conn.cursor()
# Create some fake Sensor Data
NowIs = datetime.now()
Temperature = randint(0, 100)
Humidity = randint(0, 100)
# Add Data to the Database
c = conn.cursor()
# Insert a row of data
c.execute("insert into Sensor_Stream_1 (Date, Temperature, Humidity) values (?, ?, ?)",
(NowIs, Temperature, Humidity))
# Save (commit) the changes
conn.commit()
# Select Data from the Database
c.execute("SELECT Temperature FROM Sensor_Stream_1 LIMIT 10 OFFSET (SELECT COUNT(*) FROM Sensor_Stream_1)-10")
# Gives a list of all temperature values
x = 1
Temperatures = []
for record in c.fetchall():
Temperatures.append(str(x)+','+str(record[0]))
x+=1
# Setting up the Plot with X and Y Values
xList = []
yList = []
for eachLine in Temperatures:
if len(eachLine) > 1:
x, y = eachLine.split(',')
xList.append(int(x))
yList.append(int(y))
ax.clear()
ax.plot(xList, yList)
ax.set_ylim(0,100)
ax.set_xlim(1,10)
ax.grid(b=None, which='major', axis='both', **kwargs)
label = tk.Label(root,text="Temperature / Humidity").pack(side="top", fill="both", expand=True)
canvas = FigureCanvasTkAgg(f, master=root)
canvas.get_tk_widget().pack(side="left", fill="both", expand=True)
root.ani = animation.FuncAnimation(f, animate, interval=1000)
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Here is my DB Schema:
CREATE TABLE `Sensor_Stream_1` (
`Date` TEXT,
`Temperature` INTEGER,
`Humidity` INTEGER
);
Your GUI process must not run in any thread. only the dataacquisition must be threaded.
When needed , the data acquired are transfered to the gui process (or the gui process notified from new data available) . I may need to use a mutex to share data resource between acquisition thread and gui (when copying)
the mainloop will look like :
running = True
while running:
root.update()
if data_available:
copydata_to_gui()
root.quit()
I had the same problem with tkinter and using pypubsub events was my solution.
As comments above suggested, you have to run your calculation in another thread, then send it to the gui thread.
import time
import tkinter as tk
import threading
from pubsub import pub
lock = threading.Lock()
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.label = tk.Label(root, text="Temperature / Humidity")
self.label.pack(side="top", fill="both", expand=True)
def listener(self, plot_data):
with lock:
"""do your plot drawing things here"""
self.label.configure(text=plot_data)
class WorkerThread(threading.Thread):
def __init__(self):
super(WorkerThread, self).__init__()
self.daemon = True # do not keep thread after app exit
self._stop = False
def run(self):
"""calculate your plot data here"""
for i in range(100):
if self._stop:
break
time.sleep(1)
pub.sendMessage('listener', text=str(i))
if __name__ == "__main__":
root = tk.Tk()
root.wm_geometry("320x240+100+100")
main = MainApplication(root)
main.pack(side="top", fill="both", expand=True)
pub.subscribe(main.listener, 'listener')
wt = WorkerThread()
wt.start()
root.mainloop()
This function is called every second, and it is outside the normal refresh.
def start(self,parent):
self.close=False
self.Refresh(parent)
def Refresh(self,parent):
'''your code'''
if(self.close == False):
frame.after( UpdateDelay*1000, self.Refresh, parent)
The function is called alone, and everything that happens inside it does not block the normal operation of the interface.
I've been doing some research on this one issue I've been having with TKinter, which is updating the GUI based on data from other threads. As many have suggested online, I resorted to using the queue polling strategy with the self.root.after() method.
This works pretty well, but I have a problem in which I need to update matplotlib plots embedded in a TKinter GUI, and doing so "deactivates" / draws focus away from / perhaps blocks the other aspects of the GUI. Specifically, if I'm typing something in a TKinter entry and the matplotlib figure updates, the cursor is no longer in the entry and my typing process has been interrupted.
To solve this issue, I figured I'd try to update TKinter in a separate thread altogether. Now, I have seen online many people who claim that TKinter is not thread-safe, but I have also seen others who say it is thread-safe. I went ahead and made an example program, which seems to run pretty well: the cursor can remain in the entry even when the plot updates. But what I'd like to know is, is this program safe? Or is it susceptible to failures, random or predictable? What can I do to have a thread-safe GUI?
Here's my example code:
import Tkinter as tk
import threading
import Queue
import datetime
import math
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.gridspec as gridspec
gui_queue = Queue.Queue()
GUI_THEME_COLOR = 'lightblue'
##################################################
class MainGUI:
def __init__(self, root):
self.root = root
self.root.title('TKinter GUI with Threaded Updates')
self.root.minsize(width=800, height=300)
self.root.config(background=GUI_THEME_COLOR)
self.big_frame = tk.Frame(master=root)
self.big_frame.pack(fill=tk.BOTH, expand=tk.YES, padx=10, pady=10)
self.button1 = tk.Button(master=self.big_frame, text='Button 1', command=self.button1_command)
self.button1.grid(row=0, column=0)
self.entry1 = tk.Entry(master=self.big_frame)
self.entry1.bind('<Return>', self.entry1_event)
self.entry1.grid(row=1, column=0)
def entry1_event(self, event):
self.button1.config(text=str(self.entry1.get()))
self.entry1.delete(0, tk.END)
def button1_command(self):
print 'Button 1 clicked'
class GUIManipulator(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.app = None
self.start_time = datetime.datetime.utcnow()
self.sec_checker = 1
self.num_loops = 0
self.x_list = []
self.y_list = []
def run(self):
print 'Starting GUIManipulator thread...'
while gui_queue.empty(): # Wait here until we receive the MainGUI instance
pass
self.app = gui_queue.get()
while True:
diff_time = (datetime.datetime.utcnow() - self.start_time).total_seconds()
floor_diff_time = math.floor(diff_time)
if floor_diff_time >= self.sec_checker: # Configure button1 text every second
self.app.button1.config(text=str(floor_diff_time))
self.sec_checker += 1
self.plot_figure()
def plot_figure(self):
self.num_loops += 1
self.x_list.append(self.num_loops)
self.y_list.append(math.sin(self.num_loops/5.0))
if self.num_loops == 1:
self.fig1 = Figure(figsize=(12, 6), facecolor=GUI_THEME_COLOR)
self.fig1.suptitle('Figure 1',
fontsize=14,
fontweight='bold')
self.gs = gridspec.GridSpec(2, 2)
self.plot1 = self.fig1.add_subplot(self.gs[:, 0])
self.plot1.set_title('Plot 1')
self.plot1.set_xlabel('x')
self.plot1.set_ylabel('sin(x)', labelpad=-10)
self.plot1.grid(True)
if self.num_loops > 1:
self.plot1.cla()
self.plot1.plot(self.x_list, self.y_list)
if self.num_loops == 1:
self.canvas = FigureCanvasTkAgg(self.fig1, master=self.app.big_frame)
self.canvas.draw()
self.canvas.get_tk_widget().grid(row=2, column=0)
else:
self.canvas.draw()
def main():
root = tk.Tk()
app = MainGUI(root)
gui_queue.put(app)
gui_manipulator_thread = GUIManipulator()
gui_manipulator_thread.daemon = True
gui_manipulator_thread.start()
root.mainloop()
if __name__ == '__main__':
main()
I'm attempting to add a .jpeg image to my GUI while it has several other widgets.
With my code, I can display the image in a separate Tkinter window when I use the following command:
#self.label = Label(image = self.img)
However, whenever I try to add the image to the original Tkinter window, I get the error seen below my code. The way I tried to add it to the original Tkinter window is:
#self.label = Label(frame, image = self.img)
Replicating the error
Oddly enough, when I try to replicate the error in a shorter version of the code (such as directly below), it works. HOWEVER! To replicate the error in the shortened code, you need to create a different error first. Example: Replace text = "Try" with text = "%s" %yikes (because there is no variable yikes it will give you an error). After you change the code back to the EXACT way it was before, it produces the error I've descried below (TclError: image "pyimage__" doesn't exit). At the very bottom, I've included the entire class since I'm having difficulty consistently replicating the issue. I'm using Python 2.7 and Canopy 1.5.5.
Shortened code:
import matplotlib.pyplot as plt
from Tkinter import *
from PIL import ImageTk, Image
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
from tkFileDialog import askopenfilename, askdirectory
class App:
def __init__(self, master):
frame = Frame(master)
self.button_left = Button(frame,text="< Previous Event")
self.button_left.grid(row=1,column=0)
self.button_right = Button(frame,text="Next Event >")
self.button_right.grid(row=1,column=3)
#Creating text for the UI indicating the number of leakage events
w = Label(frame, text="Trying to Recreate error")
w.grid(row=1,column=2)
self.m = Canvas(frame,width=50,height=25)
self.text_id = self.m.create_text(25,12.5, text="Try")
self.m.grid(row=1,column=1)
self.path = "C:\Carbonite\EL_36604.02_231694\EL_36604.02_231694_2015-06-15 10.39.57.jpeg"
self.image = Image.open(self.path)
self.img = ImageTk.PhotoImage(self.image)
#self.label = Label(image = self.img)
self.label = Label(frame,image = self.img)
self.label.image = self.img
self.label.grid(row = 3, column = 0)
frame.grid(row=0,column=0)
root = Tk()
app = App(root)
root.mainloop()
Error I receive in my program when I use the commented out method:
TclError Traceback (most recent call last)
C:\Carbonite\Main_interface_file.py in <module>()
136
137 root = Tk()
--> 138 app = App(root)
139 root.mainloop()
140
C:\Carbonite\Main_interface_file.py in __init__(self, master)
72 self.img = ImageTk.PhotoImage(self.image)
73 #self.label = Label(image = self.img)
---> 74 self.label = Label(frame,image = self.img)
75 self.label.image = self.img
76 self.label.grid(row=3, column = 0)
C:\Users\U10596\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.5.3123.win-x86_64\lib\lib-tk\Tkinter.pyc in __init__(self, master, cnf, **kw)
2585
2586 """
-> 2587 Widget.__init__(self, master, 'label', cnf, kw)
2588
2589 class Listbox(Widget, XView, YView):
C:\Users\U10596\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5.5.3123.win-x86_64\lib\lib-tk\Tkinter.pyc in __init__(self, master, widgetName, cnf, kw, extra)
2084 del cnf[k]
2085 self.tk.call(
-> 2086 (widgetName, self._w) + extra + self._options(cnf))
2087 for k, v in classes:
2088 k.configure(self, v)
TclError: image "pyimage8" doesn't exist
Almost entire Code:
import matplotlib.pyplot as plt
from Tkinter import *
from PIL import ImageTk, Image
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
from images_to_list import images_to_list
from tkFileDialog import askopenfilename, askdirectory
#Creating a class that creates the UI
class App:
def __init__(self, master):
self.event_num = 1
# Create a container
frame = Frame(master)
# Create 2 buttons (changes between leakage events
self.button_left = Button(frame,text="< Previous Event",
command=self.decrease)
self.button_left.grid(row=1,column=0)
self.button_right = Button(frame,text="Next Event >",
command=self.increase)
self.button_right.grid(row=1,column=3)
#Creating text for the UI indicating the number of leakage events
w = Label(frame, text="/ %s " % len(tft))
w.grid(row=1,column=2)
#Display the number of the current event in the series
self.m = Canvas(frame,width=50,height=25)
self.text_id = self.m.create_text(25,12.5, text="%s" % (self.event_num+1))
self.m.grid(row=1,column=1)
#Creating the plot of voltage data
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
self.fig.autofmt_xdate()
import matplotlib.dates as mdates
self.ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')
self.line, = self.ax.plot(tft[self.event_num],tf1[self.event_num],'.')
self.line2, = self.ax.plot(tft[self.event_num],tf2[self.event_num],'.')
self.ax.set_ylim([0,3.5])
self.path = "C:\Carbonite\EL_36604.02_231694\EL_36604.02_231694_2015-06-15 10.39.57.jpeg"
self.image = Image.open(self.path)
self.img = ImageTk.PhotoImage(self.image)
#self.label = Label(image = self.img)
self.label = Label(frame,image = self.img)
self.label.image = self.img
self.label.grid(row=3, column = 0)
self.canvas = FigureCanvasTkAgg(self.fig,master=master)
self.canvas.show()
self.canvas.get_tk_widget().grid(row=1,column=0)
frame.grid(row=0,column=0)
#Creating a textbox to jump to event number
self.textbox = Entry(frame,width=5)
button1 = Button(frame, text='Go', command=self.letsgo) #Linking "Go" button with letsgo function to jump to event number
self.textbox.grid(row=2,column=1)
button1.grid(row=2,column=2)
#function letsgo allows the user to jump to any event in the series
def letsgo(self):
txt = self.textbox.get()
try:
self.event_num = int(txt)
except ValueError:
print "Opps! The number you enter needs to be an integer!"
self.line.set_xdata(tft[self.event_num])
self.line.set_ydata(tf1[self.event_num])
self.line2.set_xdata(tft[self.event_num])
self.line2.set_ydata(tf2[self.event_num])
self.ax.set_xlim([min(tft[self.event_num]),max(tft[self.event_num])])
self.canvas.draw()
self.m.itemconfig(self.text_id, text="%s" % (self.event_num+1))
#function decrease allows the user to use the decrease button
def decrease(self):
if self.event_num == 0: #if statement accounts for if the user tries to see the event previous to the first one
self.event_num = len(tft)-1
else:
self.event_num -= 1
self.line.set_xdata(tft[self.event_num])
self.line.set_ydata(tf1[self.event_num])
self.line2.set_xdata(tft[self.event_num])
self.line2.set_ydata(tf2[self.event_num])
self.ax.set_xlim([min(tft[self.event_num]),max(tft[self.event_num])])
self.canvas.draw()
self.m.itemconfig(self.text_id, text="%s" % (self.event_num+1))
#function increase allows the user to use the increase button
def increase(self):
if self.event_num == len(tft)-1: #if statement accounts for if the user tries to see the event after the last one.
self.event_num = 0
else:
self.event_num += 1
self.line.set_xdata(tft[self.event_num])
self.line.set_ydata(tf1[self.event_num])
self.line2.set_xdata(tft[self.event_num])
self.line2.set_ydata(tf2[self.event_num])
self.ax.set_xlim([min(tft[self.event_num]),max(tft[self.event_num])])
self.canvas.draw()
self.m.itemconfig(self.text_id, text="%s" % (self.event_num+1))
root = Tk()
app = App(root)
root.mainloop()
You need to grid the Frame. When I add
frame.grid()
at the bottom of your __init__ method it works fine. I don't get an error when I run the code you posted, though. It just doesn't display the label. I wonder if this is some platform-dependent behavior. I'm using python 2.7 on Yosemite 10.10.5.
EDIT: I've tried your extended example, and as expected, I don't see the behavior you. I can change the code back and forth. When it's incorrect, I get an error; when it's correct, it runs fine.
The behavior you describe must have something to do with Canopy. The way the python interpreter works, it will compile the script to byte codes every time it runs; it doesn't know anything about what the script used to says.
Can you try running the suspect script from the command line? Also, perhaps you should add the canopy tag to your question.
I don't use Canopy, so I don't think I can help you, but I'm leaving the answer here as background for someone who hopefully can.
Good luck.
I found the issue!!
I used askopenfilename() in the very beginning of my code, which opened an extra Tkinter window. As a result, there were two Tkinter windows open and confused the program.
By sending everything to the first Tk window that was created (and removing the second), it resolved the issue.