How to send the iteration value as a param to lambda function? - python

I build a drop-down with check boxes at Tkinter,
I tried to initialize the checkboxes in loop when I iterate over elements and for every checkbox i want different lambda function which use the element that I get in the specific iteration.
mb = Menubutton(self, text="Select", elief=RAISED)
mb.menu = Menu(mb,tearoff = 0)
mb["menu"] = mb.menu
for elem in self.files:
mb.menu.add(checkbutton(label = elem, variable = elem, command=lambda: print(elem)))
The output that I got is a empty string.

Related

How to get a reference to individual buttons created in a loop in tkinter?

Attempting to create a book issue page.
I get the data (the document variable) displayed as an array of n-ples, and add the borrow/return buttons in the loop with these data fields. However, since I create multiple instances of the same button variable as seen below, I have no way of knowing which one is clicked. Here is the code:
document = self.app.Member(MemberVerification.mem_id, self.app).searchDocument(SearchBooks.inputvalues, "Books")
logger.info("Results: " + str(document) + " for string filters: " + str(filters))
cells={}
for i in range(len(document)): # Rows
self.borrow = tk.Button(self, text="Borrow", command= lambda: self.checkBorrows(document[i], self.controller, i))
self.retbook = tk.Button(self, text="Return")
for j in range(1, len(document[1])): # Columns
try:
b = tk.Entry(self,justify=tk.CENTER)
b.grid(row=i, column=j)
b.insert(tk.END, str(document[i][j]))
cells[(i, j)] = b
except Exception as e:
logger.error("Error in populateTable: " + str(e) + traceback.format_exc())
sys.exit(-1)
if i!=0:
self.borrow.grid(row=i, column=j+1)
self.borrowbuttons.append(self.borrow)
self.retbook.grid(row=i, column=j+2)
A little explanation - i == 0 is where the column names come in. The button in question is self.borrow. I tried maintaining a list of them to search which button it is, but that didn't work. I would like to be able to maintain a reference to the specific button out of the 3 that have been created, so that the callback function checkBorrows can know which book has to be borrowed. The i parameter was just experimentation, doesn't seem to pass the index in due to the async nature of the button click listener
Any suggestions? I tried maintaining a class variable, but that always ends up referring to the last button, since the callback is technically async.
Thanks!

Why am I getting a type error from this function?

I am trying to create a drop down menu in tkinter that allows the user to select a machine, or row # from the excel sheet, and then all the data from that entire row is displayed in tkinter through the display_selected function. I keep getting this error.
This is my error:
TypeError: line_7_window.<locals>.display_selected() takes 0 positional arguments but 1 was given
This is my code:
def get_machine():
for row in sheet.iter_rows(min_row=2, max_col=1, max_row=60):
for cell in row:
if cell.value == inputmachine:
machineindex = cell
return machineindex.row
def get_machineattributes():
for col in sheet.iter_cols(min_row = (get_machine()), max_col = 15, max_row = (get_machine())):
for cell in col:
return (cell.value)
def display_selected():
data = Message(line_7, text=get_machineattributes())
data.pack()
data.place(x=650, y=30)
copy = Button(line_7, text="Copy to Clipboard", command=pyperclip.copy(line7_choice))
copy.pack()
copy.place(x=550, y=45)
return
inputmachine = StringVar(line_7)
inputmachine.set("Click to select a machine")
dropdown = OptionMenu(line_7, inputmachine, *lst, command=display_selected)
dropdown.pack()
dropdown.place(x=670, y=25)
I have tried everything and I cant figure out why this would not work.
Your callback function display_selected, specified when creating the option menu, will receive the actual option chosen from Tk, so you need that parameter when defining it, even if you do nothing with it.
In other words, use something like:
def display_selected(choice):
del choice # not used
# rest of function
As an aside, I suspect you may be better off with an option menu to select the item, and a separate button to act on that selection. That would allow you to confirm the selected item before performing any action, in case you inadvertently choose the wrong one.

