Firstly let's look at this program:
def entry_simutaneously_change():
from Tkinter import *
root=Tk()
text_in_entry.set(0)
Entry(root, width=30, textvariable= text_in_entry).pack()
Entry(root, width=30, textvariable= text_in_entry).pack()
Entry(root, width=30, textvariable= text_in_entry).pack()
root.mainloop()
The contents in these three entries can change simultaneously. If I change the value of any of them, the other two would change at the same time. However, for the following program:
def entry_simutaneously_change():
from Tkinter import *
root=Tk()
text_in_entry_list=[IntVar() for i in range(0,3)]
text_in_entry_list[0].set(0)
text_in_entry_list[1].set(text_in_entry_list[0].get() ** 2)
text_in_entry_list[2].set(text_in_entry_list[0].get() ** 3)
Entry(root, width=30, textvariable= text_in_entry_list[0]).pack()
Entry(root, width=30, textvariable= text_in_entry_list[1]).pack()
Entry(root, width=30, textvariable= text_in_entry_list[2]).pack()
root.mainloop()
When I change the content in the first entry, the contents in the other two do not change. Why?
In the first program, you have one source of data, text_in_entry. You could consider it as one box where you're placing a single value that's read by each Entry.
In the second program, you have three sources of data, text_in_entry[0, 1, and 2]. The lines that set the initial value are called only once. It's like you have three boxes where data is placed; to set the initial values, you do look at the value inside the first, but there is no association between the three.
If you would like to achieve the same type of result as with the first program (when the three entries update simultaneously) then you will need to bind on an event. I note that Tkinker does not have an on-change style event but there are various hacks, however you could bind to the FocusOut event. The general idea is to ask for a function to be called when a change occurs to an entry (binding a callback). Inside that function you update the other two values based on the new value in the entry that was changed.
Related
I would like to set the tkinter Text box's view area / yview to a specific area. How do I do this? I know that one can retrieve the current yview but have been unsuccessful in setting it to a desired value. I know that it can be set to the desired value because I am getting the yview, destroying the Text box, and then recreating the text box. From there I would like to set the view area to what it was before but am having trouble. What should I do?
Example yviews:
(0.0, 1.0)
(0.07407407407407407, 1.0)
Code:
#Define the Text widget
t = Text(window)
t.pack()
for i in range(100):
t.insert(END, "{}\n".format(i))
def get_y():
global y
y = t.yview()
b = Button(window, text="get y", command=get_y)
b.pack()
b1 = Button(window, text="set y", command=lambda: t.yview(MOVETO, y[0]/y[1]))
b1.pack()
The code above gets the user very close but it always goes a little up or down and isn't quite right. What should I do to fix it? Can this be done similarly with xview?
I figured it out. We can get the yview with t.yview() but we can't just insert a yview value and expect it to use it. Instead, we must use t.yview(MOVETO, yview[0]). This gives it a value it can work with and goes to about the correct position
NOTE:
The same can be done with xview but use xview[1] instead
I want to have a calculator with 4 buttons and 2 entry. What is my problem? I don't know how to fix that it can't multiply sequence by non-int of type str nor can't multiply entry * entry.
Also I don't know where is my output and how use that.
from tkinter import ttk
from tkinter import *
import tkinter as tk
#the environment
calc=tk.Tk()
calc.title("Calculator")
#-------------------------------------
#lables and their data entry
tk.Label(calc,text="enter your first number:").grid(row=0)
tk.Label(calc,text="enter your second number:").grid(row=1)
e1=tk.Entry(calc)
e2=tk.Entry(calc)
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
x1=e1.get()
x2=e2.get()
tk.Label(calc,text="your result is:").grid(row=3)
# a free variable for get output,is this really need?
lbl=list()
#---------------------------
#the functions but my entry are entry type
def prod():
lbl=print(x1*x2)
def div():
lbl=print(x1/x2)
def sum():
lbl=print(x1+x2)
def min():
lbl=print(x1-x2)
#-------------------------------
#buttons and function in them as a command
btn1=tk.Button(calc,text="*",command=prod()).grid(row=0,column=2)
btn2=tk.Button(calc,text="/",command=div()).grid(row=1,column=2)
btn3=tk.Button(calc,text="+",command=sum()).grid(row=2,column=2)
btn4=tk.Button(calc,text="-",command=min()).grid(row=3,column=2)
#--------------------------------------------------------------------
#The answer which i need it
print("your answer is:")
calc.mainloop()
In GUI programming, you need to get the value of widgets at the time you need them, not at the time you create them.
Also, widgets return string values. If you are doing math on them, you need to convert them to numbers first.
If you want to display the result in the window, you can update a label widget with the configure method
For example, your prod definition could look something like this:
def prod():
x1 = int(e1.get())
x2 = int(e2.get())
result = x1 * x2
result_label.configure(text=str(result))
You then need to do two other things. First, you need to create the label for the result, and store the widget in a variable. To do that you must separate the creation of the widget from the layout since calling grid would cause the variable to be set to None
result_label = tk.Label(calc,text="your result is:")
result_label.grid(row=3)
Finally, your buttons need to be given a reference to the function. What you're currently doing is calling the function and assigning the result to the command attribute.
Your button should look like the following. Notice that prod does not have () after it:
btn1 = tk.Button(calc, text="*", command=prod)
...
btn1.grid(row=0,column=2)
On a side note, I think that for all widgets with a common parent, grouping all widget creation code together and then all calls to grid or pack together makes the code easier to read, easier to maintain, and easier to visualize.
For example:
btn1 = tk.Button(...)
btn2 = tk.Button(...)
btn3 = tk.Button(...)
btn4 = tk.Button(...)
btn1.grid(row=0,column=2)
btn2.grid(row=1,column=2)
btn3.grid(row=2,column=2)
btn4.grid(row=3,column=2)
I have to make 10 entry boxes and rather than do each one individually, I've done them like this:
for i in range(0,10):
widthEntry = Entry(root, width=int(9.5), relief='solid')
widthEntry.grid(row=i+7, column=2, ipady=2)
so how do I pull the value entered into, for example, entry box 7 so that I can use that value in calculations?
I'm using Python and Tkinter
Use a list to contain the Entry instances.
entries = []
for i in range(0,10):
widthEntry = Entry(root, width=int(9.5), relief='solid')
widthEntry.grid(row=i+7, column=2, ipady=2)
entries.append(widthEntry)
Get the 7th entry box:
entries[6].get()
I'm using tkinter to create a calculator of sorts for one of my classes, and I've been making like 20 labels in a grid layout, using virtually the same line of code every time except the name and obviously the row number. I was just wondering if there was a standard way to quickly and effeciently make labels like this, or if someone has a quick way they use to break the tediousness?
For example, this is what my "code" basically looked like.
label0 = tk.Label(frame,
text="Label0")
label0.grid(row=0,
column=0,
sticky="E")
label1 = tk.Label(frame,
text="Label1")
label1.grid(row=1,
column=0,
sticky="E")
...
labeln = tk.Label(frame,
text="Labeln")
labeln.grid(row=n,
column=0,
sticky="E")
I tried creating a list or library of all the label names, then saying something like
labelnames = ["label0",
"labebl1",
...,
"labeln"]
for i in len(labelnames):
labelx = tk.Label(frame,
text=labelnames[i])
labelx.grid(row=i,
column=0,
sticky="E")
This works, but the point of this was to learn and I would like to know if there is a standard or "correct" way to do this. I tend to stray away from using classes because I still don't understand them (ironic I know), but I would like to learn if this were a better use for them.
A problem with this method that arises for me is I have an entry box corresponding to each label created using a similar loop, and I'm not sure how to get the input from the entry this way.
You are doing it correctly. We could make it a little neater using enumerate:
labels = []
for i, label in enumerate(labelnames):
labelx = tk.Label(frame, text=label)
labelx.grid(row=i, column=0, sticky="E")
labels.append(labelx)
I also added the resulting widgets to a list. That way I can access them later.
labels[2].config(text='new text') # update the text on the 3rd Label
I wrote my first py code. This code to create a lotto number generator.The problem is that my variable nums will not change. Please help me.
I understand this is not as good as it can be so please tell me how to improve, any comments will be appreciated.I wanted the random numbers to come up in the ladle so i could press the submit button and 5 new numbers to come up.The problem is my veritable "nums" wont change.Thank you for helping.
import random
from tkinter import *
#TK()
window = Tk()
window.title("Lottery Nummber Generator")
#Def Click
def click():
global nums
global numsgen
numsgen = random.sample(range(1, 49), 5)
nums = " ".join(str(x) for x in numsgen)
print(nums)
numsgen = random.sample(range(1, 49), 5)
nums = " ".join(str(x) for x in numsgen)
#Fake just to make it look nice
Label(window,text="").grid(row=1, column=0,sticky=W)
Label(window,text="").grid(row=2, column=1,sticky=W)
Label(window,text="").grid(row=2, column=3,sticky=W)
#Submit button
Button(window, text="Submit", width=5,command=click).grid(row=3, column=1, sticky=W)
#Label
group = LabelFrame(window, text="Lottery Numbers:", padx=5, pady=5,fg="dark orange")
group.pack(padx=10, pady=10,)
group.grid(row=2, column=1,sticky=W)
w = Label(group, text=nums)
w.pack()
mainloop()
To get a label to update, you must do one of two things:
Associate a StringVar with the label. When you update the variable (via its set method), any labels associated with it will automatically change. This is a great solution if more than one widget needs to display the same value.
Directly configure the label. This requires that you save a reference to the widget(s) so that you can later reconfigure them. For example, you could put w.configure(text=nums) in your click function. This solution is a bit simpler than using a StringVar, simply because it requires one less object.