I would like to remove the highlighting from my combobox widget when the user selects an option. But the method select_clear() doesn't seem to be working :(
Any clues why ?
from tkinter import *
from tkinter.ttk import Combobox
class hey(Frame):
def __init__(self):
Frame.__init__(self)
self.comboboxVariable = StringVar()
values = (1, 2, 3, 4, 5)
self.comboBox = Combobox(self, textvariable = self.comboboxVariable, values = values, state = 'readonly')
self.comboBox.pack()
self.comboBox.bind("<<ComboboxSelected>>", self.updateData)
def updateData(self, event =None):
self.comboBox.select_clear()
myClass = hey()
myClass.pack()
root = myClass.master
root.mainloop()
What you are trying to do and what your script is attempting to do are two different things. First, you have event = None, which causes the function to be called when you first initialize an object and then never again. Instead, leave the function attribute just as 'event' so that it runs when the specified event takes place.
To remove the selection made, your updateData function would look like the following:
def updateData(self, event):
self.comboBox.set("")
However, to remove the highlighting from the chosen value, you would need to change the focus from the combobox to the root window:
def updateData(self, event):
self.focus_set()
Hope this helps.
Related
I am not allowed to add images yet to question posts.
Question below:
My app currently uses a window that is coded in a class.
My ultimate goal is to press enter while entering letters and numbers into an entry widget and press enter, then the function would update text that correlates to a label in my main window.
Detailed description below:
I cannot figure out how to create and entry and then bind the enter key so that when I run my app, I can click in the entry, type a value and press enter.
I see plenty of button references and I can get the button to work, but I am trying to learn how to do things and do not want to rely on buttons in this instance.
I saw in some other posts that if you call .get with an entry object, that the python code will just execute it and move on. I tested with a print statement in the function I want to call upon pressing enter, and the print statement appeared in the terminal before I typed anything in the entry widget. I then tried to type and press enter, and nothing would occur.
Should I abandon binding the ENTER key and stick with buttons in tkinter as a rule, or is there a proper way to do this? In my code example, you will see up_R is the function I am trying to execute when pressing Enter. If I use up_R(), it executes immediately. If I use up_R, then I get a TCL Error.
Specific Partial code located below:
def up_R():
print('Makes it here')
self.R.update_disp(self.e.get())
self.e.bind('<ENTER>',up_R)
The full code is below if required for assistance:
#NOAA SPACE WEATHER CONDITIONS
from tkinter import *
class window:
def __init__(self):
#main window
self.window = Tk()
self.window.title('NOAA SPACE WEATHER CONDITIONS')
self.window.geometry('800x600')
#window organization
self.window.grid_rowconfigure(0, weight = 1)
self.window.grid_rowconfigure(1, weight = 1)
self.window.grid_columnconfigure(0, weight = 1)
self.window.grid_columnconfigure(1, weight = 1)
#temp entry frame
self.e = Entry(self.window)
self.e.grid(row = 1, column = 0, sticky=N)
self.e.insert(END, 'R entry')
#init class R
self.R = R()
#init class S
self.S = S()
#init class g
self.G = G()
#frame for RSG
self.frame = Frame(self.window)
self.frame.grid(row = 0, column = 0, columnspan = 2, padx=10, pady=10)
#disp class R
self.rf = Frame(self.frame, highlightbackground='black', highlightcolor='black', highlightthickness=1)
self.rf.pack(side = LEFT)
self.rl = Label(self.rf, text = self.R.dkey, bg='#caf57a')
self.rl.pack(side=TOP)
self.rl_lower = Label(self.rf, text= self.R.tile_text, bg='#caf57a')
self.rl.pack(side=BOTTOM)
#Value update methods
# self.R.update_disp(self.e.get())
# #action
def up_R():
print('Makes it here')
self.R.update_disp(self.e.get())
self.e.bind('<ENTER>',up_R())
#main window call - goes at end of class
self.window.mainloop()
class R:
def __init__(self):
d = {'R':'None','R1':'Minor','R2':'Moderate','R3':'Strong','R4':'Severe','R5':'Extreme'}
self.dkey = 'R'
self.tile_text = d[self.dkey]
print(d[self.dkey])
def update_disp(self, dkey):
self.dkey = dkey
class S:
d = {'S1':'Minor','S2':'Moderate','S3':'Strong','S4':'Severe','S5':'Extreme'}
pass
class G:
d = {'G1':'Minor','G2':'Moderate','G3':'Strong','G4':'Severe','G5':'Extreme'}
pass
t = window()
The ENTER should be changed with Return, and the function should accept an event
Also, don't forget in a 'class' to use self in the method and self.method to call it.
def up_R(self, event):
print('Makes it here')
self.R.update_disp(self.e.get())
self.rl.config(text=self.R.dkey)
self.e.bind('<Return>', self.up_R)
i have defined a GUI class that creates a tkinter window with a couple of entries. I would like that every time that the user overwrites the Entries and press Enter, there is some operation done in the background. In addition, i would like that the entries are checking regularly certain values and updating them, so the user could see if they changed; In the example below i use a static dictionary, but normally those parameters are obtained from a camera and could fluctuate.
However, i am not even able to get the correct value printed in the label. I am not a tkinter expert so any idea would be appreciated
from tkinter import *
class GUI():
def __init__(self, window, window_title,input_dict):
self.window = window
self.window.title(window_title)
self.window.geometry('400x200')
top_frame = Frame(self.window)
top_frame.pack(side=TOP, pady=5)
Label(top_frame, text="Frame rate (fps)").grid(row=0)
Label(top_frame, text="Exposure time (ms)").grid(row=2)
self.labeling=Label(top_frame, text="Result").grid(row=3)
self.e1_var = StringVar() # or StringVar(top)
self.e1_var.set(str(round(input_dict['frameRate'])))
self.e2_var = StringVar() # or StringVar(top)
# print(type(self.e2_var))
self.e2_var.set(str(round(input_dict['Exp_time'])))
self.fps_entry = Entry(top_frame,textvariable=self.e1_var)
self.exptime_entry = Entry(top_frame,textvariable=self.e2_var)
self.fps_entry.bind("<Return>",self.my_tracer)
self.exptime_entry.bind("<Return>",self.my_tracer)
self.fps_entry.grid(row=0, column=1)
self.exptime_entry.grid(row=2, column=1)
self.window.mainloop()
def my_tracer(self,event):
val1=int(self.e1_var.get())
val2=int(self.e2_var.get())
self.labeling.configure(text=str(val1*val2))
input_dict = {
'frameRate': 50,
'Exp_time': 5000}
video_object=GUI(Tk(),"Test",input_dict)
The error your code produces is AttributeError: 'NoneType' object has no attribute 'configure', right?
Look at this line:
self.labeling=Label(top_frame, text="Result").grid(row=3)
self.labeling will be None because grid() returns None. It is indeed bad practice to 'chain' a geometry manager to the creation of a widget. Change to:
self.labeling=Label(top_frame, text="Result")
self.labeling.grid(row=3)
Now the labels are updating when the user enters a new value.
I am creating a global dictionary of data from which I will display various data in my dictionary. Two elements of the dictionary are a list and a Boolean Variable. I want to use the BooleanVar() in a CheckButton widget.
The dictionary is to store information from various machine subsystems that I want to display in my gui. One function of the gui is to be able to exclude a channel if the user wishes, meaning stop monitoring.
The machine channel is the dictionary key, with a list and a boolean varaible. The list is contains some initial data to determine the status of the channel. The BooleanVar() I want to add to a checkbutton so the user can toggle between excluding/including the channel gui.
channelListFull = {'sys1:channel1': (['Label1', 'GOOD', 0, 0],BooleanVar()),
'sys1:channel2': (['Label2', 'GOOD', 0, 0],BooleanVar()),
'sys2:channel1': (['Label3', 'GOOD', 0, 0],BooleanVar())
etc...
The rest of the code (roughly, not exactly executable) is as follows
class ChannelDisplay(Frame)
def __init__(self, master=None, label='NONE', channel='NONE',**kw):
Frame.__init(self, master, **kw)
self.lbl = label
self.chnl = channel
self.component = tk.Label(self, text=self.lbl)
self.component.grid
self.toggle = tk.Checkbutton(self,variable=channelListFull[channel][1])
self.toggle.grid
class Application(Frame):
def __init__(self,master=None):
Frame.__init__(self,master)
self.monitoring()
def monitor(self):
channelRemoveList = []
for entry in channelListFull.keys():
badChannel = channelListFull[entry][1].get()
if not badChannel :
channelRemoveList.append(entry) #This is a separate function
that modifies which channels
are included in the monitoring
process
for entry in channelListFull.keys():
self.chan = ChannelDisplay(root,label=channelListFull[0][0],channel=entry)
self.chan.grid()
root = Tk()
app=application(master=root)
app.mainloop()
I get the error at the line where I create channelListFull saying:
Exception AttributeError: "BooleanVar instance has no attribute '_tk'" in
<bound method BooleanVar.__del__ of <Tkinter.BooleanVar instance at 0x7f39981b77e8>>
ignored
Can I initiate a Tk Variable before I start my Tk widgets and windows?
No, you cannot. You must create a root window first.
I am trying to make a button that when clicked updates the number on a label. What I am trying to accomplish is that when someone scores a goal, you can click the Goal! button and it will update the teams score.
import sys
from tkinter import *
root = Tk()
class team1:
score = 0
def goal(self):
self.score += 1
team1_attempt.set(text = self.score)
team1 = team1()
team1_attempt = Label(text = team1.score).pack()
team1_button = Button(text="Goal!", command = team1.goal).pack()
Hope someone can help! New to python.
You have two problems with your code.
First problem:
team1_attempt = Label(text = team1.score).pack()
This sets team1_attempt to None, because pack(0 returns None. If you want to save a reference to a widget so you can interact with it later you must do widget creation and widget layout in two steps.
Second problem:
team1_attempt.set(text = self.score)
To change an attribute of a widget, use the configure method. I don't know what documentation you read that says to call set on a label widget, but that documentation is wrong. Use configure, like so:
test1_attempt.configure(text=self.score)
Instead of using a label, try using an Entry widget that inserts the score into the Entry widget. For example:
class test:
def __init__(self, master):
self.goalButton = Button(master,
text = "goal!",
command = self.goalUpdate)
self.goalButton.pack()
self.goalDisplay = Entry(master,
width = 2)
self.goalDisplay.pack()
self.score = 0
def goalUpdate(self):
self.goalDisplay.delete(1.0, END) # Deletes whatever is in the score display
score = str(self.score)
self.goalDisplay.insert(0, score) # Inserts the value of the score variable
I'm developing a package with GUI using tkinter. Now there is a problem when communicating classes via tkinter's bind method. A simple code which represents what I want to do is listed below:
import Tkinter as tk
lists = [1,2,3,4,5,6,7]
class selects():
def __init__(self,root):
self.root = root
self.selectwin()
def selectwin(self):
""" listbox and scrollbar for selection """
sb = tk.Scrollbar(self.root)
lb = tk.Listbox(self.root, relief ='sunken', cursor='hand2')
sb.config(command=lb.yview)
sb.pack(side=tk.RIGHT, fill=tk.Y)
lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
lb.config(yscrollcommand=sb.set, selectmode='single')
for value in lists: lb.insert(tk.END,value)
lb.bind('<Double-1>',lambda event: self.getvalue())
self.listbox = lb
def getvalue(self):
""" get the selected value """
value = self.listbox.curselection()
if value:
self.root.quit()
text = self.listbox.get(value)
self.selectvalue = int(text)
def returnvalue(self):
return self.selectvalue
class do():
def __init__(self):
root = tk.Tk()
sl = selects(root)
# do something... for example, get the value and print value+2, as coded below
value = sl.returnvalue()
print value+2
root.mainloop()
if __name__ == '__main__':
do()
class selects adopt Listbox widget to select a value in lists and return the selected value for use via attribute returnvalue. However, error is raised when running the above codes:
Traceback (most recent call last):
File "F:\Analysis\Python\fpgui\v2\test2.py", line 47, in <module>
do()
File "F:\Analysis\Python\fpgui\v2\test2.py", line 41, in __init__
value = sl.returnvalue()
File "F:\Analysis\Python\fpgui\v2\test2.py", line 32, in returnvalue
return self.selectvalue
AttributeError: selects instance has no attribute 'selectvalue'
I think this error can be solved by combining classes selects and do together as a single class. But in my package, class selects will be called by several classes, so it is better to make selects as a standalone class. Further, communications between classes like this will be frequently applied in my package. For example, do something after picking some information in matplotlib figure using pick_event, or update a list in one class after inputting texts in another class using Entry widget. So, any suggestion about this? Thanks in advance.
You're calling sl.returnvalue() right after having created sl. However, at this point sl.getvalue() has never been called, which means that sl.selectvalue does not yet exist.
If I understand what you want to do correctly, you should move the call to root.mainloop() to right after the creation of sl (sl = selects(root)). This way, Tk hits the mainloop, which runs until the window is destroyed, which is when the user double-clicks one of the values. Then, sl.getvalue() has been run and the program can continue with calling sl.returnvalue() without errors.
Since you are not actually calling the mainloop in that part of the code, I've altered your code to reflect that and still work as you want it to. A key method in this is wait_window, which halts execution in a local event loop until the window is destroyed. I've used this effbot page on Dialog Windows for reference:
import Tkinter as tk
lists = [1,2,3,4,5,6,7]
class selects():
def __init__(self,root):
self.root = root
self.selectwin()
def selectwin(self):
""" listbox and scrollbar for selection """
sb = tk.Scrollbar(self.root)
lb = tk.Listbox(self.root, relief ='sunken', cursor='hand2')
sb.config(command=lb.yview)
sb.pack(side=tk.RIGHT, fill=tk.Y)
lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
lb.config(yscrollcommand=sb.set, selectmode='single')
for value in lists: lb.insert(tk.END,value)
lb.bind('<Double-1>',lambda event: self.getvalue())
self.listbox = lb
def getvalue(self):
""" get the selected value """
value = self.listbox.curselection()
if value:
self.root.quit()
text = self.listbox.get(value)
self.selectvalue = int(text)
self.root.destroy() # destroy the Toplevel window without needing the Tk mainloop
def returnvalue(self):
return self.selectvalue
class do():
def __init__(self, master):
self.top = tk.Toplevel()
self.top.transient(master) # Make Toplevel a subwindow ow the root window
self.top.grab_set() # Make user only able to interacte with the Toplevel as long as its opened
self.sl = selects(self.top)
self.top.protocol("WM_DELETE_WINDOW", self.sl.getvalue) # use the if value: in getvalue to force selection
master.wait_window(self.top) # Wait until the Toplevel closes before continuing
# do something... for example, get the value and print value+2, as coded below
value = self.sl.returnvalue()
print value+2
if __name__ == '__main__':
root = tk.Tk()
d = do(root)
root.mainloop()