How to get every item inside a listbox in tkinter?

How do I make it so that I get all the items inside a listbox into a variable? I only manage to get the last item only. I want to print the items of a listbox into a new window but I only print the last item only.
get_content = listbox2.get(0, END)
bb = Label(receipt_window, text = "Pizzeria")
line1 = Label(receipt_window, text = "----------------------------------------------------------------")
for con_item in get_content:
con = (con_item.split('PHP'))
con1 = con[0]
con2 = con[1]
rec_content = f'{con1:<40}costs PHP{con2:<8}'
receipt = Label(receipt_window, text = rec_content)
bb.pack()
line1.pack()
receipt.pack()
The listbox contains:
The result:
It is because you use same variable receipt for the labels created inside the for loop and call receipt.pack() outside the for loop, so the last label created inside for loop will be packed only.
You need to call receipt.pack() inside the for loop:
get_content = listbox2.get(0, END)
bb = Label(receipt_window, text='Pizzeria')
line1 = Label(receipt_window, text='----------------------------------------------------------------')
bb.pack()
line1.pack()
for con_item in get_content:
con1, con2 = con_item.split('PHP')
rec_content = f'{con1:<40}costs PHP{con2:<8}'
receipt = Label(receipt_window, text=rec_content)
receipt.pack()
Note that it is better to use fixed width (monospaced) font for the labels.

Selenium (Python) - Checking parameter next to the LABEL and insert the value OR select an option

IF would like to create a generic code (by using Selenium) which will look for the label, and the find next to the label input(OR select) tag and insert the value.
Main function:
for l in label:
try:
xpathInput = "//label[contains(.,'{}')]/following::input".format(l)
checkXpathInput, pathInput= check_xpath(browser,xpathInput)
if checkXpathInput is True:
pathInput.clear()
pathInput.send_keys("\b{}".format(value))
break
for op in option:
xpathSelect = "//label[contains(.,'{}')]/following::select/option[text()='{}']".format(l,op)
checkXpathSelect, pathSelect= check_xpath(browser,xpathSelect)
if checkXpathSelect is True:
pathSelect.click()
break
except:
print("Can't match: {}".format(l))
Path checker:
def check_xpath(browser,xpath):
try:
path = browser.find_element_by_xpath(xpath)
except NoSuchElementException:
return False
return True , path
What is the current issue?
I need that if LABEL will be for example TITLE the code will check that there is NO input tag next to "Title" label and then he will go and check is there is the select tag next to the label "Title" and e.t.c....
In my current, he will find the label "Title" and then will fill in value to the first next input (which is incorrect as "Title" is using the SELECT tag)
I'd exploit the fact that find_elements_by_xpath returns a list of found elements and empty lists are falsy. So you wouldn't need a try/except and a function which returns bool or tuple values (which is not the most optimal behavior).
It would be easier to give a good answer with some html source example but I assume what you'd like to do is this:
def handle_label_inputs(label, value):
# if there is a such label, this result won't be empty
found_labels = driver.find_elements_by_xpath('//label[contains(.,"{}")]'.format(label))
# if the list is not empty
if found_labels:
l = found_labels[0]
# any options with the given value as text
following_select_option_values = l.find_elements_by_xpath('./following::select//option[text()="{}"]'.format(value))
# any inputs next to the label
following_inputs = l.find_elements_by_xpath('./following::input')
# did we find an option?
if following_select_option_values:
following_select_option_values[0].click()
# or is there an input?
elif following_inputs:
in_field = following_inputs[0]
in_field.clear()
in_field.send_keys(value)
else:
print("Can't match: {} - {}".format(label, value))
driver.get('http://thenewcode.com/166/HTML-Forms-Drop-down-Menus')
handle_label_inputs('State / Province / Territory', 'California')
I don't know how tidy the page you are work with but if it is well done, then your label should have a for="something" attribute. If that is the case then you can simply find the label-related-element and find out if its tag is input (or select):
related_element_if_done_properly = driver.find_elements_by_xpath('//*[#id="{}"]'.format(label_element.get_attribute("for")))
if related_element_if_done_properly:
your_element = related_element_if_done_properly[0]
is_input = your_element.tagname.lower() == "input"
else:
print('Ohnoes')

