Display objects attributes in tkinter label - python-3.x

I would like a label that updates when I push a button. The label is a formated string that prints some attributes of an object.
This is what I tried. It displays properly but won't update.
from class_mnoply import *
from tkinter import *
Player1=Player("Hat")
message=str('''
____________________
{0}
Bank account: ${1}
Dice1: {2}
Dice2: {3}
____________________
'''.format(Player1.name, Player1.bank, Player1.dice1, Player1.dice2))
mainWin = Tk()
topFrame=Frame(mainWin)
topFrame.pack(side=TOP)
button1 Button(mainWin,text="ThrowDice",fg="red",command=Player1.rollDice())
button1.pack(side=BOTTOM)
plLabel = Label(mainWin, textvariable=message)
plLabel.pack()
mainWin.mainloop()

You have 1 typo in the following statement and 1 potential error:
button1 Button(mainWin,text="ThrowDice",fg="red",command=Player1.rollDice())
Can you guess what is the typo? If no, you are just missing the = sign.
On the other hand, you are assigning the return value of Player1.rollDice() to command, but this is not what you want. What you want is just set the Player1.rollDice method as the command that is called when button1 is pressed. Here's the correct syntax (note the absence at the end of ()):
button1 = Button(mainWin,text="ThrowDice",fg="red",command=Player1.rollDice)
Then, where is message defined in the following statement:
plLabel = Label(mainWin, textvariable=message)
There's no need to use a StringVar object, but if you want, you have first to declare it:
message = StringVar()
and finally you can use it as textvariable for your label.
Assuming you don't know what lambda is, this is a working example of what you are trying to do (without using a StringVar variable):
from tkinter import *
def set_label_text():
plLabel.config(text='Hello World!')
mainWin = Tk()
topFrame=Frame(mainWin)
topFrame.pack(side=TOP)
button1 =Button(mainWin,text="ThrowDice",fg="red",
command=set_label_text) # note the absence of ()
button1.pack(side=BOTTOM)
plLabel = Label(mainWin)
plLabel.pack()
mainWin.mainloop()

Related

populating one combobox based on another combo box using tkinter python

