I'm trying to make a UI as an input, before closing this and then doing some plotting using pyplot. However, when I try to run a script using tkinter and importing matplotlib.pyplot, the program terminates at root = Tk() in the script, and will not run any commands after this line (including the mainloop).
Is there any way to use both tkinter and matplotlib.pyplot in the same script?
The UI I am running is:
from tkinter import *
class InputSelect(Frame):
def __init__(self, master):
self.master = master
Frame.__init__(self, master, width=200, height=200)
self.fillCanvas()
def fillCanvas(self):
self.canvas = Canvas(self, width=200, height=200)
self.canvas.pack()
self.aButton = Button(self, text="a", height=1, width=15, command=self.buttontest)
self.aButtonWindow = self.canvas.create_window(100, 80, window=self.aButton)
self.pack()
def buttontest(self):
print("buttontest")
def generateInputSelect():
print("test")
root = Tk()
print("test2")
app = InputSelect(root)
app.mainloop()
if __name__ == "__main__":
generateInputSelect()
This runs fine on its own, but if I use it in a separate script:
import ui
import matplotlib.pyplot
ui.generateInputSelect()
The console prints "test" and then closes, it doesn't reach "test2". This separate script runs as expected if I remove import matplotlib.pyplot.
After some discussion and further research, running the program through terminal led me to the error terminating with uncaught exception of type NSException.
I was able to fix this error by setting the TkAgg backend manually using
import matplotlib
matplotlib.use("TkAgg")
from matplotlib import pyplot as plt
as suggested by DonCristobal at Matplotlib Crashing tkinter Application
This issue appears to be related to MacOS, which is why the error wasn't able to be reproduced by some users.
Related
I am trying to build an app that generates dynamic visual models (using Python 3 with PyCharm on Windows). I am using Arcade for the main viewing / user interaction window, and Tkinter for preliminary data input, model parameters, numeric output, errors and warnings etc.
I find that if I open a tk window (e.g. messagebox.showinfo or messagebox.error) while the Arcade window is open, the application hangs. Here is a minimal snippet that recreats the problem:
import tkinter.messagebox
import arcade
tkinter.messagebox.showinfo("Greetings", "hello")
app = arcade.Window(500, 300, "Let's play")
tkinter.messagebox.showinfo("Greetings", "hello again")
The second messagebox never opens, and a whopping 30% of the CPU is active while Python is doing nothing except (in theory) waiting for user input.
Following solution works for the static text in Arcade. It won't update text dynamically. See Ethan Chan's comment below.
You can launch tkinter app from the arcade:
import arcade
import tkinter as tk
class ArcadeApp(arcade.Window):
def __init__(self):
super().__init__(400, 300)
self.root = None
def on_closing(self):
self.root.destroy()
self.root = None
def on_draw(self):
arcade.start_render()
arcade.draw_text('Click to launch Tkinter', 200, 150, arcade.color.RED, 30, align='center', anchor_x='center')
def on_mouse_release(self, x, y, button, key_modifiers):
if not self.root:
self.root = tk.Tk()
self.root.geometry('400x300')
self.root.protocol('WM_DELETE_WINDOW', self.on_closing)
label = tk.Label(self.root, text='Greetings from Tkinter!')
label.config(font=('', 20))
label.place(relx=0.5, rely=0.5, anchor='center')
self.root.mainloop()
ArcadeApp()
arcade.run()
Output:
I'm working on a tkinter GUI in Python to produce error messages in a new window. When running the code as shown below, the error noise plays, then it pauses for several seconds before opening the window. If I comment out the line with winsound, it opens it just fine.
import tkinter as tk
import winsound
class Error_Window:
def __init__(self, txt):
self.root = tk.Tk()
self.root.title("Error")
self.lbl = tk.Label(self.root, text=txt)
self.lbl.pack()
winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
self.root.mainloop()
I suspect that it may be due to the error noise playing in full before reaching the mainloop command. One solution to this could be running the sound in a separate thread, but I've heard multithreading with tkinter should be avoided. Any tips on getting it to open smoothly at the same time as the noise is played?
Try this, the reason why it does that is the whole program is should we say in ONE THREAD/ MAIN THREAD so it would do first or execute first the sound then pop up the window. I think there's no problem with working with threads in tkinter just like what #jasonharper said
import tkinter as tk
import winsound
import threading
class Error_Window:
def __init__(self, txt):
self.root = tk.Tk()
self.root.title("Error")
self.lbl = tk.Label(self.root, text=txt)
th = threading.Thread(target=self.__play_sound,args=[])
th.start()
self.lbl.pack()
self.root.mainloop()
def __play_sound(self):
winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
Error_Window("Hi")
from tkinter import*
import tkinter.messagebox
from tkinter import ttk
import random
import time
import datetime
def main():
root = Tk()
app = Login(root)
class Login:
def __init__(self, master):
self.master = master
self.master.title("Billing Login System")
self.master.geometry("1350x750+0+0")
self.master.config(bg = 'cadet blue')
self.frame = Frame(self.master,bg='cadet blue')
self.frame.pack()
#Some code here
..(Login Conditions)
..
#
#After authentication this window should pop up
class customer:
def __init__(self, root):
self.root = root
self.root.title("eZ Billing System")
self.root.geometry("1350x750+0+0")
self.root.config(bg="cadet blue")
self.frame = Frame(self.root,bg='cadet blue')
self.frame.pack()
#some code here
if __name__ == '__main__':
main()
This code works but the problem is that when i run the file no error shows up or warnings and neither does any window shows but if i run any other python program then this windows pops up and no problems.
I am new to this and cant figure out whats wrong.
I guess you aren't creating main window instance.
That's why it is not showing error but not showing any output even.
Try adding this :
root.mainloop()
Im new to programming, and really only doing this for a school project. Im trying to make a GUI that has a series of buttons that when pressed will run a specific emulator. When I try to run this I get a error saying "z26" is undefined. Im not quite sure on how to actually define it.
from tkinter import *
import os
class Application(Frame):
def __init__(self, master):
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
self._button = Button(self, text = "Atari", command = self._openFile)
self._button.grid()
def _openFile(self):
os.startfile(z26.exe)
root = Tk()
root.title("Arcade")
root.geometry("200x85")
app = Application(root)
root.mainloop()
The problem is that you are using x26.exe as a literal, and it is getting evaluated as though it were part of the Python program itself.
Instead, put the path with quotequotations, to make it a string:
os.startfile('path/z26.exe')
See also the Python documentation for os.startfile(path[, operation]).
I've come across a really annoying difference between how windows and mac handles a python tk window and matplotlib figure close_event.
My problem is thus,
I am trying to load a matplotlib figure from a tk button event.
I want the figure to show, and block the tk UI program flow while
the plot is active, and capturing user events until the plot is
closed.
After the plot is closed the tk app should continue.
Minimal example app showing issue.
from Tkinter import *
from matplotlib import pyplot as plt
class Plotter:
def __init__(self):
self.fig = plt.figure()
self.fig.canvas.mpl_connect('close_event', self.dispose)
plt.plot(1, 2, 'r*')
plt.show()
print "done with plotter"
def dispose(self, event):
plt.close('all')
print "disposed"
if __name__ == '__main__':
def pressed():
print 'button pressed'
Plotter()
print 'YAY'
root = Tk()
button = Button(root, text='Press', command=pressed)
button.pack(pady=20, padx=20)
root.mainloop()
Sadly, I found this works as expected in windows but not on mac using the same versions of python2.7, matplotlib (1.5.2).
Apart from the fact that this is not good UI practice, it bothers me that there is a difference on Mac and Windows for this piece of code. I would appreciate any feedback that would help with this issue, in the mean time i'll start work on implementing the plotter on a thread which is non-blocking and passing the result back to the main app when closed.
You can use plt.ion() to turn on Matplotlib's interactive mode, but this by itself will cause the program to continue without blocking the flow. To manually block the flow, use self.fig.canvas.start_event_loop_default() and self.fig.canvas.stop_event_loop() to pause the program flow until events are captured.
Implemented in your minimal example:
from Tkinter import *
from matplotlib import pyplot as plt
class Plotter:
def __init__(self):
plt.ion()
self.fig = plt.figure()
self.fig.canvas.mpl_connect('close_event', self.dispose)
self.fig.canvas.mpl_connect('button_press_event', self.on_mouse_click)
plt.plot(1, 2, 'r*')
plt.show()
self.fig.canvas.start_event_loop_default()
print "done with plotter"
def dispose(self, event):
self.fig.canvas.stop_event_loop()
print "disposed"
def on_mouse_click(self, event):
print 'mouse clicked!'
if __name__ == '__main__':
def pressed():
print 'button pressed'
Plotter()
print 'YAY'
root = Tk()
button = Button(root, text='Press', command=pressed)
button.pack(pady=20, padx=20)
root.mainloop()