How can I create a table in a DOCX file with Python?

I am trying to send selected values from radiobuttons into a .docx file
importing what I need, focus is on docx
import tkinter as tk
from docx import Document
main = tk.Tk()
these are my options that I need to place into a word document on the left of the table, they act as questions in a survey.
info = ["option 1", "option 2", "option 3", "option 4"
]
Here I am placing radiobuttons called Yes, No & N/A which are answers to the options on the left(list of info above) and also Label to represent options or in other words questions..
vars = []
for idx,i in enumerate(info):
var = tk.IntVar(value=0)
vars.append(var)
lblOption = tk.Label(main,text=i)
btnYes = tk.Radiobutton(main, text="Yes", variable=var, value=2)
btnNo = tk.Radiobutton(main, text="No", variable=var, value=1)
btnNa = tk.Radiobutton(main, text="N/A", variable=var,value=0)
lblOption.grid(column=0,row=idx)
btnYes.grid(column=1,row=idx)
btnNo.grid(column=2,row=idx)
btnNa.grid(column=3,row=idx)
Here is my function, creating a document and saving is the easy part. My issue is that I am muddled up creating a table that will have; Options on the left (from info) at the top are the headers (see RadioButtons yes, no, & N/a). And selected data, as an example, if for option 1 I have selected No, then save the data into a .docx file with the one been selected (See example bottom of page at Desired output).
def send():
document = Document()
section = document.sections[0]
#add table
table = document.add_table(1, 4)
#style table
table.style = 'Table Grid'
#table data retrived from Radiobuttons
items = vars.get()
#populate header row
heading_cells = table.rows[0].cells
heading_cells[0].text = "Options"
heading_cells[1].text = btnYes.cget("text")
heading_cells[2].text = btnNo.cget("text")
heading_cells[3].text = btnNa.cget("text")
for item in items:
cells = table.add_row().cells
cells[0].text = #Options
cells[1].text = #Yes values
cells[2].text = #No values
cells[3].text = #N/A values
#save doc
document.save("test.docx")
#button to send data to docx file
btn = tk.Button(main, text="Send to File", command= send)
btn.grid()
main.mainloop()
this is what it opens up:
Here is the desired output:
Number 1 represents selected items from the tkinter application. But will figure out how to change it to a tick box.
I am kinda confused where I am at, I am new using docx.. been trying to read the documentation.. and this is where I digged my self a hole into.
In your current code, vars is a list of IntVars. You want to get each value individually instead of vars.get(). Also when writing to docx file, you need both info and values of radiobuttons, to track them both you can use an index.
With minimal changes to your code, you can use something like this.
def send():
...
...
heading_cells[3].text = btnNa.cget("text")
for idx, item in enumerate(vars):
cells = table.add_row().cells
cells[0].text = info[idx] # gets the option name
val = item.get() #radiobutton value
if val == 2: # checks if yes
cells[1].text = "1"
elif val == 1: # checks if no
cells[2].text = "1"
elif val == 0: # checks if N/A
cells[3].text = "1"
#save doc
document.save("test.docx")
or you can use a dictionary to map radiobuttons to cells.
valuesCells = {0: 3, 1: 2, 2: 1} # value of radiobutton: cell to write
# hard to read what's going on though
for idx, item in enumerate(vars):
cells = table.add_row().cells
cells[0].text = info[idx] # gets the option name
val = item.get()
cells[valuesCells[val]].text = "1"
#save doc
document.save("test.docx")

Categories