tk button changes appearance - python-2.7

So I was doing this program and noticed that both my buttons look initially like this
And after I run my program for some time the second button changes it appearance to this
When does this happen?
Here's my code :/ in case I am doing something that should not be done. I am doing this in python 2.7.8 in IDLE.
import time
import Tkinter as tk
from Tkinter import StringVar
import threading
global root
root = tk.Tk()
x = tk.StringVar()
x.set('false')
def xval(*args):
try:
for i in range(0,9):
global x
print x.get()
if x.get()== 'false' :
print "x=false %d time"%i
time.sleep(1)
else:
print "waiting"
root.update()
except:
pass
def stop(event):
resume_btn.configure(state="normal")
global x
x.set('true')
print "execution stopped:%s"%x
def start(event):
global x
x.set('false')
print "execution started:%s"%x
xval()
root.title("GUI-Data Retrieval")
th = threading.Event()
t = threading.Thread(target=xval,args=(th,))
t.deamon=True
t.start()
x_btn = tk.Button(root, text="Stop", background="Snow", width=20, relief="raised")
x_btn.grid(row=0, column=4, sticky="W", padx=20, pady=5)
x_btn.bind('<Button-1>',stop)
resume_btn = tk.Button(root, text="Start", background="Snow", width=20, relief="raised")
resume_btn.configure(state="disabled")
resume_btn.grid(row=0, column=6, sticky="W", padx=20, pady=5)
resume_btn.bind('<Button-1>',start)
root.mainloop()

The problem is that your binding is handled before the default bindings. It is the default bindings that change the appearance of the button when it is clicked on. You are disabling the button on a click, preventing the default behavior from resetting the appearance of the button when you release the mouse button.
Unless there's a specific reason to do otherwise, you should use the command attribute of the button widget rather than try to create your own bindings.

Related

Tkinter message box without any buttons

How can I do in tkinter something similar to a messagebox, but that doesn't have any buttons, including the close, minimize and maximize buttons on top?
I want it to be in a different window (like a message box), and to be able to update the text and close it only within the code.
Is there a way to do something like that?
Make your own. For example:
try: #python3 imports
import tkinter as tk
except ImportError: #python3 failed, try python2 imports
import Tkinter as tk
class Popup(tk.Toplevel):
"""modal window requires a master"""
def __init__(self, master, **kwargs):
tk.Toplevel.__init__(self, master, **kwargs)
self.overrideredirect(True)
self.geometry('300x200+500+500') # set the position and size of the popup
lbl = tk.Label(self, text="Please wait for other players to join ... ")
lbl.place(relx=.5, rely=.5, anchor='c')
# The following commands keep the popup on top.
# Remove these if you want a program with 2 responding windows.
# These commands must be at the end of __init__
self.transient(master) # set to be on top of the main window
self.grab_set() # hijack all commands from the master (clicks on the main window are ignored)
### demo usage:
def open_popup():
root.popup = Popup(root)
# close the popup in 2 seconds
root.after(2000, close_popup)
def close_popup():
root.popup.destroy()
root = tk.Tk()
btn = tk.Button(root, text='Open Modal Window', command=open_popup)
btn.pack()
root.mainloop()

New window opens on click but does not show anything[Tkinter]

