Python Refresh GUI to create another output - python

I am very new to Python. I am trying to create an app that printing a number from a Smartsheet sheet then delete it. The problem is I only can print it once, once I click "Create" button again, it gives error message. I believe when I click "Create" button again, it returns the deleted number from the sheet. Thank you!
{"response": {"statusCode": 404, "reason": "Not Found", "content": {"detail": {"ids": [3462338204985220], "type": "row"}, "errorCode": 1006, "message": "Not Found", "refId": "hcuqkioxqz46"}}}
Here is the sheet that stores a series of number:
Here is my code:
#Smartsheet client access token
smartsheet_client = smartsheet.Smartsheet('access token')
#Order Dashboard sheet ID
MySheet=smartsheet_client.Sheets.get_sheet(sheet_id)
def conceptnum():
n=1
for Myrow in MySheet.rows:
while n==1:
for Mycell in Myrow.cells:
row_ids=Myrow.id
label1['text']=int(Mycell.value)
label2['text']="Your concept number is created"
smartsheet_client.Sheets.delete_rows(
sheet_id, # sheet_id
row_ids) # row_ids
n=n-1
Height=100
Width=200
root=tk.Tk()
canvas=tk.Canvas(root, height=Height, width=Width)
canvas.pack()
frame=tk.Frame(root, bg="grey")
frame.place(relx=0.05, rely=0.3, relwidth=0.9, relheight=0.4)
button=tk.Button(root, text="Create",command=conceptnum)
button.pack(side='bottom')
label1=tk.Label(frame,font=15)
label1.place(relx=0.1, rely=0.1,relwidth=0.8, relheight=0.8)
label2=tk.Label(root)
label2.place(relwidth=1,relheight=0.2)
root.mainloop()

As currently written, your conceptnum() function is doing this:
for each row in the sheet ->
for each cell in the current row ->
...
delete the current row
So, if your sheet contains more than one column, your script will:
get the first row of the sheet
get the value of the first cell of the row being processed
delete the row from the sheet
get the value of the second cell of the row being processed
delete the row from the sheet -> this delete row request (and the subsequent request for each additional column/cell in the row being processed) will return the "Not Found" error -- because that row no longer exists in the sheet -- you deleted it after reading the first cell value.
Assuming that your objective is to read the value in the first cell of the first row of the sheet, and then delete that row from the sheet, here's a function that will do so -- please note that I've changed the function name and variable names to follow Python style convention (lowercase with underscores):
def concept_num():
# get sheet
my_sheet = smartsheet_client.Sheets.get_sheet(sheet_id)
# initialize row_id
row_id = None
for row in my_sheet.rows:
# get the ID of the current (first) row
row_id = row.id
# get the Cell object for the first cell of the current (first) row
cell = row.cells[0]
# set labels
label1['text'] = int(cell.value)
label2['text'] = 'Your concept number is created'
# exit the 'for' loop (so that only the first row is processed)
break
# delete the row that was just processed
if row_id != None:
smartsheet_client.Sheets.delete_rows(sheet_id, row_id)
else:
label1['text'] = 'n/a'
label2['text'] = 'Concept number not found.'
EDIT 4/13/2020:
You need to fetch the sheet each time the concept_num function runs -- so that my_sheet reflects the current contents of the sheet (i.e., no longer contains rows that were deleted when the function ran previously). I've updated the code snippet above accordingly (i.e., added the get sheet call at the top of the concept_num function). I've also added code at the end of the snippet (using an else) to update labels accordingly if the sheet contains no more numbers when the Create button is clicked.

Related

After updating OptionMenu, Optionmenu's function does not work