from tkinter import *
from tkinter.ttk import Combobox
v1=[]
root = Tk()
root.geometry('500x500')
frame1=Frame(root,bg='#80c1ff',bd=5)
frame1.place(relx=0.5,rely=0.1,relwidth=0.75,relheight=0.1,anchor='n')
lower_frame=Frame(root,bg='#80c1ff',bd=10)
lower_frame.place(relx=0.5,rely=0.25,relwidth=0.75,relheight=0.6,anchor='n')
v=[]
def maincombo():
Types=["MA","MM","MI","SYS","IN"]
combo1=Combobox(frame1,values=Types)
combo1.place(relx=0.05,rely=0.25)
combo2=Combobox(frame1,values=v)
combo2.bind('<<ComboboxSelected>>', combofill)
combo2.place(relx=0.45,rely=0.25)
def combofill():
if combo1.get()=="MA":
v=[1,2,3,45]
combo2=Combobox(frame1,values=v)
combo2.place(relx=0.45,rely=0.25)
if combo1.get()=="MM":
v=[5,6,7,8,9]
combo2=Combobox(frame1,values=v)
combo2.place(relx=0.45,rely=0.25)
maincombo()
root.mainloop()
I want to populate the one combobox based on selection of other combobox I,e types.But failed to do so with simple functions.
Looking at you code, most of what you need is already there. The changes I have made are as follows:
Bound to combo1 rather than combo2 (as combo1 is the one you want to monitor)
Set combo1 and combo2 as global variables (so they can be used in the combofill method)
Set the combofill method to accept the event arg (it would raise a TypeError otherwise)
Use the .config method on combo2 rather than creating a new one each time
Set combo2 to be empty when neither "MA" or "MM" are selected
Here is my implementation of that:
from tkinter import *
from tkinter.ttk import Combobox
v1=[]
root = Tk()
root.geometry('500x500')
frame1=Frame(root,bg='#80c1ff',bd=5)
frame1.place(relx=0.5,rely=0.1,relwidth=0.75,relheight=0.1,anchor='n')
lower_frame=Frame(root,bg='#80c1ff',bd=10)
lower_frame.place(relx=0.5,rely=0.25,relwidth=0.75,relheight=0.6,anchor='n')
v=[]
def maincombo():
global combo1, combo2
Types=["MA","MM","MI","SYS","IN"]
combo1=Combobox(frame1,values=Types)
combo1.place(relx=0.05,rely=0.25)
combo1.bind('<<ComboboxSelected>>', combofill)
combo2=Combobox(frame1,values=v)
combo2.place(relx=0.45,rely=0.25)
def combofill(event):
if combo1.get()=="MA":
v=[1,2,3,45]
elif combo1.get()=="MM":
v=[5,6,7,8,9]
else:
v=[]
combo2.config(values=v)
maincombo()
root.mainloop()
A couple other ideas for potential future consideration:
I would recommend using the grid manager rather than the place manager as it will stop widgets overlapping, etc. (on my system, combo2 slightly covers combo1)
Use a dictionary rather than if ... v=... elif ... v= ... and then use the get method so you can give the default argument. For example:
v={"MA": [1,2,3,45],
"MM": [5,6,7,8,9]}. \
get(combo1.get(), [])
EDIT:
Responding to the question in the comments, the following is my implementation of how to make a "toggle combobox" using comma-separated values as requested.
As the combobox has already overwritten the value of the text area when our <<ComboboxSelected>> binding is called, I had to add a text variable trace so we could keep track of the previous value of the text area (and therefore append the new value, etc.). I am pretty sure that explanation is completely inadequate so: if in doubt, look at the code!
from tkinter import *
from tkinter.ttk import Combobox
root = Tk()
def log_last():
global last, cur
last = cur
cur = tx.get()
def append_tx(event):
if last:
v = last.split(",")
else:
v = []
v = list(filter(None, v))
if cur in v:
v.remove(cur)
else:
v.append(cur)
tx.set(",".join(v))
combo.selection_clear()
combo.icursor("end")
last, cur = "", ""
tx = StringVar()
combo = Combobox(root, textvariable=tx, values=list(range(10)))
combo.pack()
combo.bind("<<ComboboxSelected>>", append_tx)
tx.trace("w", lambda a, b, c: log_last())
root.mainloop()

Is there a way to change a buttons colour when the button is made in a function?