I am using root as the primary window in which when one puts a question, then the answer from either Wikipedia or WolframAlpha is shown in a new window. But, here what happens is that the new window properly opens but does not show anything.
from Tkinter import *
import wolframalpha
import wikipedia
root=Tk()
root1=Tk()
def getinput():
global entry
answer = StringVar()
ques=entry.get()
try:
#wolframalpha
app_id = myappid #value of myappid is there in the original code
client = wolframalpha.Client(app_id)
res = client.query(ques)
answer.set(next(res.results).text)
label=Label(root1, textvariable=answer)
except:
#wikipedia
answer.set(wikipedia.summary(ques).encode('utf-8'))
label=Label(root1, textvariable=answer)
label.pack(side=BOTTOM)
root.geometry("350x80+300+300")
label=Label(root, text="Hi! I am Python Digital Assistant. How can I help you today?")
entry=Entry(root)
submit=Button(root, text="Submit", bg="light green", command=getinput)
exit1=Button(root, text="Exit", bg="red", fg="white", command=root.destroy)
label.pack()
entry.pack(fill=X)
entry.focus_set()
submit.pack(side=LEFT)
exit1.pack(side=LEFT)
root.mainloop()
You don't have to call TK twice you have to use toplevel to achieve that , with that when you provide the question and click on the submit method the answer will pop up in the Toplevel window.
from Tkinter import *
import wolframalpha
import wikipedia
root=Tk()
def getinput():
top = Toplevel()
top.geometry("500x500")
global entry
answer = StringVar()
ques=entry.get()
try:
#wolframalpha
app_id = myappid #value of myappid is there in the original code
client = wolframalpha.Client(app_id)
res = client.query(ques)
answer.set(next(res.results).text)
label=Label(top, textvariable=answer)
except:
#wikipedia
answer.set(wikipedia.summary(ques).encode('utf-8'))
label=Label(top, textvariable=answer)
label.pack(side=TOP)
root.geometry("350x80+300+300")
label=Label(root, text="Hi! I am Python Digital Assistant. How can I help you today?")
entry=Entry(root)
submit=Button(root, text="Submit", bg="light green", command=getinput)
exit1=Button(root, text="Exit", bg="red", fg="white", command=root.destroy)
label.pack()
entry.pack(fill=X)
entry.focus_set()
submit.pack(side=LEFT)
exit1.pack(side=LEFT)
root.mainloop()

tkinter avoid GUI from freezing

I developed a simple Python application doing some stuff, then I decided to add a simple GUI using Tkinter.
The problem is that, while the I call a function called startprocess and begin doing stuff which is processor heavy and the window freezes.
I know it's a common problem and I've already read that I should use multithreads (very complicated, because the function updates the GUI too) or divide my code in different function, each one working for a little time. anyways is there any modification needed in below code to avoid GUI freezing?
import threading
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import os, datetime, sys, subprocess
import parselog_v1
# diplay messagebox window
def MessageBox(windowLable,msg):
messagebox.showinfo(windowLable, msg)
# check if Dir empty
def checkDirEmpty(work_path):
if os.path.isdir(work_path):
if not os.listdir(work_path):
print ("No Files found in directory")
MessageBox('Log Parser', 'No Files found in directory.')
else:
return True
# launch app in center of screen
def center_window(width=300, height=200):
# get screen width and height
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# calculate position x and y coordinates
x = (screen_width/2) - (width/2)
y = (screen_height/2) - (height/2)
root.geometry('%dx%d+%d+%d' % (width, height, x, y))
# application frame
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
self.master.title("Log Parser")
def createWidgets(self):
self.Run_Main = tk.Button(self)
self.Run_Main["text"] = "Browse for logs"
self.Run_Main["fg"] = "blue"
self.Run_Main["command"] = self.startProcess
self.Run_Main.pack(side='left',padx=0)
self.QUIT = tk.Button(self)
self.QUIT["text"] = "Quit!"
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
self.QUIT.pack(side='right',padx=5)
def startProcess(self):
global Src_foldername
Src_foldername = filedialog.askdirectory()
Src_foldername = Src_foldername.replace("/", "\\")
print("Source folder: " + Src_foldername)
if checkDirEmpty(Src_foldername):
# process logs
# multithread
print("Processing...")
self.refresh()
threading.Thread(target=parselog_v1.main(Src_foldername))
# scroll text inside application frame
class scrollTxtArea:
def __init__(self, root):
frame = tk.Frame(root)
frame.pack()
self.textPad(frame)
return
class IORedirector(object):
'''A general class for redirecting I/O to this Text widget.'''
def __init__(self, text_area):
self.text_area = text_area
class StdoutRedirector(IORedirector):
'''A class for redirecting stdout to this Text widget.'''
def textPad(self, frame):
# add a frame and put a text area into it
textPad = tk.Frame(frame)
self.text = tk.Text(textPad, height=21, width=68)
self.text.config()
# add a vertical scroll bar to the text area
scroll = tk.Scrollbar(textPad)
self.text.configure(yscrollcommand=scroll.set,background="black", foreground="green")
# pack everything
self.text.pack(side=tk.LEFT, pady=2)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
textPad.pack(side=tk.TOP)
self.text.insert("end", "Begin by selecting log folder..." + "\n")
self.text.configure(state='disabled') # disable text editing
sys.stdout = (self) # to begin logging stdio to GUI
return
def write(self, txt):
self.text.configure(state='normal')
self.text.insert('end', txt)
self.text.configure(state='disabled')
root = tk.Tk()
root.resizable(width=False, height=False)
center_window(500, 300) # launch in center of screen
app = Application(master=root)
scrollFrame = scrollTxtArea(root)
app.mainloop()
root.destroy()
You use thread in wrong way.
First: target= needs function name without () and arguments.
You can assign arguments to args= (it have to be tuple even if you have only one argument)
threading.Thread(target=parselog_v1.main, args=(Src_foldername,) )
Now your code runs parselog_v1.main as normal function, waits for result and it will assign this result as function name to taget= - so you have something like this:
result = parselog_v1.main(Src_foldername)
threading.Thread(target=result)
It stops mainloop so it can't get mouse/keyboard events, refresh window, etc. so it looks like window freeze.
Second: after you create thread correctly you have to start it
my_thread = threading.Thread(target=parselog_v1.main, args=(Src_foldername,) )
my_thread.start()

