Tkinter askopenfilename() won't close if destroy followed by an input - macos

I can't get a Tkinter file dialog box to close. This Tkinter file dialog box closes just fine if there is no input statement downstream. But with it, it does not close, and crashes the app.
Through a process of elimination, it seems input() downstream from the root.destroy() command is interfering with the window closing.
Anyone have a fix?
Here's the code:
import tkinter
from tkinter import filedialog
###### THIS CODE WORKS #########
# Make a top-level instance and hide since it is ugly and big.
root = tkinter.Tk()
root.withdraw()
# Make it almost invisible - no decorations, 0 size, top left corner.
root.overrideredirect(True)
root.geometry('0x0+0+0')
# Show window again and lift it to top so it can get focus,
# otherwise dialogs will end up behind the terminal.
root.deiconify()
root.lift()
root.focus_force()
# get the file path of the trades to load.
new_file_path = filedialog.askopenfilename()
# Get rid of the top-level instance once to make it actually invisible.
root.destroy()
###### WHEN INPUT IS ADDED IT DOESNT WORK######
input('Testing testing testing ')
I've tried adding a time.sleep(1) just after root.destroy.
I've tried the solution here:
Tkinter askopenfilename() won't close
I'm using OSX 10.11.4 with Pycharm.

Related

Spyder never "quits"

I loaded up Anaconda and realized there is more stuff there than I can absorb in my lifetime. However, I did load Spyder and pasted in a working program that runs without error in PyCharm and Thonny.
"""Create a 2 button window"""
import tkinter as tk
from tkinter import *
from tkinter import messagebox
#write slogan out in a message box
def write_slogan():
messagebox.showinfo("our message",
"tkinter is easy to use")
#set up the window
root = tk.Tk() #get the window
root.geometry("100x100+300+300") #x, y window size and position
#create Hello button
slogan = Button(root,
text="Hello",
command=write_slogan)
slogan.pack(side=LEFT, padx=10)
#create exit button with red letters
button = Button(root,
text="QUIT",
fg="red",
command=quit)
button.pack(side=RIGHT, padx=10)
#start running the tkinter loop
root.mainloop()
It may not surprise Spyder mavens, but I was surprised to see that it did not recognize "quit" However, I replaced it with
command=sys.exit
and that at least compiled.
However, when I ran it, the window appeared UNDER the Spyder window. I found it in the task bar. BUT, when I clicked in the Quit button, the program just hung. I had to go to the console and and type
quit
to stop the process.
I guess Spyder isn't really intended for GUI programming.

Is there a way to remove the background window that pops up when calling askopenfilename()?

When I call the basic command:
from tkinter.filedialog import askopenfilename
filename = askopenfilename()
A little window pops up behind the selector screen.
Is there a way to remove this?
It pops up because you need at least a "root" window for each tkinter application. In your case, you aren't creating any root window explicitly, so askopenfilename creates it automatically for you. One solution would be to create the root window explicitly and then hide it, something as follows
from tkinter.filedialog import askopenfilename
from tkinter import Tk
Tk().withdraw()
filename = askopenfilename()

Tkinter entry widget lags while typing. How to update typed text in real time?

Using python3. I'm new to tkinter writing a program with a GUI that takes some input parameters and does some data processing, so it needs entry boxes where I can type numbers in.
I cannot for the life of me figure out how to get the entry boxes to stop lagging, i.e: when a box is clicked on and typed into, the changes made to the text in that entry box don't appear until I click on another button or text box in the window. Functionally, the program still works like this but it's irritating not being able to see what I'm typing and others will eventually use this software.
I've gotten halfway to fixing the problem by putting in event bindings so that key presses trigger an update of the idle tasks. The text now updates while typing, but it's "one letter slow" (a typed letter appears only after the next letter is typed) and this is still not ideal.
Help?
MWE:
from tkinter import *
###Window: 'top'
top = Tk() #make window
top.geometry("670x360") #window size
top.wm_title("Test program for TKinter")#window title
#window and label background colour
bgcol='light sea green'
top.configure(background=bgcol) #set colour
#events to refresh window
def keypress(event):
print('key pressed')
#update all idle widgets (remove text box lag)
top.update_idletasks()
def mouseentry(event):
print('mouse entered text box')
#update all idle widgets (remove text box lag)
top.update_idletasks()
##text entry box
Label(top,background=bgcol, text="").pack() #spacing label
v = StringVar()
e=Entry(top, width=50, textvariable=v)#,height=1)
e.pack()
Label(top,background=bgcol, text="").pack() #spacing label
v.set("a default value")
s = e.get()
e.bind("<Key>",keypress)
e.bind("<Enter>",mouseentry)
#Label displaying text box contents (not working right now, not important)
Label(top,background=bgcol, textvariable=s).pack() #text display label
#make buttons appear on start
top.update()
top.mainloop()
How do I update the entry widget as it is typed? Is there something really simple that I'm overlooking?
Answer to own question:
Mainloop wasn't running in the background (or something) of my python install, for whatever reason, whether run via Anaconda or via the terminal.
Simple reinstall of Anaconda IDE with python3.4 fixed all my issues.

