tkinter button in class won't bind to key - python

Total noob can't make tkinter button bind to keyboard.
I've tried to bind they both in main() and in the init().
I've tried bunches of permutations of syntax. Nothing works.
I've tried around until the button(s) get focus and hitting then. NOTHING HAPPENS.
Anyone have the secret insider information on how to do it?
from tkinter import *
from tkinter.ttk import Frame, Button, Style
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
self.btn_convert.bind("<Return>", self.convert)
# -----------------------------------------------
def convert(self):
print("enter pressed")
# -----------------------------------------------
def quit(self):
self.root.destroy()
exit()
# -----------------------------------------------
def initUI(self):
self.master.title("Weight Converter")
self.pack(fill=BOTH, expand=True)
self.frame_btn = Frame(self)
self.frame_btn.pack(fill=BOTH, expand=True, padx=20, pady=5)
self.btn_convert=Button(self.frame_btn, text="Convert", command=self.convert)
self.btn_convert.pack(side=LEFT, padx=5, pady=5)
self.btn_close1=Button(self.frame_btn, text="Close", command=quit)
self.btn_close1.pack(side=LEFT, padx=5, pady=5)
def main():
root = Tk()
root.geometry("300x250+300+200")
app = Example()
root.bind("<Return>", lambda event: root.convert())
root.mainloop()
if __name__ == '__main__':
main()

Replace:
root.bind("<Return>", lambda event: root.convert())
with:
root.bind("<Return>", lambda event: app.convert())
or:
#in case you have multiple instances of Tk
app.bind("<Return>", lambda event: app.convert())
app.focus_set()
As convert is a method for Example instance(app) as opposed to Tk instance(root). Also, make sure that the object.bind is used on(root in above two lines and app onthe last line) has the focus by either manually focusing or calling object.focus_set().
Below is an example that prints "Enter" or "Escape" based on the keypress:
import tkinter as tk
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.button = tk.Button(self, text="Event")
self.button.bind('<Return>', lambda evt : self.event_handler(True))
self.button.focus_set() # ensure initial focus is on the button
self.button.pack()
def event_handler(self, is_enter):
if is_enter:
my_string = "Enter"
else:
my_string = "Escape"
print(my_string)
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
app.button.bind('<Escape>', lambda evt : app.event_handler(False))
app.pack()
root.mainloop()
Demo Example for all keys
Below demo should be displaying the pressed key for all keys:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def on_key_press(event):
global label
label['text'] = event.keysym
if __name__ == '__main__':
root = tk.Tk()
label = tk.Label(root)
root.bind('<KeyPress>', on_key_press)
label.pack()
root.mainloop()

To add a general "press Enter to run convert" binding, you should apply it to root. To add further focus-based bindings, you should apply them on a per-button basis, like so:
from tkinter import *
from tkinter.ttk import Frame, Button, Style
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
# -----------------------------------------------
def convert(self):
print("enter pressed")
# -----------------------------------------------
def quit(self):
print("quit pressed")
self.destroy()
exit()
# -----------------------------------------------
def initUI(self):
self.master.title("Weight Converter")
self.pack(fill=BOTH, expand=True)
self.frame_btn = Frame(self)
self.frame_btn.pack(fill=BOTH, expand=True, padx=20, pady=5)
self.btn_convert=Button(self.frame_btn, text="Convert", command=self.convert)
self.btn_convert.pack(side=LEFT, padx=5, pady=5)
self.btn_close1=Button(self.frame_btn, text="Close", command=quit)
self.btn_close1.pack(side=LEFT, padx=5, pady=5)
# When tab focus is on the "Close" button, change Return behaviour.
self.btn_close1.bind("<Return>", lambda event: self.quit())
def main():
root = Tk()
root.geometry("300x250+300+200")
app = Example()
root.bind("<Return>", lambda event: app.convert())
root.mainloop()
if __name__ == '__main__':
main()

Related

Tkinter - How to bind <Button-1> and call a function