Clearing tkinter canvas containing label

I create such a code:
import Tkinter as tk
from Tkinter import *
def b(canvas):
canvas.delete("all")
canvas.update()
print "works"
def main():
root = Tk()
canvas=Canvas(root)
canvas.config(width=400, height=300)
bb=Button(canvas, text="ssss",command=lambda:b(canvas))
bb.place(x=100,y=200)
root.geometry('400x300')
aa=Label(canvas,text="aaaaa")
aa.place(x=10,y=200)
canvas.pack()
root.mainloop()
if __name__ == '__main__':
main()
And the problem is that after clicking on a button label is not destroyed despite the fact that a function with canvas.destroy("all") runs.
The label is not deleted when canvas.delete("all") is invoked because you have used place to display the label, so it is not an item of the canvas. To make the label a canvas item, you need to replace
aa.place(x=10,y=200)
by
canvas.create_window(10, 200, window=aa)
And then canvas.delete("all") will also delete the label.

Tkinter Button disable does not work

Hi i am trying to disable a button , so that the command event does not work for some time .How can i make the button disabled for some time and then later reenable it , to get the callback function .
#! /usr/bin/python
from Tkinter import *
import Tkinter as tk
import time
class MyFrame(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.b1 = Button(self, text="Press Me!",command = self.callback)
self.count=0
self.but_flag=0
self.b1.grid()
def callback(self):
self.b1['state'] = DISABLED
for k in range(5):
time.sleep(1)
print k
self.b1['state'] = NORMAL
mainw = Tk()
mainw.f = MyFrame(mainw)
mainw.f.grid()
mainw.mainloop()
The problem is that the sleep in your callback function is blocking the UI from refreshing. Instead of using sleep, you could schedule the re-enabling of the button using after.
def callback(self):
self.b1['state'] = DISABLED
self.after(3000, self.enable)
def enable(self):
self.b1['state'] = NORMAL
But if you do any long-running task in callback, this will still freeze the UI.
Another alternative would be to create a worker thread for doing the actual work. This way, the UI thread is not blocked and the UI will be updated and the button deactivated/activated.
def callback(self):
threading.Thread(target=self.do_actual_work).start()
def do_actual_work(self):
self.b1['state'] = DISABLED
for i in range(5):
print i
time.sleep(1)
self.b1['state'] = NORMAL
Of course, you could also just add self.b1.update() after the disabling line to update the Button widget to its disabled state, but this will still leave the UI frozen until the method is finished.