Application hangs after deiconify(), Tkinter - python

I'm trying to do Hide/Show for my application with withdraw()/deiconify() in Tkinter, but after deiconify() method call my app hangs. Run this code on Win7.
What do I do wrong?
import Tkinter as tk
import threading
class MyApp(object):
def __init__(self, parent):
self.root = parent
self.root.geometry('400x300')
self.root.title('My Application')
btn = tk.Button(parent, text='Hide', command=self.onClick)
btn.pack()
def onClick(self):
self.hide()
self.t = threading.Timer(3, self.show)
self.t.start()
def hide(self):
print 'hide()'
print 'state: ', self.root.state()
print 'withdraw()'
self.root.withdraw()
print 'state: ', self.root.state()
def show(self):
print 'show()'
print 'state: ', self.root.state()
print 'deiconify()'
self.root.deiconify()
print 'state: ', self.root.state()
print 'show end'
if __name__ == '__main__':
root = tk.Tk()
app = MyApp(root)
root.mainloop()
UPD: there is a working sample:
import Tkinter as tk
import sched
import time
class MyApp(object):
def __init__(self, parent):
self.root = parent
self.root.geometry('400x300')
btn = tk.Button(parent, text='Hide', command=self.onClick)
btn.pack()
self.scheduler = sched.scheduler(time.time, time.sleep)
def onClick(self):
self.hide()
self.scheduler.enter(3, 1, self.show, ())
self.scheduler.run()
def hide(self):
self.root.withdraw()
def show(self):
self.root.deiconify()
if __name__ == '__main__':
root = tk.Tk()
app = MyApp(root)
root.mainloop()

Tkinter is not thread safe, and you are calling self.root.deiconify() from a thread. That is most likely the source of your problem. You'll have to re-architect your solution to have the thread use a thread-safe queue to request that the main loop make calls into Tkinter.
There's a whole lot you can do with Tkinter without using threads. Are you certain you need them?

Related

Continue executing function

When closing an instance of the ChildWindow class, which was called from another instance of MainWindow, the code does not continue to be executed.
I noticed that only when the MainWindow instance is closed does it continue to run. In general, it has a cumulative property, so the number of times the ChildWindow closes the window, the continuation will be displayed.
I want the function to continue executing when the ChildWindow closes, without closing the main window.
Here's my code:
from tkinter import *
class MainWindow():
def __init__(self):
self.root = Tk()
def run(self):
Button(self.root, text='click', command=lambda:self.open_child_window()).pack()
self.root.mainloop()
def open_child_window(self):
A = ChildWindow()
A.run()
print("why i'm not write?")
class ChildWindow():
def __init__(self):
self.root = Toplevel()
def run(self):
self.root.mainloop()
A = MainWindow()
A.run()
It seems to me that this is due to the self.root.mainloop() loop, so I was looking for how to stop it, the .quit(), .destroy() methods do not help.
It's called a nested event loop or modal loop. Use the mainloop() and quit() like this.
class ChildWindow():
def __init__(self):
self.root = Toplevel()
def run(self):
win = self.root
def on_close():
win.destroy()
win.quit()
win.protocol('WM_DELETE_WINDOW', on_close)
win.mainloop()
print('end of the nested loop')
...
You can also use wait_window() and destroy() like this.(The former runs a nested event loop until the window is destroyed.)
class ChildWindow():
...
def run(self):
win = self.root
def on_close():
win.destroy()
win.protocol('WM_DELETE_WINDOW', on_close)
win.wait_window()

Tkinter window backend coding

import pyupbit
from tkinter import *
class Main(Frame):
def __init__(self, window):
Frame.__init__(self, window)
self.window = window
self.price = Label(self.window, text='hello')
self.price.place(x=20,y=20)
self.get_price()
def get_price(self):
self.after(100, self.get_price)
price = pyupbit.get_current_price('KRW-BTC')
self.price.configure(text=price)
if __name__ == '__main__':
root = Tk()
root.geometry('300x300')
Main(root)
root.mainloop()
I'm trying to show bitcoin price every ms. I guess, because of api delay, the window looks have lags. I want to get the price in the backend and show it on frontend. How can I ? Can I get examples?
Try this:
import pyupbit
from tkinter import *
from threading import Thread
class Main(Frame):
def __init__(self, window):
super().__init__(window)
self.window = window
self.price = 0
self.price_label = Label(self.window, text='hello')
self.price_label.place(x=20,y=20)
thread = Thread(target=self.get_price_loop, daemon=True)
thread.start()
self.show_price()
def show_price(self):
self.price_label.configure(text=self.price)
self.after(30, self.show_price)
def get_price_loop(self):
while True:
self.price = pyupbit.get_current_price('KRW-BTC')
# Here you can add a bit of delay using `time.sleep(0.1)`
if __name__ == '__main__':
root = Tk()
root.geometry('300x300')
Main(root)
root.mainloop()
I has 2 loops. The tkinter loop displays whatever is in the self.price variable and the while True loop in the other thread updates that value by using self.price = pyupbit.get_current_price('KRW-BTC').

Tkinter - The Root Window hides itself after close its Toplevel window