I have made a button within a function and when the button is clicked a command is run to change the button color.
However this does not work as I get an error, but I need to create the button in the function.
It works when the button is defined outside the function and I assume the issue is that the data is forgotten after a function ends.
from tkinter import *
root = Tk()
def ColourChange(Letter):
NameButton.config(bg = "red")
def Change():
Letter = "a"
NameButton=Button(root, text = "This", command = lambda Letter = Letter:
ColourChange(Letter)
NameButton.pack()
Change()
When I click the button I would like the color of the background to change.
The actual error is
NameButton.config(bg="red") NameError: name 'NameButton' is not defined"
Set your global variable so it can be access by other function.Also move NameButton.pack() to new line after NameButton=Button(root,text="This",command=lambda Letter=Letter: ColourChange(Letter)).
from tkinter import *
root=Tk()
def ColourChange(Letter):
NameButton.config(bg="red")
def Change():
global NameButton # global variable
Letter="a"
NameButton=Button(root,text="This",command=lambda Letter=Letter: ColourChange(Letter))
NameButton.pack()
#NameButton.pack()
Change()

Python Tk Menu Delete command , Menu.reDraw()?

I have a TK Menu widget, and would like to remove the command when clicked on, after doing some side effect stuff. All the code is in a DocumentView class, hence the self.varnames
self.root= Tk()
self.root.title("Document Screen")
self.root.geometry(str(DocHeight)+"x"+str(DocHeight))
self.mainMenu = Menu(self.root)
self.allMembersMenu = Menu(self.updateMembersMenu)
for member in self.allUsers:
self.allMembersMenu.add_command(label=member,command=lambda i= member:
self.removeUser(i))
This makes a command for every user in the system. Remove user is defined as follows
def removeUser(self,uname):
print("Remove User Function , uname: {}".format(uname))
x=0
mem = self.currentDoc.getMembers()
delmem=""
for i in range(0,len(mem)):
if (mem[i]==uname):
x=i
delmem = mem[i]
break
self.allMembersMenu.delete(x)
self.allUserMenu.destroy
self.currentDoc.removeMember(delmem)
Using the print function I know the correct variables are being passed, but no change is occurring in the Menu, is there some sort of Menu.reDraw() method I'm missing?
If that doesn't exist is there a way to destroy this submenu and redraw it?
import tkinter as tk
root = tk.Tk()
root.geometry("400x600")
root.option_add("*tearOff", False)
menuBar = tk.Menu(root)
root.config(menu=menuBar)
usersMenu = tk.Menu(menuBar)
delUserMenu = tk.Menu(menuBar)
menuBar.add_cascade(menu=usersMenu, label="Users")
usersMenu.add_cascade(menu=delUserMenu, label="Delete")
usernamelist = ["Ali", "Ahmed", "Muhamed"]
def del_user(username):
delUserMenu.delete(delUserMenu.index(username))
print(username, "deleted!")
def command(username): return lambda :del_user(username)
for username in usernamelist:
delUserMenu.add_command(label=username, command=command(username))
root.mainloop()

what is the difference between a variable and StringVar() of tkinter

Code:
import tkinter as tk
a = "hi"
print(a)
a1 = tk.StringVar()
a1.set("Hi")
print(a1)
Output:
hi ##(Output from first print function)
AttributeError: 'NoneType' object has no attribute '_root' (Output from second print function)
My question:
What is the difference between a and a1 in above code and their use-cases. Why a1 is giving error?
A StringVar() is used to edit a widget's text
For example:
import tkinter as tk
root = tk.Tk()
my_string_var = tk.StringVar()
my_string_var.set('First Time')
tk.Label(root, textvariable=my_string_var).grid()
root.mainloop()
Will have an output with a label saying First Time
NOTE:textvariable has to be used when using string variables
And this code:
import tkinter as tk
def change():
my_string_var.set('Second Time')
root = tk.Tk()
my_string_var = tk.StringVar()
my_string_var.set('First Time')
tk.Label(root, textvariable=my_string_var).grid()
tk.Button(root, text='Change', command=change).grid(row=1)
root.mainloop()
Produces a label saying First Time and a button to very easily change it to Second Time.
A normal variable can't do this, only tkinter's StringVar()
Hopes this answers your questions!
StringVar() is a class from tkinter. It's used so that you can easily monitor changes to tkinter variables if they occur through the example code provided:
def callback(*args):
print "variable changed!"
var = StringVar()
var.trace("w", callback)
var.set("hello")
This code will check if var has been over-written (this mode is defined by the w in var.trace("w", callback).
A string such as "hello" is just a data type, it can be manipulated and read and all sorts, the primary difference is that if the string was assigned to a variable, such as a = 'hello', there is no way of telling if a has changed (i.e if now a = 'hello') unless you do a comparison somewhere which could be messy.
Put it simply: StringVar() allows you to easily track tkinter variables and see if they have been read, overwritten, or if they even exist which you can't easily do with just a typical a = 'hello'
Helpful : http://effbot.org/tkinterbook/variable.htm
Edit : Replaced 'variables' with 'tkinter variables' where appropriate as per #Bryan Oakley's suggestion
Tkinter is a wrapper around an embedded tcl interpreter. StringVar is a class that provides helper functions for directly creating and accessing such variables in that interpreter. As such, it requires that the interpreter exists before you can create an instance. This interpreter is created when you create an instance of Tk. If you try to create an instance of StringVar before you initialize tkinter, you will get the error that is shown in the question.
Once tkinter has been properly initialized and a StringVar instance has been created, it can be treated like any other python object. It has methods to get and set the value that it represents.
At the beginning add
root = tk.Tk()
These Variables are designed for tkinter. and these do not work independently.
Suppose if you are building a GUI calculator, you want to display the values the user inputs in the screen of the calculator. If the user is trying to add 5 + 5, we have to show, "5" "+" "5" in the display. And when the equals button is pressed, we want to display "10". That is the use of StringVar(). It holds the string equivalent of the value the interpreter holds.

Use return key and a button at the same time in tkinter

I want to write a program for my biology class... I want to integrate the function that you can type something in the Entry bar and then you can use the button or click the return key. I've the problem, that I just can click the button. Everything else don't work. Here is my code (in a simple form):
from tkinter import *
import tkinter as tk
# Main Graphic User Interface
root = Tk()
root.title("Genetic Translator")
root.geometry("300x175")
root.resizable(0,0)
# Solid Label "Information for Input"
s_label2 = Label(root, text = "\nInput Tripplet which decodes for an amino acid:\n")
s_label2.pack()
# Entry Bar
trip = Entry(root)
trip.pack()
# Function for setting focus on entry bar
trip.focus_set()
# Dictionary
output = {"GCX":"Alanine [Ala]"}
# Dict Function Function (Trans: trip -in- AS)
def dict_function1():
global o_screen
o_screen.configure(text=(output.get(trip.get().upper(),"Unknown tripplet!")))
# Bind the Return Key for Input
trip.bind("<Return>", dict_function1)
# Space Label 1
space_label1 = Label(root)
space_label1.pack()
# Button "Confirm"
mainbutton = Button(root, text = "Confirm", command = dict_function1)
mainbutton.pack()
# Space Label 2
space_label2 = Label(root)
space_label2.pack()
# Output Screen
o_screen = Label(root)
o_screen.pack()
# Mainloop function for Interface Options
root.mainloop()
Thank you for helping me.
When you press return key it will send event as argument to dict_function1 and when you click on the button nothing is send.
add argument to dict_function1 with None as default value.
def dict_function1(event=None)
Function assigned to button is called without arguments but assigned by bind is called with argument - event information - so your function have to receive that argument
def dict_function1(event=None): # None for "command="
--
<Return> binded to Entry will work only if Entry is focused, but not when Button is focused. If you bind <Return> to root then <Return> will work in both situations.
You neglected to say what "don't work" means. When I run your code from IDLE, enter 3 letters, and hit return, I get the following
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Programs\Python35\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
TypeError: dict_function1() takes 0 positional arguments but 1 was given
The issue is that when tk calls a 'command', it does not pass any arguments, but when it calls a function bound to an event, it passes an event argument. So add an optional parameter to the function.
def dict_function1(event=None):
It works for me, except for the error message when the Enter key is pressed which you don't provide, so that may or may not be the problem. It is easily fixed, but "everything else don't work" is way too vague to help you with. See "Capturing keyboard events" at http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm You should also include code if the Entry value is not found in the dictionary. Finally, you import Tkinter twice in the first 2 statements in the program. Choose one or the other.
from tkinter import *
# Main Graphic User Interface
root = Tk()
root.title("Genetic Translator")
root.geometry("300x175")
root.resizable(0,0)
# Solid Label "Information for Input"
s_label2 = Label(root, text = "\nInput Tripplet which decodes for an amino acid:\n")
s_label2.pack()
# Entry Bar
trip = Entry(root)
trip.pack()
# Function for setting focus on entry bar
trip.focus_set()
# Dictionary
output = {"GCX":"Alanine [Ala]"}
# Dict Function Function (Trans: trip -in- AS)
def dict_function1(arg=None): ## capture the event from the Return key
##global o_screen
o_screen.configure(text=(output.get(trip.get().upper(),"Unknown tripplet!")))
# Bind the Return Key for Input
trip.bind("<Return>", dict_function1)
# Space Label 1
space_label1 = Label(root)
space_label1.pack()
# Button "Confirm"
mainbutton = Button(root, text = "Confirm", command = dict_function1)
mainbutton.pack()
# Space Label 2
space_label2 = Label(root)
space_label2.pack()
# Output Screen
o_screen = Label(root)
o_screen.pack()
# Mainloop function for Interface Options
root.mainloop()

Resources