dynamically rename tkinter window - python

I have the following bits of code that creates a toplevel window and parses a dictionary into a Text widget:
def escrito(**kwargs):
write_window = Toplevel(root)
#write_window.title(kwargs) (problematic code)
writing_box = tk.Text(write_window, font = ("calibri", 20), width = 60, height = 15, wrap=WORD)
writing_box.pack(expand = tk.YES, fill = tk.X)
writing_box.grid(row = 0, column = 0, sticky = 'nswe')
texto = '\n'.join(key + ":\n" + value for key, value in kwargs.items())
writing_box.insert("1.0", texto)
def septic_osteo():
escrito(**infections.Septic_arthritis)
Septic_arthritis = {
'Empirical Treatment':
'Flucloxacillin 2g IV 6-hourly',
'If non-severe penicillin allergy':
'Ceftriaxone IV 2g ONCE daily',
'If severe penicillin allergy OR if known to be colonised with
MRSA':
'Vancomycin infusion IV, Refer to Vancomycin Prescribing
Policy',
'If systemic signs of sepsis': 'Discuss with Consultant
Microbiologist'
}
So when I run the code, the escrito functions parses the dictionary and writes its content onto a text widget contained on a Toplevel window. What I would like to know is how to dynamically rename the Toplevel window with the dicitonary's name. I do know that I can do this:
def septic_osteo():
escrito(**infections.Septic_arthritis)
write_window.title('Septic_arthritis)
but I do have like 100 functions like the one above, so, aside from labour intensive, I am not sure is the more pythonic way, so, is there a way that the window can be renamed with the dictionary name? (i.e. 'Septic_arthritis)
Thanks

If your data is in an object named infections, with attributes such as Septic_arthritis, the most straight-forward solution is to pass the data and the attribute as separate arguments, and then use getattr to get the data for the particular infection.
It would look something like this:
def escrito(data, infection):
write_window = Toplevel(root)
write_window.title(infection)
writing_box = tk.Text(write_window, font = ("calibri", 20), width = 60, height = 15, wrap="word")
writing_box.pack(expand = tk.YES, fill = tk.X)
writing_box.grid(row = 0, column = 0, sticky = 'nswe')
texto = '\n'.join(key + ":\n" + value for key, value in getattr(data, infection).items())
writing_box.insert("1.0", texto)
The important bit about the above code is that it uses getattr(data, infection) to get the data for the given infection.
If you want to create a button to call this function, it might look something like this:
button = tk.Button(..., command=lambda: escrito(infections, "Septic_arthritis"))
This will call the command escrito with two arguments: the object that contains all of the infections, and the key to the specific piece of information you want to display.

Related

creating dynamic widget reference

I have a program using GUIZero for my display interface. On this display, I have 30 pushbuttons created. I am trying to find a way to dynamically reference all 30 buttons. Here is the code I "think" I need, but obviously it is not working. Quick background on GUIZero, I create the pushbutton, and then the pushbutton has parameters I can adjust. I am trying to adjust the background of the pushbutton. That looks like {widget}.{parameter} = {value}. I am trying to make the {widget} portion dynamic.
Here is a shortened version of what works:
def Clearapp():
button_0.bg = "light grey"
button_1.bg = "light grey"
button_2.bg = "light grey"
.
.
.
button_29.bg = "light grey"
This is what I "think" it should be, but is not working.
bit0 = "button_"
def Clearapp():
global bit0
for x in range(30):
btn = bit0+str(x) # this makes "button_" + {value of x}
btn.bg = "light grey"
I know I have bit0 set as a global variable, and I am doing that because of the structure of what I am doing, I use that string in a lot of different places, and it makes it easier to use and keep my name and syntax correct.
So, the long and short, I am trying to figure out how to combine 2 strings together and then use that string as a reference or pointer to a specific item. As shown above I tried both code versions. The long version works fine. The short version results with the following errors:
File "/home/pi/Desktop/qc_box_221129a.py", line 50, in Clearapp btn.bg = "light grey" AttributeError: 'str' object has no attribute 'bg'
To add some additional clarity:
I want to use the string value in "btn" (the combination of bit0 and x) as a pointer to go to a specific widget.
So in my bottom code, this is the order of operations:
`For x in range(30):
btn = "button_" + x
btn.bg = {value}
Step 1: x=0
btn = button_ + 0
{use string to address widget} -> insert value of btn into command "btn.bg = {value}"
button_0.bg = {value}
Step 2: x = 1
btn = button_ + 1
button_1.bg = {value}
Step 3: x = 2
btn = button_ + 2
button_2.bg = {value}
.
.
.
Step 30: x = 29
btn = button_ + 29
button_29.bg = {value}`

how to remove { } in tkinter?

customerqtyUI = Label(homeUI, text = (str('number of customer:'), customer) , font = ('calibri', 20), background="floral white", foreground = 'black')
this is my code👆.
May i know why i cannot combine the string and my variable 'customer' together?
My output👆 will have a {} and i cannot remove it
I'm not sure how tkinter works, but in this case, you've passed a tuple consisting of str('number of customer:') and customer to the text keyword argument. What you really want to do is combine 'number of customers:' with the customer variable. Try this:
customerqtyUI = Label(homeUI, text = f'number of customer: {customer}', font = ('calibri', 20), background="floral white", foreground = 'black')
text field accepts a string. Passing a tuple (or any other type) will be counted as undefined behaviour. So the solution becomes
Label(..., text = 'number of customer: ' + str(customer), ...)```

Python GUI EntryButtons

I'm making a small GUI application that deals with grades and whatnot and outputs the highest grades and etc.
Here's a part of the code:
root = Tk()
gradeList = []
def addGradeObject(name, percentage):
gradeList.append(Grade(name, percentage))
updateOutput()
print(gradeList)
def undoAdd():
try:
gradeList.pop(len(gradeList) - 1)
updateOutput()
print(gradeList)
except Exception:
pass
def updateOutput():
highestGrade.setText(highest_grade(gradeList))
lowestGrade.setText(lowest_grade(gradeList))
numFailed.setText(num_failed(gradeList))
addButton = Button(text = "Add Grade", command = lambda: addGradeObject (entryA.get(), entryB.get())).grid(row = 1, column = 4)
undoButton = Button(text = "Undo", command = undoAdd).grid(row = 2, column = 4)
entryA = Entry()
entryA.grid(row = 1, column = 1)
entryB = Entry()
entryB.grid(row = 1, column = 2)
highestGrade = Entry()
highestGrade.grid(row = 2, column = 1)
lowestGrade = Entry()
lowestGrade.grid(row = 3, column = 1)
numFailed = Entry()
numFailed.grid(row = 4, column = 1)
root.title("Grade Checker")
root.mainloop()
The problem is I'm getting this error:
AttributeError: 'Entry' object has no attribute 'setText'
I don't understand. When you create an Entry box, doesn't the object of class "Entry" have an attribute/method that allows you to set text to it? I really don't know why it's not working
Entry methods can be found here. As far as I can tell, there is no setText method. There is however an insert method that you could use to set the text (though you might wand to delete the current text first).
def set_text(entry, text):
entry.delete(0, tkinter.END)
entry.insert(0 text)
Alternatively, you can hook the entry up to a StringVar and use it's .set() and .get() methods. e.g. (from the linked docs above):
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()

TypeError: unorderable types: str() < int()

Need help with this error.
my code:
from tkinter import *
def shouldIEat():
if calories.get() < 1523 :
answer.set("Eat food as soon as possible")
elif calories.get() > 1828 :
answer.set("Stop eating")
else:
answer.set("You can eat something, but don't go over 1828")
window = Tk()
answer = StringVar()
calories = IntVar()
calories.set(0)
caloriesLabel = Label(window, text = "How many calories have you consumed?")
caloriesLabel.grid( row = 1)
calories = Entry(width = 10)
calories.grid (row = 1, column = 1)
eatButton = Button(window, text = "Should I eat?" , command=shouldIEat).grid( row = 2 , column = 1)
quitButton = Button(window, text = "Quit" , command=window.quit).grid( row = 2 , column = 2)
window.mainloop()
My error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1487, in __call__
return self.func(*args)
File "D:/My Documents/School/Scripting Lang/Project", line 8, in shouldIEat
if calories.get() < 1523 :
TypeError: unorderable types: str() < int()
Your code sets up calories as a Tkinter IntVar, but then it clobbers it by creating an Entry with the same name. You need to give the Entry a different name, and then attach the calories IntVar using the textvariable argument in the Entry constructor.
Also, you never created a widget to display the answer.
from tkinter import *
def shouldIEat():
if calories.get() < 1523 :
answer.set("Eat food as soon as possible")
elif calories.get() > 1828 :
answer.set("Stop eating")
else:
answer.set("You can eat something, but don't go over 1828")
window = Tk()
answer = StringVar()
calories = IntVar()
calories.set(0)
#answer.set('')
caloriesLabel = Label(window, text = "How many calories have you consumed?")
caloriesLabel.grid(row = 1, column = 0)
caloriesEntry = Entry(width = 10, textvariable=calories)
caloriesEntry.grid(row = 1, column = 1)
Button(window, text = "Should I eat?", command=shouldIEat).grid(row = 2, column = 1)
Button(window, text = "Quit" , command=window.quit).grid(row = 2, column = 2)
answerLabel = Label(window, textvariable=answer)
answerLabel.grid(row = 2, column = 0)
window.mainloop()
We don't really need to initialise answer, but it is neater to do so. And you could use it to display some simple instructions, if you want.
There's another minor problem with your code that I should mention.
eatButton = Button(window, text = "Should I eat?" , command=shouldIEat).grid( row = 2 , column = 1)
This creates a Button object and then calls its .grid() method. That's fine, but the .grid() method returns None, it does not return the Button object, so saving that return value to eatButton is pointless. You don't need to keep a reference to that button for this program, which is why I changed it to
Button(window, text = "Should I eat?", command=shouldIEat).grid(row = 2, column = 1)
in my version. But when you do need to keep a reference to the widget you should construct it on one line and then apply the .grid() (or .pack()) method on a separate line, like you did with caloriesLabel.
BTW, in Python, names of the form calories_label are preferred over caloriesLabel. See PEP-008 for further details.
As you can see in the TypeError, you are comparing a string with an integer.
Cast your string to an integer before doing your comparison.

Creating a mouse over text box in tkinter

I'm trying to implement system where when the user points to an object, a text box appears with certain information which I haven't implemented yet, then disappears when they move their mouse away. I'm trying to do that by binding the < Enter > and < Leave > commands, but nothing happens when I run the following code, except that in the terminal it says that destroy requires two arguments, so I know it is calling the functions.
from tkinter import *
xhig, yhig = 425,325
bkgnclr = '#070707'
currentmouseoverevent = ''
c = Canvas(master, width=xhig*2, height=yhig*2, bg=bkgnclr, cursor = 'crosshair',)
def mouseovertext(event):
mouseover = "Jack"
currentmouseoverevent = event
c.create_rectangle(bbox=(event.x,event.y, (event.x + 5), (event.y +len(mouseover)*5)),outline="white", fill=bkgnclr, width= len(mouseover))
c.create_text(position=(event.x,event.y),text=mouseover, fill="white", currentmouseoverevent=event)
def closemouseover(x):
c.destroy(currentmouseoverevent)
c.bind("<Enter>", mouseovertext)
c.bind("<Leave>", closemouseover)
What arguments does destroy take, and why is the rectangle not being created?
A bounding box (bbox) in tkinter is a 4-tuple which stores the bounds of the rectangle. You are only passing in the mouse location, which is a 2-tuple.
Also, you are never actually assigning to the variable "currentmouseoverevent" before using it in the code you show, so your closemouseover function will fail.
The corrected code is as follows.
It turns out I was calling bbox wrong. Instead of passing the coords as a tuple, I should have passed them as the first four agrguments of create_rectangle. c.destroy is only for objects like canvas, entry or textbox, instead I used c.delete for deleting items, and used the event number returned by c.create_rectangle and c.create_text.
from tkinter import *
xhig, yhig = 425,325
bkgnclr = '#070707'
currentmouseoverevent = ['','']
c = Canvas(master, width=xhig*2, height=yhig*2, bg=bkgnclr, cursor = 'crosshair',)
def mouseovertext(event):
mouseover = "Jack"
if currentmouseoverevent[0] != '':
closemouseover()
currentmouseoverevent[0]=''
return
currentmouseoverevent[0] = c.create_rectangle(event.x,event.y, (event.x + 5), (event.y +len(mouseover)*5),outline="white", fill=bkgnclr, width= len(mouseover))
currentmouseoverevent[1] = c.create_text(event.x,event.y,text=mouseover, fill="white", currentmouseoverevent=event,anchor=NW)
def closemouseover(x):
c.delete(currentmouseoverevent[0])
c.delete(currentmouseoverevent[1])
c.bind("<Button-3", mouseovertext)

Categories

Resources