def kayit_ekle_update(): ##
kayit_listesiVar.set('') # remove default selection only, not the full list
kayit_listesiOM['menu'].delete(0, 'end') # remove full list
kayitlilarOM = os.listdir("allin1/data_records")
for opt in kayitlilarOM:
kayit_listesiOM['menu'].add_command(label=opt, command=tk._setit(kayit_listesiVar, opt))
kayit_listesiVar.set(kayitlilarOM[0]) # default value set
def entri_doldur(se):
## get data from excel and append them to a new list(veri_al_list)
veri_al_list = []
om_deger = "allin1/data_records/" + kayit_listesiVar.get()
wb_kayit = load_workbook(om_deger)
ws_kayit = wb_kayit.active
for column_data in ws_kayit['1']:
veri_al_list.append(column_data.value)
veri_al_list = [' ' if v is None else v for v in veri_al_list] # None elemanı hata verdiriyor. Burada tüm None olanları "" ile değiştiriyoruz.
print(veri_al_list)
## There are Entry widgets created with for loop.
## en in entry_liste ==> Entries
## ne in veri_al_liste ==> data list from excel
for en, ne in zip(entry_liste, veri_al_list):
en.delete(0,END)
en.insert(END, ne)
wb_kayit.close()
kayitlilarOM = os.listdir("allin1/data_records")
kayit_listesiVar = StringVar()
kayit_listesiVar.set("Kayıt seç")
kayit_listesiOM = OptionMenu(ust, kayit_listesiVar, *kayitlilarOM, command=entri_doldur)
I have entry widgets in my code. The user can enter data and save them. Each time this data is saved, a new excel file is created and the data is saved in it.
The name of each saved excel file is displayed in an optionmenu. When we select a record from the Optionmenu, the entri_doldur() function works and the entries are filled according to the record.
I can delete the selected record with the button. When deleted, both the entries are empty and the option menu is updated.
But the problem occurs when I create a new record. Creating a new excel file. The data is saved in it. Option menu is being updated. But after that, when I select a record in the optionmenu, the entri_doldur() function does not work. The information of the selected record does not fill the entries.

Setting individual column headers in Python Tkinter's Tksheet widget / rolling back changes in same