I am trying to get the following code to work where event calls a function to clear an entry box. Can someone tell me what I am doing wrong. I am not too familiar with Tkinter.
import tkinter as tk
from tkinter import *
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.master.title("Create Trusted Facts")
self.pack(fill=BOTH, expand=True)
frame2 = Frame(self)
frame2.pack(fill=X)
reqSumLbl = Label(frame2, text="Request Summary", width=22)
reqSumLbl.pack(side='left', padx=5, pady=5)
reqSumBox = Entry(frame2, width=100, bg="White", fg="lightgrey", borderwidth=1)
reqSumBox.insert(0, "Enter the Request Summary here")
reqSumBox.pack(fill=X, padx=50, pady=5, expand=True)
reqSumBox.bind("<Button-1>", self.clear_reqSumBox)
def clear_reqSumBox(self, reqSumBox):
reqSumBox.delete(0, END)
reqSumBox.config(fg="black")
global SummaryText
SummaryText = reqSumBox.get()
def main():
root = Tk()
root.geometry("500x550+350+50")
app = Example()
root.mainloop()
if __name__ == '__main__':
main()
reqSumBox.bind("<Button-1>", self.clear_reqSumBox)
When binding any event to a function, it automatically needs to take in a parameter called event, there are 2 ways to fix your code.
1.
reqSumBox.bind("<Button-1>", lambda event: self.clear_reqSumBox)
Make lambda function which takes in event and calls function.
2.
def reqSumBox(self, reqSumBox, event=None)
Add optional event parameter in reqSumBox function.
I personally use the first one.
First of all, why do you have two imports at the start of your Python script at they're both the same library, choose one it's incorrect.
About your question, it fails because you didn't provide the clicked object, it provided you as the first argument of the bind function the Event that happened.
I recommend you make your object a part of your current working class (Class Example), like that:
import tkinter as tk
from tkinter import *
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.master.title("Create Trusted Facts")
self.pack(fill=BOTH, expand=True)
frame2 = Frame(self)
frame2.pack(fill=X)
reqSumLbl = Label(frame2, text="Request Summary", width=22)
reqSumLbl.pack(side='left', padx=5, pady=5)
# Check my changes here.
self.reqSumBox = Entry(frame2, width=100, bg="White", fg="lightgrey", borderwidth=1)
self.reqSumBox.insert(0, "Enter the Request Summary here")
self.reqSumBox.pack(fill=X, padx=50, pady=5, expand=True)
self.reqSumBox.bind("<Button-1>", self.clear_reqSumBox)
# Changed the argument name to "event".
def clear_reqSumBox(self, event):
self.reqSumBox.delete(0, END)
self.reqSumBox.config(fg="black")
def main():
root = Tk()
root.geometry("500x550+350+50")
app = Example()
root.mainloop()
if __name__ == '__main__':
main()
Check where I comment and analyze this code.
The callback of bind() requires an argument which is the event object. So modify the callback function definition as below:
def clear_reqSumBox(self, event):
# get the widget triggering this event
reqSumBox = event.widget
reqSumBox.delete(0, END)
reqSumBox.config(fg="black")
# after that reqSumBox.get() will return empty string
global SummaryText
# SummaryText = "" will have same result of below line
SummaryText = reqSumBox.get()
However the entry will be cleared whenever you click on the entry. Is it really what you want?

How to export inputted parameters with python tkinter?

I apologies because I'm a new user for python tkinter.
It is possible to export data inputted with Entry function?
Currently the code works, but the value is not present in the "e1" output.
Thanks in advance
try:
import Tkinter as tk
except:
import tkinter as tk
class Test():
def __init__(self):
self.root = tk.Tk()
self.root.geometry('100x50')
e1 = tk.Entry(self.root)
e1.pack()
self.e1 = e1.get()
button = tk.Button(self.root,
text = 'Quit and take out values',
command=self.quit)
button.pack()
self.root.mainloop()
def quit(self):
self.root.destroy()
app = Test()
print(app.e1)
You call e1.get() right after e1 is created. So at that time there is nothing input and you should get an empty string.
You can get the entry value inside quit() function, but you need to rename e1 to self.e1:
try:
import Tkinter as tk
except:
import tkinter as tk
class Test():
def __init__(self):
self.root = tk.Tk()
self.root.geometry('100x50')
self.e1 = tk.Entry(self.root)
self.e1.pack()
button = tk.Button(self.root,
text = 'Quit and take out values',
command=self.quit)
button.pack()
self.root.mainloop()
def quit(self):
self.value = self.e1.get()
self.root.destroy()
app = Test()
print(app.value)

I have too fix something in my Copy&Paste program in Python

