This is a dialog form class :
** update full workable source code showing the problem
from tkinter import *
class SGForm:
created_form = False
def __init__(self, root, title=""):
self.form = Toplevel(root)
self.form.wm_title(title)
self.input = dict()
self.var = StringVar()
SGForm.created_form = True
def getform(self):
return self.form
def addinput(self, name, text ,var = None):
p = Frame(self.form)
p.pack(side="top", fill="both", expand=True, padx=10, pady=10)
l = Label(p, text=text)
l.pack(side="left", fill="both", expand=True, padx=10, pady=10)
self.input[name] = Entry(p, textvariable=var)
self.input[name].pack(side="left", fill="both", expand=True, padx=10, pady=10)
def addbutton(self, text, signal, func):
p = Frame(self.form)
p.pack(side="top", fill="both", expand=True, padx=10, pady=10)
b = Button(p, text=text)
b.pack(side="left", fill="both", expand=True, padx=10, pady=10)
b.bind(signal, func)
def showandreturn(self):
value = dict()
value['firstname'] = self.var.get()
SGForm.created_form = False
return value
def closeform(self, event):
self.form.destroy()
def customform(self):
self.addinput('entfirstname', 'frist name', self.var)
self.addbutton('close','<Button-1>', self.closeform)
#example calling dialog class
root = Tk()
def evntshow(event):
form = SGForm(root)
form.customform()
root.wait_window(form.getform())
test = form.showandreturn()
print(test)
button = Button(root, text='show')
button.pack()
button.bind('<Button-1>', evntshow)
root.mainloop()
Each time the button get pressed eventaddperson get triggered, when exiting the function the button animation of the main window get stuck on press status, I am looking for a way to refresh the gui or what if I am doing something wrong how to fix it?
If I use command= instead of bind() then problem disappers
BTW: if you use command= then def evntshow()has to be without event
def evntshow(): # <--- without event
form = SGForm(root)
form.customform()
root.wait_window(form.getform())
test = form.showandreturn()
print(test)
# use `command=` instead of `bind('<Button-1>',...)
button = Button(root, text='show', command=evntshow)
button.pack()
I was experiencing kind of laggy button animations when using bind() as well, switching to command= made it a look a lot better!
from tkinter import *
import time
def func1():
print('waiting for 1 second...')
time.sleep(1)
def func2(event):
print('waiting for 1 second...')
time.sleep(1)
root = Tk()
# button animation runs smoothly
Button1 = Button(root, text="button with command=", command=func1)
Button1.pack()
Button2 = Button(root, text="button with bind()") # button animation does not occur
Button2.bind('<Button-1>', func2)
Button2.pack()
root.mainloop()
I am working with python 3.6 and windows 10
Related
I'm very new to python and I don't know why but my code keeps crashing when I implement the listener specifically at the
with Listener(on_press=press) as listener: listener.join() and when it crashes it doesn't give me a error message
here's the entirety of my code:
import tkinter as tk
from tkinter.constants import LEFT, N, NE, NW, W
from PIL import Image, ImageTk
import tkinter.ttk as ttk
import time
from pynput.keyboard import Key, Controller
from pynput.keyboard import Listener
self = tk.Tk()
self.title('Key spammer')
self.iconbitmap("D:\Vs code repos\Key spammer\keyboard-icon.ico")
#Set the geometry of frame
self.geometry("350x550")
self.resizable(False, False)
#Button exit function
def exit_prog():
exit()
def press(key):
print(key)
#press interval
self.grid_rowconfigure(20, weight=1)
self.grid_columnconfigure(20, weight=1)
labelframe = ttk.Labelframe(self,text= "Press interval")
labelframe.grid(row=1, column=0, padx= 25, sticky=N)
class Lotfi(ttk.Entry):
def __init__(self, master=None, **kwargs):
self.var = tk.StringVar()
ttk.Entry.__init__(self, master, textvariable=self.var, **kwargs)
self.old_value = ''
self.var.trace('w', self.check)
self.get, self.set = self.var.get, self.var.set
def check(self, *args):
if self.get().isdigit():
# the current value is only digits; allow this
self.old_value = self.get()
else:
# there's non-digit characters in the input; reject this
self.set(self.old_value)
#Entry interval
hoursentry = Lotfi(labelframe, width= 10)
hoursentry.grid(row=1, column=1, padx= 5, pady= 10)
hoursentry.insert(0, '0')
hourslabel = ttk.Label(labelframe, text= "hours")
hourslabel.grid(row=1, column=2)
minutesentry = Lotfi(labelframe, width= 10)
minutesentry.grid(row=1, column=3)
minutesentry.insert(0, '0')
minuteslabel = ttk.Label(labelframe, text= "mins")
minuteslabel.grid(row=1, column=4)
secondsentry = Lotfi(labelframe, width= 10)
secondsentry.grid(row=1, column=5)
secondsentry.insert(0, '0')
secondeslabel = ttk.Label(labelframe, text= "secs")
secondeslabel.grid(row=1, column=6)
labelframekey = ttk.Labelframe(self,text= "Key options")
labelframekey.grid(row=2, column=0, padx= 25, pady= 25, sticky=NW)
#labelframekey.pack(side= LEFT)
keypress = ttk.Label(labelframekey, text= "Key pressed", font= 10)
keypress.grid(row=2, column=0, sticky= N)
with Listener(on_press=press) as listener:
listener.join()
class Keyreg(ttk.Entry):
def __init__(self, master=None, **kwargs):
self.var = tk.StringVar()
ttk.Entry.__init__(self, master, textvariable=self.var, **kwargs)
self.old_value = ''
self.var.trace('w', self.check)
self.get, self.set = self.var.get, self.var.set
def check(self, *args):
if press:
self.set(self.old_value)
#Keyreg = Keyreg(labelframekey, width= 10)
#keyreg.grid(row=2, column=1, sticky= N)
'''
#Creation of Option buttons
button = ttk.Button(self, text = 'Exit', command = exit_prog, width = 25)
button.grid(row=2, column=1,padx= 5, ipadx=15, ipady=10)
button2 = ttk.Button(self, text = 'Exit', command = exit_prog, width = 25)
button2.grid(row=2, column=2, ipadx=15, ipady=10)
button3 = ttk.Button(self, text = 'Exit', command = exit_prog, width = 25)
button3.grid(row=3, column=1, ipadx=15, ipady=10)
button4 = ttk.Button(self, text = 'Exit', command = exit_prog, width = 25)
button4.grid(row=3, column=2, ipadx=15, ipady=10)
'''
#Top menu for keybinds
tk.mainloop()
I tried to figure out the problem myself but when i imported it to another tab and used multiple different methods it still never crashed on those test
Please help me
You didn't show full error message so I don't know what is your real problem but I see one problem.
Code
with Listener(on_press=press) as listener:
listener.join()
runs code which waits for the end of listener and it stops rest of code
if you want to run it at the same time as tkinter then you should run as
with Listener(on_press=press) as listener:
tk.mainloop()
listener.join()
or more similar to threading (which is used by listener)
listener = Listener(on_press=press)
listener.start()
tk.mainloop()
listener.join()
relatively new to coding and currently I am playing with tkinter in python, I am using a text widget within a function and want to send the input from the text box to another function. My global variable says undefined at module level, so How could I make it defined at a module level if its within a function?
When I press the send email button I get this error message "NameError: name 'user_message_entry' is not defined"
Any suggestions? Many thanks!
minimum reproduction:
import tkinter as tk
root = tk.Tk()
root.geometry("500x500")
def send_email():
global user_message_entry
subject = ":)"
body = user_message_entry.get("1.0", "end")
message = f"subject: {subject}\n\n {body}"
print(message)
def feedback():
feedback_window = tk.Toplevel()
feedback_window.geometry("690x650")
message_frame = tk.Frame(feedback_window)
message_frame.grid(row=0, column=0, columnspan=3)
user_message_entry = tk.Text(message_frame, height=10, width=60)
user_message_entry.grid(row=0, column=0)
send_email_button = tk.Button(feedback_window, command=send_email,
height=20, width=20, bg="yellow", text="send email")
send_email_button.grid(row=1, column=0)
open_feedback_button = tk.Button(root, command=feedback, height=20, width=20, bg="yellow", text="open feedback window")
open_feedback_button.grid(row=1, column=0)
root.mainloop()
You can use Object orient methodology to make access sympler, another option also you can use globals() to make variable global
One way
globals()['user_message_entry'] = tk.Text(message_frame, height=10, width=60)
....
and from another function you can call
body = globals()['user_message_entry'].get("1.0", "end")
Second way
Object oriented programming is good for every type of problem solving, so you can use class as well
import tkinter as tk
class CBased:
def __init__(self, master, *args, **kwargs):
super(CBased, self).__init__(*args, *kwargs)
self.master = master
master.geometry("500x500")
self.open_feedback_button = tk.Button(master, command=self.feedback, height=20, width=20, bg="yellow", text="open feedback window")
self.open_feedback_button.grid(row=1, column=0)
def send_email(self):
subject = ":)"
body = self.user_message_entry.get("1.0", "end")
message = f"subject: {subject}\n\n {body}"
print(message)
def feedback(self):
self.feedback_window = tk.Toplevel()
self.feedback_window.geometry("690x650")
self.message_frame = tk.Frame(self.feedback_window)
self.message_frame.grid(row=0, column=0, columnspan=3)
self.user_message_entry = tk.Text(self.message_frame, height=10, width=60)
self.user_message_entry.grid(row=0, column=0)
self.send_email_button = tk.Button(self.feedback_window, command=send_email,
height=20, width=20, bg="yellow", text="send email")
self.send_email_button.grid(row=1, column=0)
def main():
root = Tk()
myobj = CBased(root)
root.mainloop()
if __name__ == "__main__":main()
In this way you can call every single item by self.xyz
I have the following code, which causes a color/text change when a Tkinter button is clicked. I would like to revert to the original color/text when the button is clicked a second time.
from Tkinter import *
window = Tk()
window.title("Start/Stop Button")
window.geometry('200x100')
def clicked_rf1():
btn_rf1.configure(text="Stop")
lbl_rf1.configure(text=" ON ", bg="green")
btn_rf1 = Button(window, text="Start", command=clicked_rf1)
btn_rf1.grid(column=1, row=1)
lbl_rf1 = Label(window, text=" OFF ", bg="red")
lbl_rf1.grid(column=2, row=1)
window.mainloop()
I want something that behaves a little more like a toggle, but I would like the look of a button.
Help gratefully received.
You will need an if block to choose what to do. You can make another flag variable to keep track of the state, or just use the current Label or Button text:
from Tkinter import *
window = Tk()
window.title("Start/Stop Button")
window.geometry('200x100')
def clicked_rf1():
if btn_rf1['text'] == "Start":
btn_rf1.configure(text="Stop")
lbl_rf1.configure(text=" ON ", bg="green")
else:
btn_rf1.configure(text="Start")
lbl_rf1.configure(text=" OFF ", bg="red")
btn_rf1 = Button(window, text="Start", command=clicked_rf1)
btn_rf1.grid(column=1, row=1)
lbl_rf1 = Label(window, text=" OFF ", bg="red")
lbl_rf1.grid(column=2, row=1)
window.mainloop()
This would be an ideal place to make a custom Button subclass, so you could have many of these in your program:
from Tkinter import *
window = Tk()
window.title("Start/Stop Button")
window.geometry('200x100')
class Christina(Frame):
def __init__(self, master=None, **kwargs):
Frame.__init__(self, master, **kwargs)
self.btn = Button(self, text="Start", command=self.clicked)
self.btn.grid(column=0, row=0)
self.lbl = Label(self, text=" OFF ", bg="red")
self.lbl.grid(column=1, row=0)
def clicked(self):
if self.btn['text'] == "Start":
self.btn.configure(text="Stop")
self.lbl.configure(text=" ON ", bg="green")
else:
self.btn.configure(text="Start")
self.lbl.configure(text=" OFF ", bg="red")
btn1 = Christina(window)
btn1.grid()
btn2 = Christina(window)
btn2.grid()
btn3 = Christina(window)
btn3.grid()
window.mainloop()
If you want a toggle, you can use the checkbutton without an indicator. It has options for the color in the selected and deselected state, and you can tie the value and the label together so that the label changes when you toggle the button.
Like any button, you can tie a command to it. The command can check the value of the variable to determine whether it should do the "on" function or the "off" function.
Here's a simple example:
import Tkinter as tk
def toggle():
if var.get() == "ON":
print("turning on...")
else:
print("turning off...")
root = tk.Tk()
var = tk.StringVar()
toggle = tk.Checkbutton(root, onvalue="ON", offvalue="OFF", width=4,
indicatoron=False,
variable=var, textvariable=var,
selectcolor="green", background="red",
command=toggle)
var.set("OFF")
toggle.pack()
root.mainloop()
Another approach might be to put the "pile of code" to run into different function, collect those in an iterator, and then get the next function from that iterator and execute it:
def bunchofcode():
print("foo")
def somethingelse():
print("bar")
whattodo = iter([bunchofcode, somethingelse])
def clicked_rf1():
try:
next(whattodo)()
except StopIteration:
print("nothing to do")
Or for cyclic behaviour:
from itertools import cycle
whattodo = cycle([bunchofcode, somethingelse])
For a two-state toggle button, you could also use a dict to map the current state to the next. You could also use the button's relief to mark the state.
def clicked_rf1():
transition = {"raised": "sunken", "sunken": "raised"}
btn_rf1["relief"] = transition[btn_rf1["relief"]]
I have only one while loop and the Tkonter say: GUI is not responding.
What I'm doing wrong ? I would like with button "Pause" break and
again with "button "Start" continue the program.
import Tkinter, time
root = Tkinter.Tk
class InterfaceApp(root):
def __init__ (self, parent):
root.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
self.but_state = 0
self.but_start = Tkinter.Button(self, text='Start', command=lambda: self.Start(), width=10)
self.but_pause = Tkinter.Button(self, text="Pause", command=lambda: self.Pause(), width=10)
self.but_stop = Tkinter.Button(self, text='Stop', command=lambda: self.Stop(), width=10)
self.but_start.grid(row=1, column=1, sticky='W')
self.but_pause.grid(row=1, column=2, sticky='W')
self.but_stop.grid(row=1, column=3, sticky='W')
def Start(self):
while True:
print "X"
time.sleep(2)
if self.but_state == 1:
break
else:
continue
def Stop(self):
self.but_state = 1
def Pause(self):
pass
if __name__ == "__main__":
app = InterfaceApp(None)
app.title("MPW4 microHP - Long Term Test")
app.mainloop()
First issue:
Using the while loop. To call a function again after it finished use
self.after(<time in ms>, <function to call>)
at the end of your def Start(self)
Would look like this:
# ...
def Start(self):
print("X")
if self.but_state == 0:
self.after(2000, self.Start)
# ...
Second Issue:
Do not use lambdas for simple calls. Use the name for the binding instead, just like #Parviz_Karimli pointed out.
def initialize(self):
self.but_state = 0
self.but_start = Tkinter.Button(self, text='Start', command=self.Start, width=10)
self.but_pause = Tkinter.Button(self, text="Pause", command=self.Pause, width=10)
self.but_stop = Tkinter.Button(self, text='Stop', command=self.Stop, width=10)
self.but_start.grid(row=1, column=1, sticky='W')
self.but_pause.grid(row=1, column=2, sticky='W')
self.but_stop.grid(row=1, column=3, sticky='W')
Your code is nonsense. You have to figure out how to define functions and use them properly first. I wrote a little example for you:
from tkinter import *
class App:
def __init__(self, master):
self.master = master
self.startb = Button(master, text="Start", command=self.startf)
self.startb.pack()
self.pauseb = Button(master, text="Pause", command=self.pausef)
self.pauseb.pack()
self.stopb = Button(master, text="Stop", command=self.stopf)
self.stopb.pack()
def startf(self):
print("Started")
self.after_id = self.master.after(1000, self.startf)
def pausef(self):
if self.startf is not None: # to handle any exception
self.master.after_cancel(self.after_id) # this will pause startf function -- you can start again
print("Paused")
def stopf(self):
if self.startf is not None:
self.master.after_cancel(self.after_id)
self.startf = None # this will stop startf function -- you cannot start again
print("Stopped")
root = Tk()
myapp = App(root)
root.mainloop()
Then you can modify this code -- change the behaviors of the functions etc. If you have a working piece of code which will behave as the "motor" function that does the core idea of your program, include that function in as well, and return it in the startf function, pause it in the pausef function, and finally, stop it in the stopf function.
P.S.: My code was written in Python 3.
EDIT: I completed the code and above is a working program that starts, pauses and stops depending on the button you click.
I'm trying to make my first GUI program. The problem is, that I can't figure out how to make a main menu, which would switch to one of the programs after clicking a button.
#Dev by Mkee
from Tkinter import *
import tkMessageBox
#Main Stuff
app = Tk()
app.title("Mkee's Tools")
app.geometry('300x200')
#modules
class Programs:
def Shuffle():
app2 = Tk()
app2.title("Shuffle")
app2.geometry('300x200')
app2.mainloop()
#end of modules
labelText = StringVar()
labelText.set('')
label1 = Label(app, textvariable=labelText, height=4)
label1.pack()
button1 = Button(app, text='Shuffle', width=30, command=Programs.Shuffle)
button1.pack(side='right', padx=5,pady=1)
app.mainloop()
I know that I'm doing it wrong. I just have no idea how to do it, So i gave it a try of how could it be. Please help me.
You could call pack_forget() to hide widgets, and (later)
pack to show them again:
Tkinter is singled-threaded, and mainloop runs the main event loop. Therefore you shouldn't call mainloop twice.
#Dev by Mkee
import Tkinter as tk
import sys
class Shuffle(object):
def __init__(self,master=None):
self.master=master
self.text=tk.Text(master)
def hide(self):
self.text.pack_forget()
def show(self):
self.text.pack(side=tk.LEFT, padx=5, pady=5)
class Buttons(object):
def __init__(self,master=None):
self.master=master
self.red = tk.Button(self.master, text="Red", bg="red", fg="white")
self.green = tk.Button(self.master, text="Green", bg="green", fg="black")
self.blue = tk.Button(self.master, text="Blue", bg="blue", fg="white")
def hide(self):
self.red.pack_forget()
self.green.pack_forget()
self.blue.pack_forget()
def show(self):
self.red.pack(side=tk.LEFT,expand=tk.YES,fill=tk.BOTH)
self.green.pack(side=tk.LEFT,expand=tk.YES,fill=tk.BOTH)
self.blue.pack(side=tk.LEFT,expand=tk.YES,fill=tk.BOTH)
class MainApp(object):
def __init__(self,master=None):
self.master=master
app=self.app=tk.Tk()
app.title("Mkee's Tools")
app.geometry('300x200')
self.shuffle=Shuffle(master)
self.buttons=Buttons(master)
self.current=None
menubar=tk.Menu(app)
program_menu=tk.Menu(menubar)
program_menu.add_command(label='Shuffle',
command=lambda: self.show(self.shuffle))
program_menu.add_command(label='Buttons',
command=lambda: self.show(self.buttons))
program_menu.add_command(label='Quit',command=sys.exit)
menubar.add_cascade(label='Programs', menu=program_menu)
app.config(menu=menubar)
def show(self,obj):
if self.current != obj:
try: self.current.hide()
except AttributeError: pass
self.current=obj
obj.show()
def main():
m=MainApp()
m.app.mainloop()
if __name__=='__main__':
main()