I am writing a UI for a simulation program which accepts tabular data.
The basic functionality I need is for the user to be able to enter / change data in cells either by directly typing into them, or by pasting data (usually from an excel sheet). The program checks this data and either accepts or rejects it before running the simulation. I also want to let the user type in their own column headers for the table.
Tksheet is an awesome Tkinter add-on, giving an excel-like "feel" to the input frame, but its documentation leaves much to be desired. (For instance: each event generates a different event-information array--see code for two event-processing routines below--but nowhere is it specified what these parameters are. It is left for the user to discover using trial and error, or trying to read the source code--which is not documented either).
I have two specific questions:
Is there any way to not-commit, or to roll back, changes to the table? If my data-tests fail, how do I prevent potentially harmful user input from being entered into the table?
Obviously I can (and do) add a begin_*** event in which I can keep copies of the original values, and then reset the table values if the data testing at the end_*** event fails, but this is wasteful and inelegant. I have a feeling that the set_data_ref_on_destroy property has something to do with such a capability, but the documentation does not explain what this parameter is or how to use it.
How can I change a single column header at a time? The .headers property seems to work only with a full list of headers starting with column 0 (if I run self.sheet.headers([single_value], index = i) it ignores the index parameter and plugs single_value in column 0)
Again, I can set the column headers to something non-default at init and keep a running list of all headers, so that I can reset all the headers on each change, but this is wasteful and inelegant.
In the following code sample I set up a simple table, and bind three user-generated events: one for typing a value to a cell, one for pasting a block of values, and one for adding an option to the right-click menu of a column header, to allow the user to type a name to the column.
from tksheet import Sheet
import tkinter as tk
import tkinter.messagebox as msg
import tkinter.simpledialog as sd
class demo(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.grid_columnconfigure(0, weight=1) # This configures the window's escalators
self.grid_rowconfigure(0, weight=1)
self.frame = tk.Frame(self)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.grid_rowconfigure(0, weight=1)
self.frame.grid(row=0, column=0, sticky="nswe")
self.sheet = Sheet(self.frame, data=[[]]) # set up empty table
self.sheet.grid(row=0, column=0, sticky="nswe")
self.sheet.enable_bindings(bindings= # enable table behavior
("single_select",
"select_all",
"column_select",
"row_select",
"drag_select",
"arrowkeys",
"column_width_resize",
"double_click_column_resize",
"row_height_resize",
"double_click_row_resize",
"right_click_popup_menu",
"rc_select", # rc = right click
"copy",
"cut",
"paste",
"delete",
"undo",
"edit_cell"
))
# Note that options that change the structure/size of the table (e.g. insert/delete col/row) are disabled
# make sure that pasting data won't change table size
self.sheet.set_options(expand_sheet_if_paste_too_big=False)
# bind specific events to my own functions
self.sheet.extra_bindings("end_edit_cell", func=self.cell_edited)
self.sheet.extra_bindings("end_paste", func=self.cells_pasted)
label = "Change column name" # Add option to the right-click menu for column headers
self.sheet.popup_menu_add_command(label, self.column_header_change, table_menu=False, index_menu=False, header_menu=True)
# Event functions
def cell_edited(self, info_tuple):
r, c, key_pressed, updated_value = info_tuple # break the info about the event to individual variables
if check_input(updated_value):
pass # go do stuff with the updated table
else:
msg.showwarning("Input Error", "'" + updated_value + "' is not a legal value")
pass # what do I do here? How do I make tksheet *not* insert the change to the table?
def cells_pasted(self, info_tuple):
key_pressed, rc_tuple, updated_array = info_tuple # break the info about the event to individual variables
r, c = rc_tuple # row & column where paste begins
if check_input(updated_array):
pass # go do stuff with the updated table
else:
msg.showwarning("Input Error", "pasted array contains illegal values")
pass # what do I do here? How do I make tksheet *not* insert the change to the table?
def column_header_change(self):
r, c = self.sheet.get_currently_selected()
col_name = sd.askstring("User Input", "Enter column name:")
if col_name is not None and col_name != "": # if user cancelled (or didn't enter anything), do nothing
self.sheet.headers([col_name], index=c) # This does not work - it always changes the 1st col
self.sheet.redraw()
# from here down is test code
def check_input(value): # instead of actual data testing we let the tester choose a pass/fail response
return msg.askyesno("Instead of input checking","Did input pass entry checks?")
test = demo()
lst = ["hello", "world"]
test.sheet.insert_column(values=lst)
lst = [0, "hello", "yourself"]
test.sheet.insert_column(values=lst)
test.mainloop()
I realize that the original post is now 5 months old, and I'm a relative n00b, but I hope this helps.
Given a tksheet instance 'sheet' that has already been populated with headers ["A"."B"."C"], the following works to change the header "B" to "NEW":
sheet.headers()[1]="NEW"
Hope this helps.

Is there a way to get the Column menu updates automatically with the sheet menu?

I am devoloping an app where the user upload his excel file and gets the Sheets and columns. How do I get the Columns drop-down menu (The second one) to update with the Sheets drop-down menu(First one).
I have already tried to make a function 'Update' that gets the new sheet form the Fuction 'GetSheet' and update it. But it does not work as the column drop-down menu get Always stucked in the Default sheet.
master.title('ATT Analytics App')
master.geometry("400x250")
Myfile= filedialog.askopenfile()
wb = load_workbook(filename = str(Myfile.name))
#Sheets = wb.sheetnames
variable = StringVar(master)
variable.set(str(wb.sheetnames[2])) # default value
w = OptionMenu(master, variable, str(wb.sheetnames[0]), str(wb.sheetnames[1]), str(wb.sheetnames[2]), str(wb.sheetnames[3]))
w.pack()
def GetSheet():
FileRead = pd.read_excel(str(Myfile.name),sheet_name= str(variable.get()))
MyHeadres = list(FileRead.columns.values)
return MyHeadres, FileRead
variable1 = StringVar(master)
def Update(TheHeaders):
variable1.set(str(TheHeaders[0]))
wc = OptionMenu(master, variable1, str(TheHeaders[0]), str(TheHeaders[1]), str(TheHeaders[2]), str(TheHeaders[3]), str(TheHeaders[4]), str(TheHeaders[5]))
return wc
def RunAll():
GetMySheet, FileRead = GetSheet()
UpdateMysheet = Update(GetMySheet)
return UpdateMysheet, variable1.get(), FileRead
button = Button(master, text="Run", command=RunAll)
button.pack(side = TOP)
UpdateMysheet, MyColumn, ReadMyFile = RunAll()
UpdateMysheet.pack()
FileRead = ReadMyFile
mainloop()
I want to bring my Code to be able to update the Column Drop-down (Variable1) menu with the drop down menu (Variable), which works fine and also get to store the column you want and move on the choose another one and so on..
I would appreciate your help a lot.
Edit: Now when I choose another sheet, the Default value of the columns updates to the new sheet, but when I look the complete List, I find out that the values are from the old sheet.

multiple value from mysql to reportlab

i have an issue that i can't show my second record in mysql table. The report just showing 1 record in a row and the second one isn't show on pdf file. i'm using reportlab for report generator on python 2.7
this is my code that i can' fix yet :
def nilaisql():
rpt = raw_input("input NPM : ")
sql = "select nama, tanggal, jamMasuk from t_"+rpt
curs.execute(sql)
result = curs.fetchall()
for row in result:
c = canvas.Canvas("Sampelone.pdf")
c.drawString(250, 700, str(row[0]))
c.save()
os.system("Sampelone.pdf")
this is my record on mysql. I want to show the second row record but the pdf just showing the first row record
it should showing the second row record
and this is the result on my pdf file
i'm getiing stuck in here and if you know something i'm really grateful that you can share the solution in here
for row in result:
c = canvas.Canvas("Sampelone.pdf")
c.drawString(250, 700, str(row[0]))
c.save()
what your code snippet is doing is, creating a new file and writing the content of your variable row into the pdf file and c.save saves it. In the next iteration, this same file is recreated which is blank and the original file is overwritten by this blank file and the content of row is printed that is why you will always see only first row record in it.
This should work fine. Increment or Decrement the value of y according to your use and document height.
c = canvas.Canvas("Sampelone.pdf") #creates a pdf
for row in result:
c.drawString(250, y, str(row[0])) #writes data at given co-ordinates
c.save() #saves the pdf
This way you can see all row records in the pdf.
But this practice is not considered good, you should always put your data in flowable like this. .
from reportlab.lib import styles
from reportlab.platypus import SimpleDocTemplate, Paragraph
def nilaisql():
pdfname = 'mydoc.pdf'
doc = SimpleDocTemplate(
pdfname
)
style = styles["Normal"]
story = []
rpt = raw_input("input NPM : ")
sql = "select nama, tanggal, jamMasuk from t_" + rpt
curs.execute(sql)
result = curs.fetchall()
for row in result:
story.append(Paragraph(row, style))
doc.build(
story
)
os.system("Sampelone.pdf")
Read more about flowables in reportlab-userguide

PyQt5: Problems naming a row after using insertRow()

I am trying to create a button that adds a row to a table (QtTableWidget) and uses a dialog box to ask for the name, and I have hit a big problem (seemingly a flaw within PyQt).
By adding a row using the insertRow() function the row header automatically has a value of none, which then means you cannot use the verticalHeaderItem(rowPosition).setText(...) on the row Header as it cannot set the text of an item with value none.
The relevant code is here:
def RenameRow(self, i, name):
self.tab1table.verticalHeaderItem(i).setText(name)
def DatabaseAddRow(self):
text, ok = QInputDialog.getText(self, "Row Entry", 'Please Enter A Row Name:', QLineEdit.Normal, 'e.g. ECN 776')
if ok and text != '':
rowPosition = self.tab1table.rowCount()
self.tab1table.insertRow(rowPosition)
self.RenameRow(rowPosition, text)
Any Ideas how to get around this or maybe methods I do not know about?
So I managed to solve this myself just after asking this after wasting half a day on this problem, such is life. The solution to the problem is to assign an empty item to the header and then rename it, the implementation is here:
def RenameRow(self, i, name, table):
item = QTableWidgetItem()
table.setVerticalHeaderItem(i, item)
item = table.verticalHeaderItem(i)
item.setText(QCoreApplication.translate("MainWindow", name))

Categories