Extracting rows within Python Tkinter-Treeview into a Pandas data frame - python

I have a GUI where results from a dataframe are populated into a treeview within python based on filters previously input. The user can then click on treeview and update the values to the desired number. The number of rows within the view can vary from 1 - 20+. Once the user has updated the view as desired, I have a button below "Check Allocation".
It is at this point I want to "export" the treeview into a dataframe for me to run against another table. I cant seem to simply export this as a dataframe. Is there any work around this? I only need the first and last columns (of the 8) to check the newly updated file.
Here is what I have so far.
def PrintAllocation(self):
treeview = tkk.Treeview(root)
treeview.grid(column = 1, row = 8, columnspan = 4, padx = 1, pady = 1)
cols = list(matches.columns)
treeview["columns"] = cols
for i in cols:
treeview.column(i, width = 100, anchor = "w")
treeview.heading(i,text=i,anchor='w',)
for index, row in matches.iterrows():
treeview.insert("",0,text=index,values=list(row))
def set_cell_value(event): # Double click to enter the edit state
for item in treeview.selection():
#item = I001
item_text = treeview.item(item, "values")
#print(item_text[0:2]) # Output the value of the selected row
column= treeview.identify_column(event.x)# column
print(column)
row = treeview.identify_row(event.y) #row
cn = int(str(column).replace('#',''))
rn = int(str(row).replace('I',''))
if column == '#8':
entryedit = Text(root,width=50,height = 1)
entryedit.grid(column = 2, row = 9, padx = 1, pady = 1)
else:
entryedit = Text(root,width=10,height = 1)
entryedit.grid(column = 2, row = 9, padx = 1, pady = 1)
def saveedit():
treeview.set(item, column=column, value=entryedit.get(0.0, "end"))
entryedit.destroy()
okb.destroy()
okb = ttk.Button(root, text='OK', width=4, command=saveedit)
okb.grid(column = 3, row = 9,padx = 1, pady=1)
def CheckAllocation():
children = treeview.getchildren()
for child in children:
print(treeview.set(child))
treeview.bind('<Double-1>', set_cell_value) # Double-click the left button to enter the edit
button_check = Button(root,text="Check Allocation", command = CheckAllocation)
button_check.grid(column = 2, row = 10, padx = 10, pady=10)
'''

I don't really understand your code but when I need to get a treeview to pandas I do it as follows:
First I create an empty list for each column in the treeview.
column_a_list = []
column_b_list = []
column_c_list = []
column_d_list = []
Then running through the lines of the treeview in a "for" function, I append to each column list the value of the column in each line.
for child in self.treeview.get_children():
column_a_list.append(self.treeview.item(child)["values"][0])
column_b_list.append(self.treeview.item(child)["values"][1])
column_c_list.append(self.treeview.item(child)["values"][2])
column_d_list.append(self.treeview.item(child)["values"][3])
Then I create a dictionary from all the lists, using the header as the key and lists are the values as a list.
full_treeview_data_dict = {'HEADER A': column_a_list, 'HEADER B': column_b_list, 'HEADER C': column_c_list, 'HEADER D': column_d_list,}
Then I create a dataframe from the dictionary.
treeview_df = pd.DataFrame.from_dict(full_treeview_data_dict)
Here is the full sample code in one chunk:
column_a_list = []
column_b_list = []
column_c_list = []
column_d_list = []
for child in self.treeview.get_children():
column_a_list.append(self.treeview.item(child)["values"][0])
column_b_list.append(self.treeview.item(child)["values"][1])
column_c_list.append(self.treeview.item(child)["values"][2])
column_d_list.append(self.treeview.item(child)["values"][3])
full_treeview_data_dict = {'HEADER A': column_a_list, 'HEADER B': column_b_list, 'HEADER C': column_c_list, 'HEADER D': column_d_list,}
treeview_df = pd.DataFrame.from_dict(full_treeview_data_dict)
I hope it helps.

You can also do this:
row_list = []
columns = ('name', 'school', 'c3', 'c4')
for row in treeview.get_children():
row_list.append(treeview.item(row)["values"])
treeview_df = pd.DataFrame(row_list, columns = columns)

The current answer is good, I just wanted to add my two cents here:
self.treeview_columns = [] # list of names here
# initialize empty df
# if too big you can preallocate but probably not needed
treeview_df = pd.DataFrame(None, columns=self.treeview_columns)
for row in self.treeview.get_children():
# each row will come as a list under name "values"
values = pd.DataFrame([self.treeview.item(row)["values"]],
columns=self.treeview_columns)
# print(values)
treeview_df = treeview_df.append(values)
This way you grow your df row by row using append and you reduce the number of subsets that you need to do.

Related

Tkinter delete not working on referenced entry when referenceing lenth of entry

I have a tkinter window class that I've made and my delete function is not working properly.
my_window = tk.Tk()
class QuoteForm():
def __init__(self,master):
self.file_data = ''
self.master = master
self.master.rowconfigure(0, weight=1)
self.master.rowconfigure(1, weight= 1)
self.master.rowconfigure(2, weight = 1)
master.geometry('600x400')
master.resizable(False,False)
#create the frames
self.directory_frm = tk.Frame(master=master)
self.directory_frm.grid(row=0) #this is the frame for the directory
self.add_on_frm = tk.Frame(master=master)
self.add_on_frm.grid(row=1) #this is the frame for add-ons input
self.button_frm = tk.Frame(master=master)
self.button_frm.grid(row=2) #this is the frame for
#creates buttons, entries, labels
self.load_directory_frame() #creates and grids the directory button
self.load_add_on_frame() #creates and grids the entry buttons and labels
self.load_button_frame() #creates and grids the buttons
my_window.mainloop()
def load_add_on_frame(self):
vcmd = (self.master.register(self.validate_ent), '%S')
#create inputs and labels for add-ons
self.trip_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd, name='trip_ent')
self.trip_ent.grid(column= 1, row = 0)
self.raw_cutouts_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.raw_cutouts_ent.grid(column= 3, row = 0)
def clear_entries(self):
entries = (self.trip_ent, self.raw_cutouts_ent) #list of entries to loop (there are a total of 12 in the actual code)
for entry in entries:
entry.delete(0,len(entry.get())) #this is where the trouble seems to happen
new_quote = QuoteForm(my_window)
My problem is that the on the second to last line of code (starting with 'entry.delete')
Typically you would do 'entry.delete(0,END)' but because entry is a variable the code won't run with END.
'END' is an invalid index, and 'end' just does the same as pulling the length, and so i tried to make it dynamic by making the 'end' the length of whatever is in the entry.
When i do that however, it deletes nothing [i also tried forcing it with int(len(entry.get()))]. If i manually enter an integer it will delete everything up to that integer, including if it's the same as the length of that entry, and I put breaks to confirm that i'm getting an int return and I am.
I realize i could just write a line of code to delete each entry individually, but there's a totaly of 12 and I would like to clean it up.
I'm adding the full code to be able to run below
import os
import re
import tkinter as tk
from tkinter import filedialog as fd
from tkinter import messagebox
import pandas as pd
my_window = tk.Tk()
class QuoteForm():
def __init__(self,master):
self.file_data = ''
self.master = master
self.master.rowconfigure(0, weight=1)
self.master.rowconfigure(1, weight= 1)
self.master.rowconfigure(2, weight = 1)
master.geometry('600x400')
master.resizable(False,False)
self.directory_frm = tk.Frame(master=master)
self.directory_frm.grid(row=0) #this is the frame for the directory
self.add_on_frm = tk.Frame(master=master)
self.add_on_frm.grid(row=1) #this is the frame for add-ons input
self.button_frm = tk.Frame(master=master)
self.button_frm.grid(row=2) #this is the frame for
self.load_directory_frame()
self.load_add_on_frame()
self.load_button_frame()
my_window.mainloop()
#staticmethod
def get_quote_data(filepath):
#read csv to get job infomation for pricing
try:
if filepath:
job_info = pd.read_csv(filepath,
index_col=0, #set index column
skiprows=range(4), #skip first 4 rows
usecols=['Item','Quan'])
job_info = job_info.drop(labels='Grand Total:', axis= 0)
customer_info = pd.read_csv(filepath, header=None,
skiprows= lambda x: x not in range(2), #skip any row beyond first two rows
usecols=[0,1]) #use first two columns
customer_info = {customer_info.at[0,0].replace(':',''): customer_info.at[0,1], ##formatting the data for legibility
customer_info.at[1,0].replace(':','') : customer_info.at[1,1]}
return [customer_info, job_info]
except:
messagebox.showerror("Data Invalid", "Please make sure you select a valid estimate CSV file.")
def sink_check(self):
####this is to be used at the submit buttons to confirm that there are not more sinks than cutouts
cutouts = self.um_sink_inst_ent.get()
sink_quan_list = (self.std_sink_ent.get(),self.upgrd_sink_ent.get(),self.van_sink_ent.get(),self.cust_sink_temp_ent.get())
sinks = sum(sink_quan_list)
if sinks > cutouts:
return False
###check that the sinks included does not exceed the number of sinks charged for install
return True
def validate_ent(self,input):
if not input:
return True
elif re.fullmatch(r'[0-9]',input):
return True
return False
def open_file(self):
file = fd.askopenfile(mode='r', filetypes=[('CSV Files', '*.csv')])
if file:
filepath = os.path.abspath(file.name)
file_data = self.get_quote_data(filepath)
cust_name = file_data[0]['Name']
job_addr = file_data[0]['Addr']
self.file_select_text['text'] = f"{job_addr} for {cust_name} is currently selected"
def load_directory_frame(self):
file_select_btn = tk.Button(master=self.directory_frm,text= "Select a file",command=self.open_file)
file_select_btn.grid(column=0, row=0)
self.file_select_text = tk.Label(master=self.directory_frm, text = "No File Selected")
self.file_select_text.grid(column=1, row=0)
def load_add_on_frame(self):
vcmd = (self.master.register(self.validate_ent), '%S')
#create inputs and labels for add-ons
self.trip_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd, name='trip_ent')
self.trip_ent.grid(column= 1, row = 0)
self.raw_cutouts_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.raw_cutouts_ent.grid(column= 3, row = 0)
self.radii_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.radii_ent.grid(column= 1, row = 1)
self.arcs_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.arcs_ent.grid(column= 3, row = 1)
self.splay_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.splay_ent.grid(column= 1, row = 2)
self.wtrfall_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.wtrfall_ent.grid(column= 3, row = 2)
self.um_sink_inst_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.um_sink_inst_ent.grid(column= 1, row = 3)
self.farm_sink_co_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.farm_sink_co_ent.grid(column= 3, row = 3)
self.std_sink_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.std_sink_ent.grid(column= 1, row = 4)
self.upgrd_sink_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.upgrd_sink_ent.grid(column= 3, row = 4)
self.van_sink_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.van_sink_ent.grid(column= 1, row = 5)
self.cust_sink_temp_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
self.cust_sink_temp_ent.grid(column= 3, row = 5)
trip_lbl = tk.Label(master=self.add_on_frm,text = "Extra Trip(s)")
trip_lbl.grid(column= 0, row = 0)
raw_cutouts_lbl = tk.Label(master=self.add_on_frm,text = "Unpolished Cutout(s)")
raw_cutouts_lbl.grid(column= 2, row = 0)
radii_lbl = tk.Label(master=self.add_on_frm,text = "Radii")
radii_lbl.grid(column= 0, row = 1)
arcs_lbl = tk.Label(master=self.add_on_frm,text = "Arc(s)")
arcs_lbl.grid(column= 2, row = 1)
splay_lbl = tk.Label(master=self.add_on_frm,text = "Splay(s)")
splay_lbl.grid(column= 0, row = 2)
wtrfall_lbl = tk.Label(master=self.add_on_frm,text = "Waterfal Leg(s)")
wtrfall_lbl.grid(column= 2, row = 2)
um_sink_inst_lbl = tk.Label(master=self.add_on_frm,text = "Install of UM Sink(s)")
um_sink_inst_lbl.grid(column= 0, row = 3)
farm_sink_co_lbl = tk.Label(master=self.add_on_frm,text = "Farm Sink C/O")
farm_sink_co_lbl.grid(column= 2, row = 3)
std_sink_lbl = tk.Label(master=self.add_on_frm,text = "Standard 18ga Sink(s)")
std_sink_lbl.grid(column= 0, row = 4)
upgrd_sink_lbl = tk.Label(master=self.add_on_frm,text = "Upgrade 18ga Sink(s)")
upgrd_sink_lbl.grid(column= 2, row = 4)
van_sink_lbl = tk.Label(master=self.add_on_frm,text = "Vanity Sink(s)")
van_sink_lbl.grid(column= 0, row = 5)
cust_sink_temp_lbl = tk.Label(master=self.add_on_frm,text = "Customer Sink Template(s)")
cust_sink_temp_lbl.grid(column= 2, row = 5)
def load_button_frame(self):
submit_btn = tk.Button(master=self.button_frm, text='Submit')
submit_btn.grid(column=0,row=0)
clear_btn = tk.Button(master=self.button_frm,text='Clear',command=self.clear_entries)
clear_btn.grid(column=1, row=0)
advanced_btn = tk.Button(master=self.button_frm,text='Advanced')
advanced_btn.grid(column=2, row=0)
def clear_entries(self):
entries = (self.trip_ent, self.raw_cutouts_ent, self.radii_ent, self.arcs_ent, self.splay_ent, #list of entry boxes on the form
self.wtrfall_ent, self.um_sink_inst_ent, self.um_sink_inst_ent, self.farm_sink_co_ent,
self.std_sink_ent, self.upgrd_sink_ent, self.van_sink_ent, self.cust_sink_temp_ent)
for entry in entries:
entry.delete(0,tk.END)
new_quote = QuoteForm(my_window)
It's all about yourvalidate_ent function. Only when it returns true then your entry text can change. While typing tkinter just sent single chars like '1','2','a'. Even when you remove with backspace, this function gets the character you are trying to remove. However when you try to clear it function gets as an input whole string like '123543123'. This is not takes place inside r'[0-9]' reguler expression and you return false so tkinter denies removing it.
There is two simple solution to fix this.
First one add another condition for longer input like:
def validate_ent(self,input):
if not input:
return True
elif re.fullmatch(r'[0-9]',input):
return True
if(len(input)>2):
return True
return False
However I do not recommend this one because if someone copy paste longer inputs then it can write letters inside entry boxes.
def validate_ent(self,input):
if not input:
return True
elif re.fullmatch(r'[0-9]*',input):
return True
return False
In here we added a asteriks to reguler expression. Now it's accepting numbers bigger then 9. Now people can also paste numbers that fits into this rule. Also removing works as expected!

Pythonic Logic - Seeking a more efficient approach to multiple if statements that check a list of 0's and 1's

I've been working on a simple GUI within Python to pull data from PowerBi, that looks similar to the image below:
The app works fine, however I am looking to improve it's efficiency.
The checkbar is produced with the following code:
Datasets = [
'Option 1', 'Option 2', 'Option 3',
'Option 4', 'Option 5',
'Option 6', 'Option 7',
'Option 8', 'Option 9']
print(os.getcwd())
cwd = os.getcwd
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var, width=22, anchor='w')
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return map((lambda var: var.get()), self.vars)
if __name__ == '__main__':
root = Tk()
root.title("PowerBI Data Collector")
root.iconphoto(True, PhotoImage(
file="Icon/Directory"))
responseLabel = Label(root)
# Check
data1 = Checkbar(root, Datasets[0:3], anchor=W)
data2 = Checkbar(root, Datasets[3:6], anchor=W)
data3 = Checkbar(root, Datasets[6:9], anchor=W)
data1.grid(row = 3, column = 1, padx = 1, pady = 1)
data1.config(relief=GROOVE, bd=1)
data2.grid(row = 4, column = 1, padx = 1, pady = 1)
data2.config(relief=GROOVE, bd=1)
data3.grid(row = 5, column = 1, padx = 1, pady = 1)
data3.config(relief=GROOVE, bd=1)
Based on the user's choice's from the checkbars, a list of 0's and 1's is produced describing the state of the input, using the code:
dataState = list(data1.state())
dataState.extend(list(data2.state()))
dataState.extend(list(data3.state()))
As such, if option 2 and option 4 is chosen, the dataState will read: [0,1,0,1,0,0,0,0,0]
From here there are a number of if statements that check for whether their respective integers from the list is a 1, and if so calls the respective function to pull the data specific to that checkbox from PowerBi. A few of which are detailed below:
if dataState == [0]*len(Datasets): # nothing
responseLabel.destroy()
responseLabel = Label(text = "Please select from the checklist above")
responseLabel.grid(row = 7, column = 1)
if dataState[0] == 1: # option2
# Response Label
responseLabel.destroy()
try:
uf.option2(User=userDetails[0], Pass = userDetails[1])
responseLabel = Label(text = "All data downloaded")
responseLabel.grid(row = 7, column = 1)
except:
responseLabel = Label(text = "option 1 data download failed")
responseLabel.grid(row = 7, column = 1)
if dataState[1] == 1: # option1
# Response Label
responseLabel.destroy()
try:
uf.option1(User=userDetails[0], Pass = userDetails[1])
responseLabel = Label(text = "All data downloaded")
responseLabel.grid(row = 7, column = 1)
except:
responseLabel = Label(text = "option 2 data download failed")
responseLabel.grid(row = 7, column = 1)
This is quite inefficient and was fine when there were only 3 options, but now there are 9, and more are expected to be added. I was thinking of converting the if statement section to a for loop, and the iteration of the loop that corresponded to a 1 within the list called a specific function, but this too seemed inefficient so I pose the question here, with the hopes of finding a better suggestion.
Thanks!
A simple, scalable option would be to make each option's code into a function and put them into a list or tuple, e.g.:
optionFunc = (opt1, opt2, opt3, etc.)
Then you could iterate through dataState and call the associated function, something like:
for index, state in enumerate(dataState):
if state:
option_func[index](responseLabel)
There may be a more sophisticated way to do this, maybe the GUI code you're using can associate labels with the checkboxes that you can use as dictionary indexes, but this would be the general idea.
(I put optionFunc in camelCase to be consistent with the rest of your code, but in Python snake_case would be the preferred form)
The only difference I see between the code under the if of option1 and option2 is the function being called: uf.option1 vs uf.option2 and also in the failure print. this duplication of code can be avoided.
first, use a dictionary to map between the option and its function in uf:
option_funcs={1: uf.option1, 2: uf.option2 ...}
then convert the code in your "if"s to a function that gets an integer option as parameter and calls the relevant uf.option
def download_data(option):
responseLabel.destroy()
try:
option_funcs[option](User=userDetails[0], Pass = userDetails[1])
responseLabel = Label(text = "All data downloaded")
responseLabel.grid(row = 7, column = 1)
except:
responseLabel = Label(text = "option {} data download failed".format(option))
responseLabel.grid(row = 7, column = 1)
finally, replace all of your ifs with a for that iterates over dataState:
for count, value in enumerate(dataState, start=1):
if value: download_data(count)

how to disable all columns apart from one column in Qtablewidget PYQT - python

Problem Statement:
Disable specific columns and enable specific row on bases of current row index.
I am working on Qtablewidget i tried following code this working fine for disable.
i wanted to enable tablewidget row contents on bases of row index .
when i clicked pushbutton that row should be enable.I am new to the stackoverflow please guide me.I am tring to enable tablewidget cell,pushbutton,combobox i am not getting please guide me how to enble particular row on bases of index.
Code :
self.tableWidget = QtGui.QTableWidget(self.centralwidget)
self.tableWidget.setColumnCount(4)
myresult = [(u'sandeep', u'checkbox'), (u'shivaraj', u'checkbox')]
for row, result in enumerate(myresult):
self.tableWidget.insertRow(self.tableWidget.rowCount())
for column, value in enumerate(result):
item = QtGui.QTableWidgetItem(str(value))
if column == 1:
if (value == "textbox"):
self.cb = QtGui.QComboBox()
lis = ("---select---", "description", "multiple_input")
self.cb.addItems(lis)
self.cb.setCurrentIndex(1)
self.tableWidget.setCellWidget(row, column, self.cb)
self.cb.setEnabled(False)#this is for combobox disable
elif (value == "checkbox"):
self.cb = QtGui.QComboBox()
lis = ("---select---", "description", "multiple_input")
self.cb.addItems(lis)
self.cb.setCurrentIndex(2)
self.tableWidget.setCellWidget(row, column, self.cb)
self.cb.setEnabled(False)#this is for combobox disable
self.tableWidget.setItem(row, column, item)
item.setFlags(QtCore.Qt.ItemIsEnabled)#this is for text non editable
self.btn_sell = QtGui.QPushButton('Edit')
self.btn_sell1 = QtGui.QPushButton('Delete')
self.btn_sell1.setEnabled(False)#this for button disble
self.tableWidget.setCellWidget(row, 2, self.btn_sell)
self.tableWidget.setCellWidget(row, 3, self.btn_sell1)
self.btn_sell.clicked.connect(self.edit)
def edit(self):
index = self.tableWidget.currentRow()
print index
self.table = QtGui.QTableWidget()
self.table.setGeometry(QtCore.QRect(220, 100, 881, 100))
self.table.setColumnCount(4)
self.table.setRowCount(1)
self.table.setColumnWidth(0, 120)
self.table.setColumnWidth(1, 500)
self.table.setColumnWidth(2, 120)
self.table.setColumnWidth(3, 120)
indexes = self.tableWidget.currentRow()
widget = self.tableWidget.cellWidget(indexes, 2)
# print widget
if isinstance(widget, QtGui.QComboBox):
h = str(widget.currentText())
if (h == "multiple_input"):
j = "checkbox"
elif (h == "description"):
j = "textbox"
if (j == "textbox"):
self.cb = QtGui.QComboBox()
lis = ("---select---", "description", "multiple_input")
self.cb.addItems(lis)
self.cb.setCurrentIndex(1)
self.table.setCellWidget(0, 2, self.cb)
[enter image description here][1]elif (j == "checkbox"):
self.cb = QtGui.QComboBox()
lis = ("---select---", "description", "multiple_input")
self.cb.addItems(lis)
self.cb.setCurrentIndex(2)
self.table.setCellWidget(0, 2, self.cb)
n = [str(self.tableWidget.item(indexes, 0).text())]
for x in n:
f = ''.join(map(str, x))
self.table.setItem(0, 0, QtGui.QTableWidgetItem(f))
n1 = [str(self.tableWidget.item(indexes, 1).text())]
# print n1
for i in n1:
s = ''.join(i)
self.table.setItem(0, 1, QtGui.QTableWidgetItem(s))
self.li = QtGui.QPushButton("Update")
self.table.setCellWidget(0, 3, self.li)
self.li.clicked.connect(self.edit_data)
self.table.show()
click on below link has image.
Try the above code:
Select row and click on edit button it will take the current index row values into the separate table `where we can edit and update the values.This is the one way i have tried to update the value it works fine.

loop only appends on last button

I've made a gui with a variable amount of buttons and entries, dependent on earlier user inputs. I want to store the new entries in a list. My loop however will only append the last entry created in the loop. How can I get each button to append it's respective user entry?
def getFuseType():
(Fuse.fuseType).append(e.get()
print(Fuse.fuseType)
for i in range(1,int(Site.NoFuses)+1):
l = Label(FuseWindow, text = "Fuse Type")
e = Entry(FuseWindow)
l.grid(row = 1, column = i+3)
e.grid(row = 2, column = i+3)
b = Button(FuseWindow, text = "ok", command = getFuseType)
b.grid(row = 3, column = i+3)
Fuse GUI
see the image I've uploaded, The top right 'OK' button appends the entry. I want the top Left button to also append it's respective entry.
The problem is that the function isn't creating a closure around the e variable so they only affect the most recent (last) object assigned to e. If you really want to do this you'll need to use a defaulted arg..
for i in range(1,int(Site.NoFuses)+1):
l = Label(FuseWindow, text = "Fuse Type")
e = Entry(FuseWindow)
l.grid(row = 1, column = i+3)
e.grid(row = 2, column = i+3)
def getFuseType(e=e):
(Fuse.fuseType).append(e.get())
print(Fuse.fuseType)
b = Button(FuseWindow, text = "ok", command = getFuseType)
b.grid(row = 3, column = i+3)
Get getFuseType out of the for, it is defined every loop iteration and hence you only get the last create entry e
def getFuseType(ent):
Fuse.fuseType.append(ent)
print(Fuse.fuseType)
for i in range(1,int(Site.NoFuses)+1):
l = Label(FuseWindow, text = "Fuse Type")
e = Entry(FuseWindow)
ent = e.get()
l.grid(row = 1, column = i+3)
e.grid(row = 2, column = i+3)
b = Button(FuseWindow, text = "ok", command = lambda ent = ent:getFuseType(ent))
b.grid(row = 3, column = i+3)

Python pptx module

I have to edit a pptx template which contain tables like this:
How to append values stored in my python dict to the empty fields?
I'm using a pptx module, but I couldn't find any example of doing this.
from pptx import Presentation
prs = Presentation('template.pptx')
slide = prs.slides[2] #<- This is the slide that contains the table
shape = slide.shapes #<- As I understood This gives access to the shapes
textframe=shape.textframe
textframe.clear()
prs.save('test.pptx') #<- Saves the new file
pptx module link
quote from the dev-group of python-ppty developer
-if you know its index, something like table = slide.shapes[2] would do the trick.
Then you'll need to navigate the cells before you can change their contents:
for idx, row in enumerate(table.rows):
if idx = 0: # skip header row
continue
name_cell = row.cells[0]
name_cell.text = 'foobar'
corners_cell = row.cells[1]
---in main----
table_data = [['ID', 'Name', 'Age', 'Second name'], ['1', 'Petro', 22, 'Petrovich'], ['2', 'Ivan', 32, 'Ivanovich'], ['3', 'Oles', 23, 'Marko']]
prs = Presentation(template_filepath)
slide_1 = slide_build(prs, 5)
table_draw(table_data, slide_1.shapes)
prs.save(result_filepath)
def slide_build(prs, layout):
slide = prs.slides.add_slide(prs.slide_layouts[layout])
return slide
def table_draw(table_data, shapes):
rows_number = 0
columns_number = 0
# get table size
rows_number = len(table_data)
for i, item in enumerate(table_data):
columns_number += 1
table = table_build(rows_number, columns_number, shapes)
column_coord = 0
row_coord = 0
for row_count, row in enumerate(table_data):
for item_count, row_item in enumerate(row):
table.cell(row_count + row_coord, item_count + column_coord).text = str(row_item)
def table_build(rows, cols, shapes):
left = (0.1)
top = Inches(0.7)
width = Inches(6.0)
height = Inches(0.8)
table = shapes.add_table(rows, cols, left, top, width, height).table
# set column widths
i = 0
while i
Some thing like this

Categories