below my code:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - TEST")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.obj = NewWindow(self)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico")
# the "try/except" code has an issue..
try:
self.window.focus()
self.mw.parent.attributes('-disabled', 1)
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
finally:
self.mw.parent.attributes('-disabled', 0)
def main():
app=MainWindow()
if __name__=="__main__":
main()
the try/except code makes the Toplevel window important. when it runs, the user can't touch the root window, and if he try to do it, a bell songs and the Toplevel window flashes. it's the exactly behaivour that I want! but this piece of code has an issue.. when the user close the Toplevel window, the root doesn't became the active window. it's a big issue because it makes the root window to go back the other ones. see my gif to understand better what I mean:
http://www.imagebam.com/image/c983ce1356199964
how can I solve this issue?
You've got the wrong idea about try ... finally; it does not work that way. There are 2 ways to do what you want. One way is to simply put that code in the main window:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - TEST")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.parent.attributes('-disabled', 1)
self.obj = NewWindow(self)
self.parent.attributes('-disabled', 0)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico")
self.window.focus()
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
def main():
app=MainWindow()
app.parent.mainloop()
if __name__=="__main__":
main()
Another way is to make a method to run when the toplevel closes:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - TEST")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.obj = NewWindow(self)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico")
self.window.protocol("WM_DELETE_WINDOW", self.on_close)
self.window.focus()
self.mw.parent.attributes('-disabled', 1)
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
def on_close(self):
self.mw.parent.attributes('-disabled', 0)
self.window.destroy()
def main():
app=MainWindow()
app.parent.mainloop()
if __name__=="__main__":
main()

How to use multiprocessing.Pool correctly with PySide to create a non-blocking GUI

I am try to use multiprocessing to create a non-blocking GUI. The function Multiprocessing.Pool.appy_async() allows a callback function to be added, making it easy to update the main GUI after a time-intensive operation has been completed. However, the following code still blocks when clicking on button1. How can I modify this so that while the button1 callback is executing, button2 still responds. I am running python 2.7 and multiprocessing 0.70a1.
from PySide.QtCore import *
from PySide.QtGui import *
import multiprocessing
import time
import sys
def f(x):
'''This is a time-intensive function
'''
y = x*x
time.sleep(2)
return y
class MainWindow(QMainWindow): #You can only add menus to QMainWindows
def __init__(self):
super(MainWindow, self).__init__()
self.pool = multiprocessing.Pool(processes=4)
button1 = QPushButton('Connect', self)
button1.clicked.connect(self.apply_connection)
button2 = QPushButton('Test', self)
button2.clicked.connect(self.apply_test)
self.text = QTextEdit()
vbox1 = QVBoxLayout()
vbox1.addWidget(button1)
vbox1.addWidget(button2)
vbox1.addWidget(self.text)
myframe = QFrame()
myframe.setLayout(vbox1)
self.setCentralWidget(myframe)
self.show() #display and activate focus
self.raise_()
def apply_connection(self):
result = self.pool.apply_async(f, [10], callback=self.update_gui)
result.get(3)
def update_gui(self, result):
self.text.append('Applied connection. Result = %d\n' % result)
def apply_test(self):
self.text.append('Testing\n')
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
app.exec_()
result.get(3) blocks for 3 seconds to wait for the result. Don't call get, the callback will handle the result.

tkinter quit crash

I am very new to Tkinter. I made this "Hello World"-like GUI program in Tkinter. However, every time I click on the quit button, the program crashes. Thanks in advance!
from Tkinter import *
import sys
class Application(Frame):
def __init__(self,master=None):
Frame.__init__(self,master=None)
self.grid()
self.createWidgets()
def createWidgets(self):
self.quitButton = Button(text='Quit',command=self.quit)#Problem here
self.quitButton.grid()
app = Application()
app.master.title("Sample application")
app.mainloop()
In Tkinter the root element is a Tk object. Application should be a subclass of Tk, not Frame:
from Tkinter import *
import sys
class Application(Tk):
def __init__(self):
Tk.__init__(self)
self.grid()
self.createWidgets()
def createWidgets(self):
self.quitButton = Button(text='Quit',command=self.destroy) # Use destroy instead of quit
self.quitButton.grid()
app = Application()
app.title("Sample application")
app.mainloop()
This Code works fine now:
import tkinter
class MyApp(tkinter.LabelFrame):
def __init__(self, master=None):
super().__init__(master, text="Hallo")
self.pack(expand=1, fill="both")
self.createWidgets()
self.createBindings()
def createWidgets(self):
self.label = tkinter.Label(self)
self.label.pack()
self.label["text"] = "Bitte sende ein Event"
self.entry = tkinter.Entry(self)
self.entry.pack()
self.ok = tkinter.Button(self)
self.ok.pack()
self.ok["text"] = "Beenden"
self.ok["command"] = self.master.destroy
def createBindings(self):
self.entry.bind("Entenhausen", self.eventEntenhausen)
self.entry.bind("<ButtonPress-1>", self.eventMouseClick)
self.entry.bind("<MouseWheel>", self.eventMouseWheel)
def eventEntenhausen(self, event):
self.label["text"] = "Sie kennen das geheime Passwort!"
def eventMouseClick(self, event):
self.label["text"] = "Mausklick an Position " \
"({},{})".format(event.x, event.y)
def eventMouseWheel(self, event):
if event.delta < 0:
self.label["text"] = "Bitte bewegen Sie das Mausrad"\
" in die richtige Richtung."
else:
self.label["text"] = "Vielen Dank!"
root = tkinter.Tk()
app = MyApp(root)
app.mainloop()
When you use self.quit() the python interpreter closes down without the tkinter application bieng closed . So try .destroy() command and after .mainloop() use sys.quit(). Hope this helps.
Your using __init__ difficultly. Do this:
from tkinter import *
root = Tk()
btn_quit = Button(root, text='Quit', command=quit()).pack()
root.mainloop()
If you do self.quit, that is the quit command so the thing will crash!
Hope this helps!
try using raise SystemExit
this may be better.
or check out me

Categories

Resources