I wrote a script in python 3.4 where I'm making use of the tkinter module to build the GUI and pandas/matplotlib to visualise some data. The visualisation is being produced in a new window through the use of a button in the main window. The problem is that when I close the window that contains the graph (produced by pandas/matplot) the main window widgets are completely unresponsive. Furthermore, when I try to close the main window (through the 'X' button) I get a Fatal Python error: PyEval_RestoreThread: NULL tstate, which I don't get if I close the window without producing the graphs.
In simple words: the rest of the application behaves as it should if I never produce the graphs and becomes completely unresponsive if I do.
Below are the code segments of the caller of the plotting method in the main window and the method itself where the use of pandas and matplot is clearly shown.
Caller:
button_view_browsers = tk.Button(window, text="Display graph", command=lambda: self.threaded_browser_hist(doc))
button_view_browsers.grid(row=2, column=1, sticky=W+E+N+S, columnspan=3)
Visualisation method:
def display_browser_hist(self, data):
ser = Series(data.viewer_browser())
ser.value_counts().plot(kind='bar')
matplotlib.pyplot.show()
def threaded_browser_hist(self, doc):
Thread(target=self.display_browser_hist(doc)).start()
Any help would be greatly appreciated.
EDIT: Just to be sure I'm also including the modules I'm using and how I'm importing them:
from pandas import Series
import matplotlib
import tkinter as tk
from tkinter import W, E, N, S
Related
Is it possible to have two instances of tkinter ?
import tkinter as tk
import tkinter as sk
root = tk.Tk()
root2 = sk.Tk()
....some window with tk
....some window with sk
root.mainloop()
root2.mainloop()
then have a Toplevel() in both instances.
You can, but the way it works likely won't be like what you expect. Importing it twice isn't the problem (but neither is it the solution). No matter how you import it or how often you import it, creating more than one instance of Tk is the problem. Each instance is backed by a separate internal interpreter. Images and variables and widgets created in one won't exist in the other.
If you need more than one window, it's usually best if second and subsequent windows are instances of Toplevel.
By creating 2 instances or tkinter I can close one instance and all top Levels of that instance. Leaving the second Instance open and running with it's Toplevel instances. This is useful in the sense where I use it for a User preference file. Where it checks for a userfile database for keeping track of variables. I use a csv file to save user variable using pandas. This in turn keeps all the form information in my app safe from being erased after closing the application or accidentally closing the window. Adding AtExit saves the info closing the addinfo window and continues to run the main application. That was my reasoning for having asked the question. I have since found that using multiple Toplevel(s) is a better choice as it will also produce the same result. So my menu items all have a separate instance definition and can be closed in the same manner ,making error checks with each closed window.
from tkinter import Tk,Label,Entry,Button,Toplevel
root=Tk()
def about():
ab=Toplevel()
# About stuff for this window
ab.mainloop()
def info():
inf=Toplevel()
# Information Stuff for this window.
inf.mainloop()
def getUserInfo():
# User info using pandas
getUserInfo.mainloop()
root.mainloop()
My program iterates through a list of values and creates a new frame with relevant information. I want to add a button to refresh the values in just one of the frames. The following image is a mockup of what I'm trying to achieve, where the "reload" button grabs new data for just one printer.
I'm running into an issue where only the last values get updated. The following code is an approximation of what I was trying:
import tkinter as tk
from tkinter import ttk
def buttonupdate(x):
return int(x.get())+1
root=tk.Tk()
values=[0,0,0,0,0,0,0]
stringVarList=[]
for i,item in enumerate(values):
newStringVar=tk.StringVar()
newStringVar.set(item)
stringVarList.append(newStringVar)
valueLabel=tk.Label(root, textvariable=stringVarList[i])
valueLabel.grid(row=0,column=i)
button=tk.Button(root, text="+1", command=lambda:stringVarList[i].set(buttonupdate(stringVarList[i])))
button.grid(row=1, column=i)
root.mainloop()
With this code, only the last value gets updated, no matter which button I press.
What can I try instead? Thank you.
I'm currently using an embedded turtle canvas in a tkinter window. While it's intuitive that all I need to do is set my turtle to turtle.RawTurtle(canvas), there are some functions that just don't work, and I can't figure out why.
t.clear();t.pu();t.speed(0);t.ht();t.tracer(0)
But I get the error:
AttributeError: 'RawTurtle' object has no attribute 'tracer'
Despite this, many other functions work, such as clear, penup, speed, and hideturtle.
Is there any way of disabling screen updates until the drawing is finished, then manually updating the canvas, with RawTurtle?
The tracer() method is a method of the turtle's screen, not the turtle itself. To get access to it, when embedded under a tkinter window, wrap the canvas in a turtle screen:
screen = turtle.TurtleScreen(canvas)
t = turtle.RawTurtle(screen)
which should give you access to the various screen methods. Then you should be able to use screen.tracer(0) to turn off drawing updates and screen.update() to show the finished drawing. A more complete example:
import tkinter as tk
import turtle
root = tk.Tk()
canvas = turtle.ScrolledCanvas(root)
canvas.pack(side=tk.LEFT)
screen = turtle.TurtleScreen(canvas)
t = turtle.RawTurtle(screen)
t.hideturtle()
# t.speed('fastest')
screen.tracer(0)
t.penup()
t.sety(-100)
t.pendown()
t.circle(100)
screen.update()
screen.mainloop()
I am looking for a way to write information for my treeview in tkinter. I wrote this by using the set method but my sentences disappear when I write on the next line. I want my information for the teeeview to display when I move to the next line.
from tkinter import *
from tkinter import ttk
root =Tk()
tree = ttk.Treeview(root)
tree.insert("","0","item1",text="LANGUAGE")
tree.insert("","1","item2",text="GUI")
tree.insert("item1","1",text="Version")
tree.insert("item2","end",text="Tkinter")
tree.config(columns=("NOTE"))
tree.column("NOTE",width=300)
tree.heading("NOTE",text="Info")
tree.set("item1","NOTE","Am using python version 3.6.1 \n on windows machine
")
tree.set("item2","NOTE","This an example Tkinter Treeview in Python, which
is from \nttk class make sure import ttk\n also from tkinter import *")
tree.pack()
root.mainloop()
Are there any methods in treeview I can use to display this, because I want to write a lot of information for the treeview?
You need to increase the height of the rows so that all your text will be visible. The height of the rows can only be modified by using a style:
style = ttk.Style(root)
style.configure('my.Treeview', rowheight=50)
tree.configure(style='my.Treeview')
As far as I know, it is not possible to adjust the height of a single row.
I am trying to make a basic 4 frame animation, I cannot use a tkinter canvas as I want it to use the art which I have drawn (the files). There is nothing wrong with the file type as I have tested it on its own. However the code seems to just remove the window for the 6 seconds and then show the final frame.
import time
import tkinter
window=tkinter.Tk()
frame1=tkinter.PhotoImage(file="file1.ppm")
frame2=tkinter.PhotoImage(file="file2.ppm")
frame3=tkinter.PhotoImage(file="file3.ppm")
frame4=tkinter.PhotoImage(file="file4.ppm")
image=tkinter.Label(window,image=frame1)
image.pack()
time.sleep(2)
image.configure(image=frame2)
time.sleep(2)
image.configure(image=frame3)
time.sleep(2)
image.configure(image=frame4)
I'm not sure whether it is the "time.sleep" or the "image.configure" that is the problem but I have tried to mess around with different types of timing methods which also seem to fail.
import tkinter
window=tkinter.Tk()
frame1=tkinter.PhotoImage(file="file1.ppm")
frame2=tkinter.PhotoImage(file="file2.ppm")
frame3=tkinter.PhotoImage(file="file3.ppm")
frame4=tkinter.PhotoImage(file="file4.ppm")
image=tkinter.Label(window,image=frame1)
image.pack()
def loop(n):
frame = [frame1, frame2, frame3, frame4][n]
window.after(2000, lambda : image.configure(image=frame))
window.after(2000, lambda : loop((n+1)%4))
loop(1)