I want to sum values from treeview column no matter if one of the rows is empty, also I want to delete that row when the Sum button is pressed. I wrote a code but I always get this error:
IndexError: string index out of range
This is the code:
from tkinter import*
from tkinter import ttk
myApp = Tk()
myApp.title(" Program ")
TotalEntry=Entry(myApp, width=18)
TotalEntry.grid(row=0,column=1, sticky="e", pady=5)
NewTree= ttk.Treeview(myApp, height=7)
NewTree['show'] = 'headings'
NewTree["columns"]=("1")
NewTree.column("1", width=80, anchor="center")
NewTree.heading("1", text="ID")
item = NewTree.insert("", "end", values=(2))
item = NewTree.insert("", "end", values=(""))
item = NewTree.insert("", "end", values=(6))
NewTree.grid(row=0,column=0)
def SumAllCosts():
for i in NewTree.get_children():
a = NewTree.item(i,"values")[0]
if len(a)==0:
NewTree.delete(i)
SumPreCosts=0.0
for child in NewTree.get_children():
PreCost=round(float(NewTree.item(child,"values")[0]),2)
SumPreCosts += PreCost
TotalEntry.delete(0,"end")
TotalEntry.insert(0,round(SumPreCosts,2))
Sum=Button(myApp,text=" Sum ",command=SumAllCosts)
Sum.grid(row=0,column=2, sticky="w",pady=5)
myApp.mainloop()
If you print type(NewTree.item(i, "values")) and repr(NewTree.item(i, "values")), you can see that this returns
<class 'tuple'> ('2',)
<class 'str'> ''
<class 'tuple'> ('6',)
As you can see, for the 2 and 6 entry, this returns a tuple so you can do NewTree.item(i, "values")[0] to get the first value. However, the empty item is returned as an empty string, so NewTree.item(i, "values")[0] gives the error you describe.
You can change that part of the code to check if NewTree.item(i, "values") is not empty:
for i in NewTree.get_children():
if not NewTree.item(i, "values"):
NewTree.delete(i)
Related
Good,
I'm trying to sum the values of a column, while inputting it. Since I put a code in the entry and check if it exists and put it in columns in treeview, and I would like to add only the "price" values, but I can't do it, I get the data from the price column, but I can't get if This 5.99 I have entered another 5.99 add up and give me a total, as I add a price.
What I can be doing wrong? or what I have wrong
Any additional information would be appreciated.
def Cesta(self):
self.conex()
self.b_codigo = self.s_Codigo.get()
self.sql3 = "SELECT * FROM productos WHERE codigo = %s"
self.mycursor.execute(self.sql3,[(self.b_codigo)])
self.r_codigo = self.mycursor.fetchall()
self.row3 = [item['nombre'] for item in self.r_codigo]
if self.s_Codigo.get() == "":
MessageBox.showinfo("ERROR", "DEBES INTRODUCIR DATOS", icon="error")
elif self.r_codigo:
for self.x2 in self.r_codigo:
print (self.x2["nombre"], self.x2["talla"], self.x2["precio"]+"€")
self.tree.insert('', 'end', text=self.x2["nombre"], values=(self.x2["talla"],self.x2["precio"]+" €"))
print(self.x2["fecha"])
for self.item in self.tree.get_children():
self.resultado = 0
self.celda = int(self.tree.set(self.item,"col2"))
self.total = int(self.resultado) + int(float(self.celda))
print(self.total)
else:
MessageBox.showinfo("ERROR", "EL CODIGO INTRODUCIDO NO ES CORRECTO", icon="error")
self.clear_entry()
`
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/__init__.py", line 1921, in __call__
return self.func(*args)
File "/Users/tomas/Downloads/PROYECTO/main.py", line 205, in Cesta
self.celda = int(self.tree.set(self.item,"col2"))
ValueError: invalid literal for int() with base 10: '134,99 €'
[Finished in 6.7s]
`
self.tree = ttk.Treeview(self.pagina1,columns=("col1","col2"), height=50)
self.tree.grid(column=0, row=2, padx=50, pady=100)
### COLUMNAS ###
self.tree.column("#0",width=250)
self.tree.column("col1",width=150, anchor=CENTER)
self.tree.column("col2",width=150, anchor=CENTER)
### NOMBRES COLUMNAS ###
self.tree.heading("#0", text="Articulo", anchor=CENTER)
self.tree.heading("col1", text="Talla", anchor=CENTER)
self.tree.heading("col2", text="Precio", anchor=CENTER)
Everything else is going well for me, but the part in which I want to add the results of the price column does not
What am I doing wrong, to be able to add the values of the prices column every time I insert a new product?
I have already managed to solve the error, the new price is already added to the old one, thanks for making me reflect on it.
for self.x2 in self.r_codigo:
print (self.x2["nombre"], self.x2["talla"], self.x2["precio"]+"€")
self.tree.insert('', 'end', text=self.x2["nombre"], values=(self.x2["talla"],self.x2["precio"]))
self.total = 0
for self.item in self.tree.get_children():
self.celda = float(self.tree.set(self.item,"col2"))
self.total+=self.celda
print(self.total)
By selecting two comboboxes (combined with bind), I would like to extract the ID of a field from Table1 and insert it into Table2. I have no problems extracting a field based on a combobox, but I have problems extracting a field based on 2 comboboxes, because they are combined with each other. The problem is only def id_rounds() function.
I have two comboboxes: one in which I select the name of the "Tournament" and another in which I select the number of Rounds (from 1 to 38 different rounds for each tournament). To choose which tournament the tournament ID must match, I use the combobox combo_Tournaments and function def combo_tournaments; while to choose the number of the Round I use the combobox combo_Rounds and the combo_rounds function. By selecting the Tournament and / or Round, the relevant ID is also automatically entered (as well as the actual data). So each combobox puts in 2 things each, for a total of 4.
Here is the database:
CREATE TABLE "All_Tournament" (
"ID_Tournament" INTEGER,
"Tournament" TEXT,
PRIMARY KEY("Tournament" AUTOINCREMENT)
);
CREATE TABLE "All_Round" (
"ID_Round" INTEGER,
"Number_Round" INTEGER,
"ID_Tournament" INTEGER,
PRIMARY KEY("ID_Round" AUTOINCREMENT),
);
PROBLEM: Currently as I wrote the code of the function def id_rounds(), the ID of the selected Round is saved, but without exact correspondence to the chosen Tournament in the Tournament combobox. The problem is that each Tournament is each made up of 38 different Rounds, therefore in the All_Round table the numbers from 1 to 38 are repeated several times, each corresponding to the Tournament ID. For example Serie A from 1 to 38 Round; Serie B from 1 to 38 rounds; Premier League from 1 to 38 rounds. So I would like to enter the ID of the single Round corresponding to the Tournament (in relation to the tournament), because each tournament has 1 to 38 rounds, so there are many different "1 to 38 rounds" for each tournament.
#Combobox Tournament
lbl_Tournament = Label(root, text="Tournament", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Tournament.place(x=6, y=60)
combo_Tournaments = ttk.Combobox(root, font=("Calibri", 11), width=30, textvariable=campionato, state="readonly")
combo_Tournaments.place(x=180, y=60)
combo_Tournaments.set("Select")
combo_Tournaments['values'] = combo_tournaments()
combo_Tournaments.bind('<<ComboboxSelected>>', combo_teams)
lbl_Rounds = Label(root, text="Rounds", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Rounds.place(x=600, y=60)
combo_Rounds = ttk.Combobox(root, font=("Calibri", 11), width=30, textvariable=rounds, state="readonly")
combo_Rounds.place(x=680, y=60)
combo_Rounds.set("Select")
combo_Rounds['values'] = combo_campionati()
combo_Tournaments.bind('<<ComboboxSelected>>', combo_rounds, add=True)
def combo_tournaments():
tournaments = combo_tournaments.get()
cursor.execute('SELECT Tournament FROM All_Tournament')
result=[row[0] for row in cursor]
return result
def id_tournaments():
tournaments = combo_tournaments.get()
cursor.execute('SELECT ID_Tournament FROM All_Tournament WHERE Tournament=?',(tournaments,))
result=[row[0] for row in cursor]
return result[0]
def combo_rounds(event=None):
rounds = combo_rounds.get()
cursor.execute('SELECT Number_Round From All_Round WHERE ID_Tournament')
result=[row[0] for row in cursor]
combo_Rounds['value'] = result
return result
#THE PROBLEM IS HERE
def id_rounds():
rounds = combo_rounds.get()
cursor.execute('SELECT ID_Round FROM All_Round WHERE Number_Round=? AND Tournament=?',(rounds, tournaments))
result=[row[0] for row in cursor]
return result[0]
def combo_teams(event=None):
tournaments = combo_tournaments.get()
cursor.execute('SELECT s.Name_Teams FROM All_Teams s, All_Tournament c WHERE s.ID_Tournament=c.ID_Tournament AND c.Tournament = ?', (tournaments,))
result=[row[0] for row in cursor]
combo_Teams_1['values'] = result
combo_Teams_2['values'] = result
return result
WHAT DO I WANT TO GET? So I would like to obtain for example that: if from the Tournament combobox I select Serie A and then Round 1, in the Results table the ID of Round 1 should be entered but corresponding to Serie A. Or, another example, if from the Tournament combobox I select Serie B and then Round 1, the ID of Round 1 should be entered in the Results table but corresponding to Serie B.
QUESTION: How can I fix the function def id_rounds and which inserts the number of the Round in correspondence (in relation) to the tournament? Currently I only enter the ID of the selected Round in the combobox without matching the championship chosen in the tournament combobox.
Below is the modified code based on my understanding:
def combo_tournaments():
cursor.execute('SELECT Tournament FROM All_Tournament')
result=[row[0] for row in cursor]
return result
def combo_rounds(event=None):
# get all Number_Round for selected tournament
cursor.execute('''
SELECT Number_Round From All_Round r, All_Tournament t
WHERE r.ID_Tournament = t.ID_Tournament AND Tournament = ?''', (campionato.get(),))
result=[row[0] for row in cursor]
combo_Rounds['value'] = result # update combo_Rounds
rounds.set('Select') # reset Rounds selection
return result
def id_rounds(event=None):
# get the ID_Round based on selected tournament and Number_Round
cursor.execute('''
SELECT ID_Round FROM All_Round r, All_Tournament t
WHERE r.ID_Tournament = t.ID_Tournament AND Number_Round = ? AND Tournament = ?''',
(rounds.get(), campionato.get()))
result = cursor.fetchone()
if result:
print(result[0])
return result[0]
return None
...
campionato = StringVar()
rounds = StringVar()
#Combobox Tournament
lbl_Tournament = Label(root, text="Tournament", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Tournament.place(x=6, y=60)
combo_Tournaments = ttk.Combobox(root, font=("Calibri", 11), width=30, textvariable=campionato, state="readonly")
combo_Tournaments.place(x=180, y=60)
combo_Tournaments.set("Select")
combo_Tournaments['values'] = combo_tournaments()
combo_Tournaments.bind('<<ComboboxSelected>>', combo_rounds)
lbl_Rounds = Label(root, text="Rounds", font=("Calibri", 11), bg="#E95420", fg="white")
lbl_Rounds.place(x=600, y=60)
combo_Rounds = ttk.Combobox(root, font=("Calibri", 11), width=30, textvariable=rounds, state="readonly")
combo_Rounds.place(x=680, y=60)
combo_Rounds.set("Select")
combo_Rounds.bind('<<ComboboxSelected>>', id_rounds)
...
Note that I have used the campionato and rounds (StringVar) to get the selected tournament and Number_Round.
*I wanted to bind platform_id drop combobox to teh combobox_b so taht if cpu is selected in platform_id_drop, then cpu frequencies must be listed otherwise gpu frequencies must be listed. I am using while loop to create a number of rows based on input we are giving and used dictionary to store respective columns. I am able to get only fo rone set of row i.e frequencies are display oly for one row but not for other rows. Having Problem with bind function. Please help me with this.
'''
import pandas as pd
from tkinter import filedialog
from tkinter import ttk
from tkinter.filedialog import asksaveasfile
import collections
app=Tk()
app.title("trace")
app.geometry("1000x500")
global z
required=2
z=required
global global_id
global_id=0
global text_file_3
global text_file_4
a_dict = collections.defaultdict(list)
a_dict['global_id']={}
a_dict['unique_dag_id']={}
a_dict['platform_id']={}
a_dict['deadline']={}
a_dict['wcet_cpu']={}
a_dict['wcet_gpu']={}
a_dict['input_arrival_time']={}
a_dict['hyper_period_entry']={}
a_dict['input_task_period']={}
a_dict['frequency']={}
unique_dag_id = StringVar()
wcet_cpu = StringVar()
wcet_gpu = StringVar()
deadline = StringVar()
input_arrival_time = StringVar()
hyper_period_entry = StringVar()
input_task_period=StringVar()
frequency=StringVar()
last_county=StringVar()
v=[]
dict1={'gpu':['177000000' ,'266000000' ,'350000000' ,'420000000' ,'480000000', '543000000' , '600000000'],'cpu':['200000000', '300000000', '400000000', '500000000', '600000000', '700000000', '800000000', '900000000', '1000000000' ,'1100000000', '1200000000', '1300000000', '1400000000', '1500000000' ,'1600000000', '1700000000', '1800000000', '1900000000', '2000000000']}
def save_trace1():
global global_id
global_id_info=global_id_entry
if(platform_id_drop.get()=='cpu'):
platform_id_info=0
else:
platform_id_info=1
unique_dag_id_info=unique_dag_id_entry
wcet_cpu_info=wcet_cpu_entry.get()
wcet_gpu_info=wcet_gpu_entry.get()
deadline_info=deadline_entry.get()
input_arrival_time_info=input_arrival_time_entry.get()
hyper_period_entry_info=hyper_period_entry_entry.get()
input_task_period_info=input_task_period_entry.get()
combobox_b_info=combobox_b.get()
for i in range(required):
print(a_dict['platform_id'][i].get())
global_id_label=Label(text="global_id ")
platform_id_label=Label(text='platform_id')
unique_dag_id_label=Label(text='unique_dag-id')
wcet_cpu_label=Label(text='wcet_cpu')
wcet_gpu_label=Label(text='wcet_gpu')
deadline_label=Label(text='deadline')
input_arrival_time_label=Label(text='input-arrival time')
hyper_period_entry_label=Label(text='hyper_period_entry')
input_task_period_label=Label(text='input_task_period')
freq_label=Label(text='Frequency')
platform_id_options=[
'cpu','gpu',
]
global_id_label.place(x=50,y=50)
platform_id_label.place(x=150,y=50)
unique_dag_id_label.place(x=330,y=50)
wcet_cpu_label.place(x=450,y=50)
wcet_gpu_label.place(x=600,y=50)
deadline_label.place(x=750,y=50)
input_arrival_time_label.place(x=900,y=50)
hyper_period_entry_label.place(x=1050,y=50)
input_task_period_label.place(x=1200,y=50)
freq_label.place(x=1350,y=50)
trace_entries=[]
dag_entries=[]
while(z>0):
#platform_id_drop.pack(pady=20)
def selo(eventobj):
v=[]
if(platform_id_drop.get()=='cpu'):
print("a")
v=['200000000', '300000000', '400000000', '500000000', '600000000',
'700000000', '800000000', '900000000', '1000000000' ,'1100000000', '1200000000', '1300000000', '1400000000', '1500000000' ,'1600000000', '1700000000', '1800000000', '1900000000', '2000000000']
elif(platform_id_drop.get()=='gpu'):
print("m")
v=['177000000' ,'266000000' ,'350000000' ,'420000000' ,'480000000', '543000000' , '600000000']
global_id_entry=Label(text=str(global_id))
global_id_entry.place(x=50,y=50+60*(global_id+1))
a_dict['global_id'][global_id]=global_id
unique_dag_id_entry=Label(text=str(global_id))
unique_dag_id_entry.place(x=330,y=50+60*(global_id+1))
a_dict['unique_dag_id'][global_id]=unique_dag_id_entry
wcet_cpu_entry=Entry(app)
wcet_cpu_entry.place(x=450,y=50+60*(global_id+1))
a_dict['wcet_cpu'][global_id]=wcet_cpu_entry
wcet_gpu_entry=Entry(app)
wcet_gpu_entry.place(x=600,y=50+60*(global_id+1))
a_dict['wcet_gpu'][global_id]=wcet_gpu_entry
deadline_entry=Entry(app)
deadline_entry.place(x=750,y=50+60*(global_id+1))
a_dict['deadline'][global_id]=(deadline_entry)
input_arrival_time_entry=Entry(app)
input_arrival_time_entry.place(x=900,y=50+60*(global_id+1))
a_dict['input_arrival_time'][global_id]=(input_arrival_time_entry)
hyper_period_entry_entry=Entry(app)
hyper_period_entry_entry.place(x=1050,y=50+60*(global_id+1))
a_dict['hyper_period_entry'][global_id]=(hyper_period_entry_entry)
input_task_period_entry=Entry(app)
input_task_period_entry.place(x=1200,y=50+60*(global_id+1))
a_dict['input_task_period'][global_id]=( input_task_period_entry)
platform_id_drop=ttk.Combobox(app,values=platform_id_options)
platform_id_drop.bind("<<ComboboxSelected>>",selo)
platform_id_drop.place(x=150,y=50+60*(global_id+1))
a_dict['platform_id'][global_id]=platform_id_drop
combobox_b = ttk.Combobox(app,values=v)
combobox_b.place(x=1350,y=50+60*(global_id+1))
a_dict['frequency'][global_id]=( combobox_b )
v.clear()
global_id=global_id+1
z=z-1
button=Button(app,text="save_info",command=save_trace1)
button.place(x=0,y=0)
app.mainloop()
'''
I creating GUI interacting with treeview and I want to get all the value inside the list and show it in treeview window. I have a add button and once I click it, it will work fine. But on the second time, it shows an error Item 1 already exists. It also does not added to the list.
This is my code:
from tkinter import *
from tkinter import ttk
root = Tk()
def add1():
global count
for i in tree_table.get_children():
tree_table.delete(i)
get_name = txt_name.get()
get_ref = txt_ref.get()
get_age = txt_age.get()
get_email = txt_email.get()
data_list.append((get_name, get_ref, get_age, get_email))
for item in data_list:
tree_table.insert(parent='', index='end', iid=count, text=f'{count + 1}', values=(item))
txt_name.delete(0, END)
txt_ref.delete(0, END)
txt_age.delete(0, END)
txt_email.delete(0, END)
count += 1
print(data_list)
tree_table = ttk.Treeview(root)
global count
count = 0
data_list = []
tree_table['columns'] = ("Name", "Reference No.", "Age", "Email Address")
tree_table.column("#0", width=30)
tree_table.column("Name", width=120, anchor=W)
tree_table.column("Reference No.", width=120, anchor=W)
tree_table.column("Age", width=120, anchor=W)
tree_table.column("Email Address", width=120, anchor=W)
headings = ["#0", "Name", "Reference No.", "Age", "Email Address"]
txt_headings = ["No.", "Name", "Reference No.", "Age", "Email Address"]
for i in range(len(headings)):
tree_table.heading(headings[i], text=txt_headings[i], anchor=W)
txt_name = Entry(root, width=20)
txt_name.pack()
txt_ref = Entry(root, width=20)
txt_ref.pack()
txt_age = Entry(root, width=20)
txt_age.pack()
txt_email = Entry(root, width=20)
txt_email.pack()
btn_enter = Button(root, text="Add", width=20, command=add1)
btn_enter.pack()
tree_table.pack()
root.mainloop()
Traceback:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\Python385\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "d:/Code/Cpet5/new.py", line 32, in add1
tree_table.insert(parent='', index='end', iid=count, text=f'{count + 1}', values=(item))
File "C:\Python\Python385\lib\tkinter\ttk.py", line 1366, in insert
res = self.tk.call(self._w, "insert", parent, index,
_tkinter.TclError: Item 1 already exists
How do I refresh the treeview to reflect the changes made in the list?
Quick fix:
Get rid of the iid argument:
tree_table.insert(parent='', index='end', text=f'{count + 1}', values=(item))
But that will create an issue of the No. column getting same value always.
Actual fix:
So the actual problem is your list contains alot of values, you should get rid of those values once you insert it, so the code should be something like:
def add1():
global count
get_name = txt_name.get()
get_ref = txt_ref.get()
get_age = txt_age.get()
get_email = txt_email.get()
data_list.clear() #clear the list
data_list.append((get_name, get_ref, get_age, get_email)) #append to the empty list
for item in data_list:
tree_table.insert(parent='', index='end',iid=count, text=f'{count + 1}', values=(item))
txt_name.delete(0, END)
txt_ref.delete(0, END)
txt_age.delete(0, END)
txt_email.delete(0, END)
count += 1
print(data_list)
This way your clearing whats inside of the list each time and appending new values to list.
With your older code you can see that first time the the list is [('1', '1', '1', '1')] and when the next set of values is appended it becomes [('1', '1', '1', '1'), ('2', '2', '2', '2')] so there is not enough space accommodate all this value in? Anyway this fixes it. Or you could also make a tuple of those inputs and then pass that tuple as the values for treeview without looping, like acw1668 did.
You don't need to clear the treeview before adding new row to it:
def add1():
global count
get_name = txt_name.get()
get_ref = txt_ref.get()
get_age = txt_age.get()
get_email = txt_email.get()
row = (get_name, get_ref, get_age, get_email)
data_list.append(row)
count += 1
tree_table.insert(parent='', index='end', iid=count, text=f'{count}', values=row)
txt_name.delete(0, END)
txt_ref.delete(0, END)
txt_age.delete(0, END)
txt_email.delete(0, END)
print(data_list)
I have a dictionary in the form:
{
"filename":"file.txt",
"filesize":"500kb",
"maxcolwidth":{
"col1":"300",
"col2":"2",
"col3":"3"},
"numberofcolumns":"3",
"datatypes":{
"col1":"string",
"col2":"int",
"col3":"int"},
"rowcount":"400"
}
I'm currently using Tkinter for python to build a GUI, but cannot find an easy/elegant way of displaying the following dictionary in either a tkinter treeview widget or a nicely formatted string to display in a text box. The output i was looking for was something like this:
Filename - file.txt
Filesize - 500KB
Maxcolwidth - col1 - 300
col2 - 2
col3 - 3
Numberofcolumns - 3
Datatypes - col1 - string
col2 - int
col3 - int
rowcount - 400
or more like a hierarchical tree
Filename
file.txt
Filesize
500KB
Maxcolwidth
col1
300
col2
2
col3
3
Numberofcolumns
3
Datatypes
col1
string
col2
int
col3
int
rowcount
400
Any ideas?
Thanks in advance
The solution is to create a treeview with one additional column, and then add a function that adds an item to the tree. It adds an item, and if the value is a dictionary, it recurses through all of the child elements.
Here's a simple example using python 2.x. For python 3.x you only have to change the imports. I don't know if it meets your definition of "elegant" or "easy".
import Tkinter as tk
import ttk
DATA = {
"filename":"file.txt",
"filesize":"500kb",
"maxcolwidth": {
"col1":"300",
"col2":"2",
"col3":"3"
},
"numberofcolumns":"3",
"datatypes": {
"col1":"string",
"col2":"int",
"col3":"int"
},
"rowcount":"400"
}
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.tree = ttk.Treeview(self, columns=("value",))
self.vsb = ttk.Scrollbar(self, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.tree.pack(side="top", fill="both", expand=True)
self.addNode(value=DATA, parentNode="")
def addNode(self, value, parentNode="", key=None):
if key is None:
id = ""
else:
id = self.tree.insert(parentNode, "end", text=key)
if isinstance(value, dict):
self.tree.item(id, open=True)
for (key, value) in value.iteritems():
self.addNode(value, id, key)
else:
self.tree.item(id, values=(value,))
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()