I need to change the order of switching values in Spinbox widget, in case, when "values" parametr is set. This could be similar like a "increment=-1", when using "from_" and "to" paramentrs. I want, just the opposite, when i'm clicking "downbutton" - index of values is increaseing...
from tkinter import *
root = Tk()
var = StringVar()
values = ['1.Python','2.Ruby','3.PHP','4.Perl','5.JavaScript']
spin_box = Spinbox(root,
textvariable=var,
values=values,
wrap=True,
command=lambda: print(var.get()),
width=12)
spin_box.pack()
root.mainloop()
Just reverse your list, and initialize the value with the last item in the reversed list. It doesn't change the index of the selected item per se, but it makes the down arrow move through the list in the opposite way.
from tkinter import *
root = Tk()
values = ['1.Python','2.Ruby','3.PHP','4.Perl','5.JavaScript']
values = values[::-1]
var = StringVar()
spin_box = Spinbox(root,
textvariable=var,
values=values,
wrap=True,
command=lambda: print(var.get()),
width=12)
var.set(values[-1])
spin_box.pack(padx=50, pady=50)
root.mainloop()
Related
I am trying to make a calculator with Tkinter GUI. However, when I make buttons under an entry, they get pushed apart. Also, instead of the buttons being in their corresponding columns, they are way out of line. What is making this happen?
Code:
from tkinter import *
# Configure the window
gui = Tk()
gui.title("Calculator")
gui.geometry("400x500")
# Variables for displaying input and output
expression = StringVar()
input_ = ""
# Make the Entry
expression_entry = Entry(gui, textvariable=expression,
width=49).grid(column=0, row=0)
# Make the Buttons
number_1 = Button(gui, width=3, height=2)
number_1.grid(column=0, row=1)
number_2 = Button(gui, width=3, height=2)
number_2.grid(column=1, row=1)
gui.mainloop()
https://i.stack.imgur.com/8yGWn.png
It is because column 0 is very wide to hold the entry. By default, items are centered in their allocated space so the first button is centered under column 0, and the second is centered in column 1.
The solution is to decide how many columns you want under the entry widget, then have the entry widget span that many columns. Then, remove the width for the entry widget and use the sticky attribute so that it completely fills the space given to it rather than forcing it to be a specific width.
The following code adds a third column for more buttons
from tkinter import *
# Configure the window
gui = Tk()
gui.title("Calculator")
gui.geometry("400x500")
# Variables for displaying input and output
expression = StringVar()
input_ = ""
# Make the Entry
expression_entry = Entry(gui, textvariable=expression)
# Make the Buttons
number_1 = Button(gui, width=3, height=2)
number_2 = Button(gui, width=3, height=2)
number_3 = Button(gui, width=3, height=2)
# assuming there are three columns
expression_entry.grid(column=0, row=0, columnspan=3, sticky="ew")
number_1.grid(column=0, row=1)
number_2.grid(column=1, row=1)
number_3.grid(column=2, row=1)
gui.mainloop()
I'm trying to create a GUI and I am having trouble getting read only entry fields to insert a value. I've tried using a text value and this didn't insert anything into the field.
here is the function:
def calculateFinalCMD():
global planetInfo
global getDestinationNum
displayfc1.grid(row=14, column=2)
displayfc1.insert(0, ((100 - int(crewInfo[0][1])) * planetInfo[getDestinationNum][1]))
displayfc2.grid(row=15, column=2)
displayfc2.insert(0, ((100 - int(crewInfo[1][1])) * planetInfo[getDestinationNum][1]))
displayfc3.grid(row=16, column=2)
displayfc3.insert(0, ((100 - int(crewInfo[2][1])) * planetInfo[getDestinationNum][1]))
displayfc4.grid(row=17, column=2)
displayfc4.insert(0, ((100 - int(crewInfo[3][1])) * planetInfo[getDestinationNum][1]))
displayms1.grid(row=18, column=2)
displayms1.insert(0, ((150 - int(crewInfo[4][1])) * planetInfo[getDestinationNum][1]))
displayms2.grid(row=19, column=2)
displayms2.insert(0, ((150 - int(crewInfo[5][1])) * planetInfo[getDestinationNum][1]))
Here are the entry fields which are separate from the function, getDestinationNum is updated by another entry field earlier in the code.
getDestinationNum = 0
displayfc1 = Entry(root, state="readonly")
displayfc2 = Entry(root, state="readonly")
displayfc3 = Entry(root, state="readonly")
displayfc4 = Entry(root, state="readonly")
displayms1 = Entry(root, state="readonly")
displayms2 = Entry(root, state="readonly")
Any ideas on how anything could be changed or if the code is wrong? thanks!
This is not a minimal reproducible example. Something like this would have better explained your problem.
from tkinter import Tk, Entry
root = Tk()
my_entry = Entry(root, state='readonly')
my_entry.grid(row=0, column=0)
my_entry.insert(0, 500) # does not work
root.mainloop()
The problem is that your Entry widget is read only and cannot be updated.
We can get around that by waiting until we have set a value and use the configure method to update the state after the fact.
from tkinter import Tk, Entry
root = Tk()
my_entry = Entry(root)
my_entry.grid(row=0, column=0)
my_entry.insert(0, 500)
my_entry.configure(state='readonly')
root.mainloop()
There are some other things that could be improved with your code like relegating your calculations to a helper function, having your entries in arrays, and setting your entries in a loop.
This is just an example as I don't have access to what's inside your variables.
# This makes it much easier to follow the logic
# of your calculation
def calculate(multiplier, crew, planet):
return (multiplier - int(crew[1])) * planet[1]
multipliers = [100, 100, 100, 100, 150, 150]
# you could just append your entries to an array when creating them
# rather than add them here
entries = [displayfc1,
displayfc2,
displayfc3,
displayfc4,
displayms1,
displayms2
]
# zipping them up allows you to iterate through all
# of them at once
for entry, mult, crew, row in zip(entries,
multipliers,
crewInfo,
range(14, 20)
):
entry.grid(row=row, column=2)
entry.insert(0, calculate(mult, crew, planetInfo[getDestinationNum]))
entry.configure(state='readonly')
I want to build a program to add a basketball lineup.
Ideally I want the output to be (as an example):
Center, John
Point Guard, Jack
Shooting Guard, James
This would depend on how many values you add and what you type for the name. I am struggling to pull these values that are entered. I am not getting an error - just not getting the results I am looking for. For example, instead of "Point Guard", it says "". I am also not returning a value for the Entry fields. Any help would be greatly appreciated!!
'''
import tkinter as tk
from tkinter import *
from tkinter import ttk
root = Tk()
menu = Menu(root)
root.config(menu=menu)
combovalues = ['Center' , 'Point Guard' , 'Shooting Guard' , 'Power Forward' , 'Small Forward' ]
startinglineup = []
entry_values = []
root.counter = 2
my_lineup = []
string_var = tk.StringVar()
entry_values.append(string_var)
def addlineup():
Label(root, text='Lineup Name').grid(row=0)
e1 = Entry(root)
e1.grid(row=0, column=1)
combobox = ttk.Combobox(root, values=combovalues)
combobox.grid(column=0, row=1)
e2 = Entry(root)
e2.grid(row=1, column=1)
addbutton = tk.Button(root, text='Add', width=25, command=add)
addbutton.grid(column=0, row=14)
confirmbutton = tk.Button(root, text='Confirm', width=25, command=save)
confirmbutton.grid(column=0, row=15)
def save():
number = root.counter
print(my_lineup)
def add():
root.counter += 1
combobox = ttk.Combobox(root, values=combovalues)
combobox.grid(column=0, row=root.counter)
entry = Entry(root)
entry.grid(row=root.counter, column=1)
for stringvar in entry_values:
text = string_var.get()
if text:
my_lineup.append(text)
my_lineup.append([text, combobox])
# --- main menu ---
filemenu = Menu(menu)
menu.add_cascade(label='File', menu=filemenu)
# --- lineups ----
lineupmenu = Menu(menu)
menu.add_cascade(label='Lineups', menu=lineupmenu)
lineupmenu.add_command(label='Add Lineup', command=addlineup)
lineupmenu.add_command(label='View Lineups')
mainloop()
'''
To get results from an entry:
Create a StringVar() (If you want to store the result in a different variable and not the Entry itself)
string_var = tk.StringVar()
Creat an Entry
entry = tk.Entry(root, textvariable=string_var)
entry.pack()
Remember to add string_var to the parameter textvariable, textvariable=string_var.
Finally, get the result (it can be done at any time)
result = string_var.get()
Or, you can just do (If you don't care to store the result in the Entry itself) :
entry = tk.Entry(root)
entry.pack()
result = entry.get()
You don't actually need a StringVar
i am developing an application to calculate some taxes and show the result in the graphical interface. The code itself works perfectly, but if i use numbers with bigger squares, the result overlaps over the previous one. My question is, is it possible to clear the previous result and calculate the new one?
Follow the complete code below:
from tkinter import *
root = Tk()
l_vlrRec = Label(root, text='Receita')
l_vlrRec.place(x=10, y=10)
e_vlrRec = Entry(root)
e_vlrRec.place(x=75, y=10, width=75)
def calcular():
receita = float(e_vlrRec.get())
l_result = Label(root, text='{:.2f}'.format(receita))
l_result.place(x=10, y=150)
e_vlrRec.delete(0, END)
bt = Button(root, text='Calcular', command=calcular)
bt.place(x=10, y=50)
root.mainloop()
You can use the label's textvariable and also you don't have to instantiate a new Label every time the button is pressed:
v_result = DoubleVar()
l_result = Label(root, textvariable=v_result)
l_result.place(x=10, y=150)
def calcular():
v_result.set(round(float(e_vlrRec.get()),2))
You can do the same for your Entry object e_vlrRec so you don't have to cast the string you get by calling e_vlrRec.get() but use the variable's get() instead
Without using textvariable you can also reconfigure the label's text parameter:
l_result.configure(text='{:.2f}'.format(receita))
or
l_result['text'] = '{:.2f}'.format(receita)
I'm trying to make a GUI through Tkinter that will calculate production based on some user input. Based on the number of systems the user selects, I have that number of option menus pop up for the inverter type and that number of entry widgets pop up for modules per string, strings per inverter, and inverters per system. See the picture for an example if the user selects 2 systems.
I'm using a callback function to grab the user selected number of systems real time to dynamically generate the inverter/module widgets discussed above.
My issue is that I'm unable to retrieve the values from these widgets. My attempt is shown in the weather calculation function.
I'm assuming the issue is because I generate the widgets/variables within the callback function. However, I haven't been able to figure out a way to dynamically generate the number of widgets based on user input outside of the callback function.
Any assistance with this would be greatly appreciated!
class Window:
# Define User Inputs:
def __init__(self, master):
master.title('Production Analysis Tool')
# EQUIPMENT PARAMETERS
# callback function to create entry boxes based on number of systems
def callback(*args):
self.system_size = int(self.system_size_raw.get())
# Modules per String
self.L3 = Label(root, text = "Number of Modules Per String").grid(row=20, column=1, sticky=E)
self.modules_string_raw = IntVar(root)
modules_per_string =[]
for i in range(self.system_size):
self.label = Label(root, text = "System {}".format(i+1)).grid(row=21+i, column=1, sticky=E)
self.widget = Entry(root).grid(row=21+i, column=2, sticky=W)
modules_per_string.append(self.widget)
# Number of Systems
self.L1 = Label(root, text = "Number of Systems").grid(row=1, column=1, sticky=E)
self.system_size_raw = IntVar(root)
choices = [1,2,3,4,5,6,7,8,9,10]
self.popupMenu2 = OptionMenu(root, self.system_size_raw, *choices).grid(row=1, column=2, sticky=W)
self.system_size_raw.trace("w", callback)
#Calculation Function
def weather_calculation(self):
# Get Values from User Input
self.mod_strings = np.float(self.modules_string_raw.get())
root = Tk()
root.configure()
window = Window(root)
root.mainloop()
All you need to do is save a reference to your Entry widgets in a list. You can then iterate over that list to get the value of each widget.
It appears that you're already saving the widgets to the list variable modules_per_string. All you need to do is make that global or an object attribute rather than a local variable so other functions can reference it.
As Bryan Oakley said, make list for widgets to store each objects of entries and label in two list.
For Example:
import tkinter as tk
class Demo:
def __init__(self):
self.root = tk.Tk()
self.root.geometry("600x600")
systems_label = tk.Label(self.root, text="No Of Systems:")
systems_label.place(x=100, y=20)
no_Of_System_Ent = tk.Entry(self.root, width=15)
no_Of_System_Ent.place(x=200, y=20)
submit_Button = tk.Button(self.root, text="Submit", command=lambda: self.process(no_Of_System_Ent.get()))
submit_Button.place(x=350,y=20)
def display(self,sys_len):
for i in range(sys_len):
buffer = self.obj_of_entries[i].get()
print(buffer)
def delete(self,sys_len):
for i in range(sys_len):
self.obj_of_entries[i].destroy()
self.obj_of_labels[i].destroy()
def process(self,length_sys):
self.obj_of_entries = []
self.obj_of_labels = []
y_pos = 80
for i in range(int(length_sys)):
#Adding objects of label in list 'obj_of_labels'
self.obj_of_labels.append(tk.Label(self.root,text="System "+str(i)))
self.obj_of_labels[len(self.obj_of_labels)-1].place(x=100,y=y_pos)
#Adding objects of entry in list 'obj_of_entries'
self.obj_of_entries.append(tk.Entry(self.root,width=15))
self.obj_of_entries[len(self.obj_of_entries)-1].place(x=200,y=y_pos)
#Increments Y by 50
y_pos = y_pos + 50
self.delete_Button = tk.Button(self.root, text="Delete All", command=lambda: self.delete(int(length_sys)))
self.delete_Button.place(x=200,y=400)
self.print_Button = tk.Button(self.root, text="Print All", command=lambda: self.display(int(length_sys)))
self.print_Button.place(x=350,y=400)
ob=Demo()
In this example:
I created a entry and button in the init function to take no of systems from user.
def __init__(self):
self.root = tk.Tk()
self.root.geometry("600x600")
systems_label = tk.Label(self.root, text="No Of Systems:")
systems_label.place(x=100, y=20)
no_Of_System_Ent = tk.Entry(self.root, width=15)
no_Of_System_Ent.place(x=200, y=20)
submit_Button = tk.Button(self.root, text="Submit", command=lambda: self.process(no_Of_System_Ent.get()))
submit_Button.place(x=350,y=20)
After clicking submit button,it will go to process function.
Ps: length_sys is the no of systems.
def process(self,length_sys):
self.obj_of_entries = []
self.obj_of_labels = []
y_pos = 80
for i in range(int(length_sys)):
#Adding objects of label in list 'obj_of_labels'
self.obj_of_labels.append(tk.Label(self.root,text="System "+str(i)))
self.obj_of_labels[len(self.obj_of_labels)-1].place(x=100,y=y_pos)
#Adding objects of entry in list 'obj_of_entries'
self.obj_of_entries.append(tk.Entry(self.root,width=15))
self.obj_of_entries[len(self.obj_of_entries)-1].place(x=200,y=y_pos)
#Increments Y by 50
y_pos = y_pos + 50
self.delete_Button = tk.Button(self.root, text="Delete All", command=lambda: self.delete(int(length_sys)))
self.delete_Button.place(x=200,y=400)
It will append the entry and label obj in its respective list and place the current obj in GUI window.
At Last,It will increment y axis by 80 so that next label and entry comes down to the previous one.
If user clicks delete all button,then it will go to delete all list obj of both entries and labels.
Ps: sys_len is the no of systems.
def delete(self,sys_len):
for i in range(sys_len):
self.obj_of_entries[i].destroy()
self.obj_of_labels[i].destroy()
To see the content,use this code:
(It will print in the Python shell so you can see if data is correct or not.)
def display(self,sys_len):
for i in range(sys_len):
buffer = self.obj_of_entries[i].get()
print(buffer)
I think I solved the doubt.
Ciao!