Raspberry Pi escape character

I am trying to create a shell script in which I automatically run a video fullscreen.
It has no way to quit unless I shut down the Raspberry Pi.
What is a small script I can use to bind something like "!" to quit the application?
I searched Google for 'omxplayer exit fullscreen' and found this answer, originally posted by dom on the RaspberryPi forum:
Changing TV modes does lose any content on them (e.g. the console
framebuffer).
You can provoke the console framebuffer to be recreated with: fbset
-depth 8 && fbset -depth 16
Add that to the end of a script that launches omxplayer.
(for extra points read the depth before launching omxplayer and set it
back to original value afterwards)
You might also want to check this issue report on omxplayer's GitHub.
I am not sure if this will work but potentially you could use a tkinter window that you make non visable.
#import the tkinter module for the GUI and input control
try:
# for Python2
import Tkinter as tk
from Tkinter import *
except ImportError:
# for Python3
import tkinter as tk
from tkinter import *
def key(event):
#create a function to control closing the window in this case
if event.keysym == 'Escape':
#this currently closes the window however you could add to root.destroy() with
#the relevant command for closing the video.
root.destroy()
#initiate root window, remove it from view, bind all keys (you could just
#bind '<Escape>' if preffered
root = Tk.tk
root.withdraW()
root.bind_all('<Key>', key)
i am aware this isnt a specific design to your problem however it will let you bind the escape key like you wished. this stopped the whole application in my example however you may have to include extra lines to ensure each part of your application is correctly ended.

Create a PyGTK GUI with event to reload itself

I'm prototyping GUI layout with PyGTK, sometimes using glade/builder sometimes not, and the following scene repeats endlessly:
Modify the code
Run the GUI script
Judge the result
Modify again
Run again...
So, since I heard that Python allows reloading of modules, I would like to know if it is possible to modify the code WITHOUT CLOSING THE WINDOW, and then, from the window itself, say, clicking on a button, "reload" the window reflecting the changes in code.
Since it is a conceptual question, I don't have any specific code to show.
Thanks for the attention
I think it is possible if you do the following:
Identify and isolate the widget W that you want to see updated when you press the button (if you want to see the whole window updated, then make it whatever you add in the window, not the window itself).
Write a function (or class) that creates and returns this widget
Put this function or class in a module that you will reload
Create your button outside W and connect it to a function that does the following
Remove current W from window
Reload the module
Create new instance of W
Add it to the window
Of course, the critical step here is "reload the module". I guess you have to make sure no code from the module is running and no other module depends on variables defined on this module.
EDIT: I had some time, so I made a little prototype. Change the label in widget_module.py and then hit Update
gui.py
# Load in pygtk and gtk
import pygtk
pygtk.require('2.0')
import gtk
import widget_module
# Define the main window
class Whc:
def __init__(self):
# Window and framework
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("destroy", self.destroy)
# A Button, with an action
# Add it to the geometry
# show the button
self.button = gtk.Button("Update")
self.button.connect("clicked", self.update, None)
self.vbox = gtk.VBox()
self.vbox.pack_start(self.button)
self.widget = widget_module.get_widget()
self.vbox.pack_start(self.widget)
self.window.add(self.vbox)
# Show the window
self.window.show_all()
# Callback function for use when the button is pressed
def update(self, widget, data=None):
print "Update"
self.vbox.remove(self.widget)
reload(widget_module)
self.widget = widget_module.get_widget()
self.vbox.pack_start(self.widget)
self.widget.show()
# Destroy method causes appliaction to exit
# when main window closed
def destroy(self, widget, data=None):
gtk.main_quit()
# All PyGTK applicatons need a main method - event loop
def main(self):
gtk.main()
if __name__ == "__main__":
base = Whc()
base.main()
widget_module.py
import pygtk
import gtk
def get_widget():
return gtk.Label("hello")

Resources