This is my Copy&Paste program:
from tkinter import *
import Pmw
class CopyTextWindow(Frame):
def __init__(self):
Frame.__init__(self)
Pmw.initialise()
self.pack(expand=YES, fill=BOTH)
self.master.title("ScrolledText Demo")
self.frame1=Frame(self, bg="White")
self.frame1.pack(expand=YES, fill=BOTH)
self.text1=Pmw.ScrolledText(self, text_width=25, text_height=12, text_wrap=WORD,
hscrollmode="static", vscrollmode="static")
self.text1.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)
options = ["Copy", "Paste"]
self.selectedOption = StringVar()
self.menu = Menu(self.frame1, tearoff=0)
for option in options:
self.menu.add_radiobutton( label=option, variable=self.selectedOption,
command=self.ExecuteOption)
self.text1.bind("<Button-3>", self.popUpMenu)
def popUpMenu(self, event):
self.menu.post(event.x_root, event.y_root)
def ExecuteOption(self):
if self.selectedOption.get()=="Copy":
self.CopiedText=self.text1.get(SEL_FIRST, SEL_LAST)
else:
self.text1.settext( self.text1.get()+self.CopiedText)
def main():
CopyTextWindow().mainloop()
if __name__=="__main__":
main()
In this program, I want to make a GUI, that in it you can copy and paste text that you have selected. when you press the right mouse button, a little menu with the Copy and Paste options.
The program opens up, but when I press the right mouse button, no menu appears. Python also doesn't complain with an error.
I need to understand my mistake in this code.
For a reason I ignore, the event doesn't seem to be triggered when the bind is on the Text or on the Frame, but it works when it's on the main window:
from tkinter import *
import Pmw
class CopyTextWindow(Frame):
def __init__(self, master=None):
# I've added a master option to pass to the frame
Frame.__init__(self, master)
Pmw.initialise()
self.pack(expand=YES, fill=BOTH)
self.master.title("ScrolledText Demo")
self.frame1=Frame(self, bg="White")
self.frame1.pack(expand=YES, fill=BOTH)
self.text1=Pmw.ScrolledText(self, text_width=25, text_height=12, text_wrap=WORD,
hscrollmode="static", vscrollmode="static")
self.text1.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)
options = ["Copy", "Paste"]
self.selectedOption = StringVar()
self.menu = Menu(self.frame1, tearoff=0)
for option in options:
self.menu.add_radiobutton( label=option, variable=self.selectedOption,
command=self.ExecuteOption)
def popUpMenu(self, event):
print("ok")
self.menu.post(event.x_root, event.y_root)
def ExecuteOption(self):
if self.selectedOption.get()=="Copy":
self.CopiedText=self.text1.get(SEL_FIRST, SEL_LAST)
else:
self.text1.settext( self.text1.get()+self.CopiedText)
def main():
# main window
root = Tk()
ctw = CopyTextWindow(root)
# bind on the main window
root.bind("<Button-3>", ctw.popUpMenu)
root.mainloop()
if __name__=="__main__":
main()

Python: Tkinter OK button callback function

I'm working on my very first Python GUI and I'm trying to modify this tkinter example, but I simply cannot figure out how to write a callback function for the OK button that will pass on the entered value to the main program.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
value=StringVar(None)
value.set("this is the default value")
valueEntry=Entry(self, textvariable=value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.quit)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
I've read a gazillion of tutorials, but none of them explains this clearly. Theoretically, I should be able to get the selected value with value.get(), but I keep getting error messages no matter where I put it. Also, AFAIK, I should be able to define a default value with value.set(), but this doesn't seem to have an effect, since the text box is empty when I run the program.
What is the easiest way to pass on values to the main python program after root.mainloop() terminates? (The actual dialog box contains several entry boxes for entering string and integer values.)
I.e. I want to be able to use something like:
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
print value
print value2
print value3
How do I define default values for entry boxes?
Change every occurrence of the value variable with self.value. This should fix it and the default value will be displayed.
UPDATE
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def showMe(self):
print(self.value.get())
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
self.value=StringVar(None)
self.value.set("this is the default value")
valueEntry=Entry(self, textvariable=self.value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.showMe)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Both your quitButton and okButton call the self.quit functions. So no mater what value you enter when you press the OK button you are calling the quit function which has its own problems as well outside the scope of your question.
Try to define value as self.value and make the okButton call a function that does: print self.value.get().

Tkinter (python 2.7.2) Help needed

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()

Categories

Resources