Python Tkinter can't select option in optionmenu - python

I am having the problem where I am able to populate two optionmenus using Tkinter, (the second one dynamically based off the first), but I notice when I try to select one of the values in the second optionmenu, it does not allow me to select. I have noticed on the same GUI, sometimes when running another function, it will have this affect on a different option menu that worked fine prior to running the function. The options will show correctly, and the mouse can scan over them, but when you click on one it doesn't show that it has been selected, or execute the command set to it. Has anyone had this problem before?
Ok, so my hopes of someone else having the same issue are going down, and I'll include more code by request of some of the responders in case this might shed light on the issue. I'll try and pull everything applicable:
class GUI(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.build_gui()
#reads the tabs on an excel and inputs the tab names as the values in the first optionmenu (this works)
def read_board_tabs(self):
#many of these variables in the function may not be defined. Ignore them as they are taken out of context. This should just help visually see the structure.
filepath = 'Board Control.xlsx'
wkbk = load_workbook((filepath))
sheets = wkbk.get_sheet_names()
print sheets
return sheets
#reads content of that excel tab chosen to populate the second optionmenu (populating the option menu works, but they can't be selected once populated)
def read_serials(self, board):
#many of these variables in the function may not be defined. Ignore them as they are taken out of context. This should just help visually see the structure.
sheet = board
if(sheet == ''):
return ['']
else:
filepath = 'Board Control.xlsx'
workbook = excel_transfer.workbook(filepath)
wb = workbook.open_existing_workbook()
ws = workbook.activate_specific_worksheet(wb, sheet)
row = 1
current_row = 0
previous_row = 0
serials = []
#read the serials that exist for the board selected
while current_row != None:
previous_row = current_row
row = row + 1
cell = 'A' + str(row)
current_row = workbook.read_new_cell(cell, ws)
if(current_row != None):
serials.append(current_row)
if(len(serials) == 0):
serials = ['']
self.BOARD_SERIAL_OPTION['menu'].delete(0, 'end')
for item in serials:
self.BOARD_SERIAL_OPTION['menu'].add_command(label=item)
#this is the command that won't execute when I try to select the second optionmenu value
def find_board_info(self, serial):
#many of these variables in the function may not be defined. Ignore them as they are taken out of context. This should just help visually see the structure.
self.board_checkout_status_var.set('')
sheet = (self.boards_var).get()
new_search = StringFound.StringSearch(serial)
results = new_search.read_board(sheet)
if(results == ['']):
self.boardstatusvar.set('No board was found')
else:
self.boardstatusvar.set('Board: %s Serial: %s' %(results[1], serial))
self.boardstatus_locationvar.set('Found in file: %s' %results[0])
self.boards_var.set('%s serial %s' %(results[1], serial))
self.dispositionvar.set(results[3])
self.TXvar.set(results[5])
self.RXvar.set(results[6])
self.lastvar.set(results[10])
self.datevar.set(results[9])
if(results[14] != None):
self.currentvar.set(results[10])
self.locationvar.set(results[4])
self.imagevar.set(results[8])
self.notesvar.set(results[12])
self.current_board_chosen = [sheet, serial, results[15]]
#creates the gui
def build_gui(self):
n = Notebook(self)
board_process = Tkinter.LabelFrame(self, text="Board Updates")
n.add(board_process, text='Board Signout')
n.pack()
self.boards_var = StringVar()
self.boards_var.set("")
self.serials_var = StringVar()
self.serials_var.set("")
self.SEARCHBOARDFRAME = Tkinter.LabelFrame(board_process, text='Find Board')
self.SEARCHBOARDFRAME.grid(row=0, column=0, sticky='WE')
self.BOARD_SEARCH_LABEL = Label(self.SEARCHBOARDFRAME, text='Type:')
self.BOARD_SEARCH_LABEL.grid(row=0, column=0, sticky='W', padx=5, pady=2)
self.BOARD_SEARCH_OPTION = OptionMenu(self.SEARCHBOARDFRAME, self.boards_var, *self.list_of_boards, command=self.read_serials)
self.BOARD_SEARCH_OPTION.grid(row=0, column=1, sticky='W', padx=5, pady=2)
self.BOARD_SERIAL_LABEL = Label(self.SEARCHBOARDFRAME, text='Serial:')
self.BOARD_SERIAL_LABEL.grid(row=1, column=0, sticky='W', padx=5, pady=2)
self.BOARD_SERIAL_OPTION = OptionMenu(self.SEARCHBOARDFRAME, self.serials_var, *self.list_of_serials, command=self.find_board_info)
self.BOARD_SERIAL_OPTION.grid(row=1, column=1, sticky='W', padx=5, pady=2)
if __name__ == '__main__':
root = Tk()
app = GUI(root)
root.mainloop()

The problem is in these lines of code:
for item in serials:
self.BOARD_SERIAL_OPTION['menu'].add_command(label=item)
You are putting items in the option menu with a label, but you aren't giving them a command. The whole reason the Optionmenu widget exists is to add a special command to each item that gives the option menu its behavior. Unless you add that command when you dynamically create new items, those items won't do anything when you select them -- it's just a dumb menu with labels on it.
Unfortunately, the command that is associated with each item is returned from a private factory class (Tkinter._setit), so you don't have any officially supported way to add new items to an option menu. If you aren't afraid to use private commands, you can change your code to be this:
for item in serials:
command=Tkinter._setit(self.serials_var, item, self.find_board_info)
self.BOARD_SERIAL_OPTION['menu'].add_command(label=item, command=command)
For another way to solve this problem see Change OptionMenu based on what is selected in another OptionMenu

Related

Tkinter Generating new rows of Entry boxes not responding to Button call

I am trying to create an SQLite database interface using python and Tkinter to store the results of tests. Basically, the user first selects an option from a drop-down menu (Tkinter menubar) which generates a form with 6 predefined tests for collecting input. The input from these entry boxes is then stored in SQLite, where each row/test is stored in a different table. Different materials will be tested but the tests are the same for each. I want to compare the same test results for multiple materials at a later stage to model trends etc.
So, my idea is that the menu-bar calls a function (which determines the test category, board_strength for example) to generate a form with the date and project number and which does the layout. A class is used to generate the entry boxes, get the input, calculate the average, and store the values to SQLite after each row is filled out. If the user requires an additional row for the same test, a button should add it as needed. Then, if the user moves onto the next test (maybe via a button..), they again have the option to add another row for this test, and so on. Here I've only shown 1 test, ECT, but there are 5 more.
I've tried making a button to generate a new row but it doesn't seem to work properly. I've read a few posts on this site and googled, and although I'm quite new to working with classes, it seemed the easiest way to do what I want.
from tkinter import *
import tkinter as tk
date = datetime.date.today()
class create_widgets:
'''create widgets for input data, collect input, determine average, and store'''
def __init__(self, window, test_name, units, row):
self.window = root
self.test_name = ''
self.units = ''
self.row = 0
self.add_entry(window, test_name, units, row)
def add_entry(self, window, test_name, units, row):
self.entries = []
lbl_of_test = Label(window, text = f'{test_name} ({units}):', font = ('Arial', 10))
lbl_of_test.grid(row = row, column = 0)
for i in range(3):
self.entry = Entry(window, width=8)
self.entry.grid(row=row, column=i+1)
self.entries.append(self.entry)
def board_strength():
''' Add project details and date and generate test labels'''
lbl1 = Label(top_frame, text = 'Board Strength Properties', font = ('Arial Bold', 12))
lbl1.pack(side = 'top')
display_date = Label(top_frame, text = f'Date: {date}', font = ('Arial', 10))
display_date.pack(anchor = 'w')
sample_lable = Label(top_frame, text = 'Project Number:', font = ('Arial Bold', 10))
sample_lable.pack(anchor = 'sw', side = 'left')
sample_entry = Entry(top_frame, width = 15)
sample_entry.pack(anchor = 'sw', side = 'left')
for i in range(3):
lbl = Label(btm_frame2, text = f'Test: {i+1}', font = ('Arial', 10))
lbl.grid(row=0, column=i+1)
#First test
ect_widgets = create_widgets(btm_frame2, test_name = 'ECT', units = 'kN/m', row = 1)
ect_button = Button(btm_frame2,text='Add ECT', command = ect_widgets.add_entry)
ect_button.grid(row=12,column= 1, pady = 20)
# Next test
# fct_widgets = create_widgets(btm_frame2, test_name = 'FCT', units = 'kPa', row = 1)
# fct_button = Button(btm_frame2,text="FCT", command = fct_widgets.add_entry)
# fct_button.grid(row=12,column= 2, pady = 20)
# Next: Add FCT
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=filemenu)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.quit)
papermenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Paper", menu=papermenu)
boardmenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Board", menu=boardmenu)
boardmenu.add_command(label="Strength Properties", command = board_strength)
boardmenu.add_command(label="Structural Properties", command= 'board_structure')
root.config(menu=menubar)
root.mainloop()
When I run this code, I get the following error:
TypeError: add_entry() missing 4 required positional arguments: 'window', 'test_name', 'units', and 'row'
Why does it still want these arguments if I've already passed them creating the instance ect_widget? And how do I increase the row number accordingly when new rows are added? The row numbers are going to be a headache.
Any help or input would greatly be appreciated. Thanks!
This snippet of the code you have offered isn't enough to actually run it so I'm sorry for minor errors, but I think I know what you are missing here.
You probably want the add_entry method to not have all those arguments required. While it needs those things to do what it does; you can save that data in the instance of the class when you create it.
def __init__(self, window, test_name, units, row):
self.window = window
self.test_name = test_name
self.units = units
self.row = row
self.add_entry()
def add_entry(self):
self.entries = []
lbl_of_test = Label(self.window,
text = f'{self.test_name} ({self.units}):',
font = ('Arial', 10))
lbl_of_test.grid(row = self.row, column = 0)
for i in range(3):
self.entry = Entry(self.window, width=8)
self.entry.grid(row=self.row, column=i+1)
self.entries.append(self.entry)
Something like this is probably more appropriate. We store attributes of an instance using that "self." syntax. The "self.window = window" etc saves these things so you can use them whenever without passing them. Then, in the add_entry method, it can use the saved values of those things by calling up the 'self.' version of them.
(Technically speaking, there is nothing magical about using the word 'self' before those variables; it works that way because 'self' is the first argument passed into non-static methods--including __init__--in a class. Whatever is first refers to the instance of that class, ergo the typical name of 'self.' If you ever needed to refer to the instance of a class within its own methods you would just use 'self.')
I hope that helps, let us know if you have more questions.
P.S. I split up that really long line into multiple...generally, you don't want lines longer than 80 characters, and Python lets you cut lines freely between items inside of parentheses.

how do I create entry fields and buttons to get the content from the entry field using iteration in tkinter for python?

I'm trying to make a tkinter GUI with a certain amount of buttons and entry fields that is specified by the user, so in this code below for example if the user specifies the variable number to be 3 I want there to be 3 entry boxes and , and I want to set it up so that if I type a value into the first field and click the button next to it, I want that button to read the value from the entry field next to it. I also need to assign each entry field to a variable that will be created through the same iterative loop. However, I'm having difficulty especially in regards to mapping the buttons to the entry fields, as I always seem to run up against an error with the text "AttributeError: 'NoneType' object has no attribute 'get'". Would anyone be able to either fix my code or help me find an alternative solution to the problem? Sorry if the description's a bit confusing.
This is different from just a problem of just getting the contents of the entry widget as I need it to create a certain amount of entry widgets and buttons using iteration, and the question that my question has been marked a duplicate of doesn't explain how to iteratively map each entry field to each button. For example, if I enter 3 as the variable, I need the program to create entry field 1, entry field 2 and entry field 3 and button 1, button 2 and button 3 and then map each button to its respective entry field using iteration.
I've tried using dictionaries, but this doesn't seem to help much.
import tkinter as tk
root = tk.Tk()
number = 3
d={}
def callBack():
print(d["E{0}".format(i)].get())
return
for i in range(0,number):
d["E{0}".format(i)] = tk.Entry(root)
d["E{0}".format(i)].grid(row=i, column=0)
d["B{0}".format(i)] = tk.Button(root, text="test", command=callBack)
d["B{0}".format(i)].grid(row=i, column=1)
The solution to "'NoneType' object has no attribute 'get'" has been asked probably a hundred times on this site, and the answer is always the same.
In python, when you do x = y().z(), x will be given the value of z(). In the case of x=tk.Entry(...).grid(...), x will be None because grid(...) always returns None. The solution is to always call grid or pack or place separate from when you create a widget.
You also claim you are having problems with dictionaries, but I don't see any problem in your code other than you are making it more difficult than necessary. You can directly use i as an index without having to build up a string for the index. If you need to keep track of both buttons and entries, I recommend two variables rather than one.
Part of the problem may also have to do with the fact you're trying to do something very odd in your command. You're trying to call the get method of the entry, but that's pointless since it simply returns a value that gets thrown away. In almost all cases, the correct solution is to write a proper function rather than trying to squeeze functionality into a lambda.
Example:
def handle_click(i):
entry = entries[i]
print("the value is {}".format(entry.get()))
buttons = {}
entries = {}
for i in range(0,number):
entry = tk.Entry(root)
button = tk.Button(root, text="test", command=lambda i=i: handle_click(i))
buttons[i] = button
entries[i] = entry
entry.grid(row=i, column=0)
button.grid(row=i, column=1)
You need to save the Entry and Button before calling grid:
import tkinter as tk
number = 3
root = tk.Tk()
def get_on_click(widget_dict, entry_name):
def on_click():
result = widget_dict[entry_name].get()
print("%s = %s" % (entry_name, result))
return result
return on_click
d = dict()
for i in range(0, number):
entry_name = "E{0}".format(i)
button_name = "B{0}".format(i)
print(entry_name, button_name)
d[entry_name] = tk.Entry(root)
d[entry_name].grid(row=i, column=0)
d[button_name] = tk.Button(root, text="test", command=get_on_click(d, entry_name))
d[button_name].grid(row=i, column=1)
root.mainloop()
This should help you get started.
In your comment, you ask how to save the value in the Entry. I would create a class to handle everything:
import tkinter as tk
number = 3
root = tk.Tk()
class EntryButton(object):
def __init__(self, root, number):
self.number = number
self.entry = tk.Entry(root)
self.button = tk.Button(root, text="test", command=self.on_click)
self.entry.grid(row=number, column=0)
self.button.grid(row=number, column=1)
self.value = None
def on_click(self):
self.value = self.entry.get()
storage = dict()
for i in range(0, number):
storage[i] = EntryButton(root, i)
root.mainloop()
for i in range(0, number):
value = storage[i].value
print(f"storage[{i}] = {value}")
As you can see, this eliminates a lot of extra work.
For get text from entry
Entry.get("1.0", "end-1c")
# 1.0 for get first line.
# end-1c for if last letter space, this deletes it.
More info

How to get values of checkbuttons from for loop tkinter python

I am new to programming in tkinter and am very stuck on using checkbuttons. I have created multiple checkbuttons in one go, all with different text for each one and a different grid position. However I have no idea how to get the value of each button or how to even set it. I want to be able to get the state/value for each button and if it is checked, then another function is called. How do I set and call the value/state of each button? Can this be done in a for loop or do I have to create them individually?
def CheckIfValid(self, window):
Class = self.ClassChosen.get()
Unit = self.UnitChosen.get()
Topic = self.TopicChosen.get()
if Class == '' or Unit == '' or Topic == '':
tm.showinfo("Error", "Please fill in all boxes")
else:
QuestionData = OpenFile()
QuestionsList = []
for x in range (len(QuestionData)):
#if QuestionData[x][2] == Topic:
QuestionsList.append(QuestionData[x][0])
for y in range(len(QuestionsList)):
self.ButtonVal[y] = IntVar()
Checkbutton(window, text = QuestionsList[y], padx = 20, variable = self.ButtonVal[y]).grid(row = 12 + y, column = 2)
ConfirmSelection = Button(window, text = "Set Homework", command = lambda: SetHomeworkClass.ConfirmHomework(self)).grid()
print(variable.get()) #here I would like to be able to get the value of all checkbuttons but don't know how
You use the list of IntVars either called from a command= in the Checkbutton or in the Button. Don't know why you are calling another class's object, SetHomeworkClass.objectConfirmHomework(self). It doesn't look like that will work as you have it programmed, as that is another name space and the list of IntVars is in this name space, but that is another topic for another thread.
try:
import Tkinter as tk # Python2
except ImportError:
import tkinter as tk # Python3
def cb_checked():
# remove text from label
label['text'] = ''
for ctr, int_var in enumerate(cb_intvar):
if int_var.get(): ## IntVar not zero==checked
label['text'] += '%s is checked' % cb_list[ctr] + '\n'
root = tk.Tk()
cb_list = [
'apple',
'orange',
'banana',
'pear',
'apricot'
]
# list of IntVar for each button
cb_intvar = []
for this_row, text in enumerate(cb_list):
cb_intvar.append(tk.IntVar())
tk.Checkbutton(root, text=text, variable=cb_intvar[-1],
command=cb_checked).grid(row=this_row,
column=0, sticky='w')
label = tk.Label(root, width=20)
label.grid(row=20, column=0, sticky='w')
# you can preset check buttons (1=checked, 0=unchecked)
cb_intvar[3].set(1)
# show what is initially checked
cb_checked()
root.mainloop()

TkTable insert rows python

Hi I am trying to create a table using Tktable and the wrapper i found online : http://tkinter.unpythonic.net/wiki/TkTableWrapper
I am having trouble understanding how to add rows. I have been modifying the sample_test method included in the file with no success.
My end goal is to have a table in my GUI and then write a row every time i read in data from a serial connection. I therefore would not know how many rows i will need. I could just pre-assign a very large table but this seems slow. I am expecting to read off a very large number of datapackets (potentially in the tens of thousands).
I have tried the insert_rows method but I don't think I fully understand how it works and the documentation is a bit sparse.
Also, I could not get the scroll bar to work. while i could add it easily by adding the lines below before the test.pack method call, they wouldn't scroll with the mouse. I think the binding is off:
scroll = Tkinter.Scrollbar(root)
test.configure(yscrollcommand=scroll.set)
scroll.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
Any help would be appreciated.
Thanks.
As it stands, sample_test creates a table with the configuration option
state='disabled' (this is why you can't add more rows).
Try setting it to state='normal', either at creation, or whenever you need
to make changes, whichever suits best.
def sample_test():
from Tkinter import Tk, Scrollbar, Button
def test_cmd(event):
print 'command'
def browsecmd(event):
print 'browsecmd'
#print event.__dict__
root = Tk()
quit = Button(root, text="QUIT", command=root.destroy)
quit.pack(side = 'bottom')
numrows, numcols = 10, 10
var = ArrayVar(root)
for y in range(numrows):
for x in range(numcols):
index = "%i,%i" % (y, x)
var[index] = index
test = Table(root,
rows=numrows+1,
cols=numcols+1,
state='normal',
width=6,
height=6,
titlerows=1,
titlecols=1,
roworigin=-1,
colorigin=-1,
selectmode='extended',
selecttype='row',
rowstretch='unset',
colstretch='last',
browsecmd=browsecmd,
flashmode='on',
variable=var,
usecommand=0,
command=test_cmd)
# http://effbot.org/zone/tkinter-scrollbar-patterns.htm
s = Scrollbar(root, orient='vertical', command=test.yview_scroll)
test.config(yscrollcommand=s.set)
s.pack(side='right', fill='y')
test.pack(expand=1, fill='both')
test.tag_configure('sel', background = 'yellow')
test.tag_configure('active', background = 'blue')
test.tag_configure('title', anchor='w', bg='red', relief='sunken')
data = ('py','t','h','o','n','','+','','Tk','')
def add_new_data(*args):
#test.config(state='normal')
test.insert_rows('end', 1)
r = test.index('end').split(',')[0] #get row number <str>
args = (r,) + args
idx = r + ',-1'
test.set('row', idx, *args)
test.see(idx)
#test.config(state='disabled')
root.after(3000, add_new_data, *data)
root.after(4000, add_new_data, *data)
root.mainloop()

Problems in Python getting multiple selections from Tkinter listbox

This is the same problem I posed earlier today and which a couple of you tried to help me with, but I can't get it to work. All I want to do is to populate "ichose" with the multiple selections I make when I click on the listbox.
import Tkinter as tk
from Tkinter import *
global ichose
class App(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
self.master=master
self.grid()
self.ichose = ()
self.l = Listbox(self, height=10, selectmode=EXTENDED)
# Selectmode can be SINGLE, BROWSE, MULTIPLE or EXTENDED. Default BROWSE
self.l.grid(column=0, row=0, sticky=(N,W,E,S))
self.l.bind("Double-Button-1", self.entered)
s = Scrollbar(self, orient=VERTICAL, command=self.l.yview)
s.grid(column=0, row=0, sticky=(N,S,E))
self.l['yscrollcommand'] = s.set
for i in range(1,101):
self.l.insert('end', 'Line %d of 100' % i)
def entered(self, event):
self.ichose = self.selection_get()
self.ichose = ('hello')
root=tk.Tk()
root.title('Listbox Problem')
root.geometry('200x200')
app=App(root)
root.mainloop()
print app.ichose
Whatever I do, "ichose" comes out as an empty tuple ().
It's clear that the function "entered" is never called because I never see the test string 'hello'.
I also don't know what the various options are as in "Double-Button-", "<>" etc. Where can I find a list and explanation of each one?
If somebody could please just modify my program so the "print ichose" works, I'd be really grateful. You can see from my program that I don't really know what I'm doing but am keen to learn. Thank you.
I've finally found the answer to my own question. This is REALLY useful if you want to capture multiple responses from a listbox. I've commented a lot. Hope it helps!
import Tkinter as tk
from Tkinter import *
class App(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
self.master=master
self.grid()
self.ichose = []
self.l = Listbox(self, height=10, selectmode=MULTIPLE)
# Selectmode can be SINGLE, BROWSE, MULTIPLE or EXTENDED. Default BROWSE
self.l.grid(column=0, row=0, sticky=(N,W,E,S))
s = Scrollbar(self, orient=VERTICAL, command=self.l.yview)
s.grid(column=0, row=0, sticky=(N,S,E))
self.l['yscrollcommand'] = s.set
for i in range(1,101):
self.l.insert('end', 'Line %d of 100' % i)
# Create Textbox that will display selected items from list
self.selected_list = Text(self,width=20,height=10,wrap=WORD)
self.selected_list.grid(row=12, column=0, sticky=W)
# Now execute the poll() function to capture selected list items
self.ichose = self.poll()
def poll(self):
items =[]
self.ichose = []
# Set up an automatically recurring event that repeats after 200 millisecs
self.selected_list.after(200, self.poll)
# curselection retrieves the selected items as a tuple of strings. These
# strings are the list indexes ('0' to whatever) of the items selected.
# map applies the function specified in the 1st parameter to every item
# from the 2nd parameter and returns a list of the results. So "items"
# is now a list of integers
items = map(int,self.l.curselection())
# For however many values there are in "items":
for i in range(len(items)):
# Use each number as an index and get from the listbox the actual
# text strings corresponding to each index, and append each to
# the list "ichose".
self.ichose.append(self.l.get(items[i]))
# Write ichose to the textbox to display it.
self.update_list()
return self.ichose
def update_list(self):
self.selected_list.delete(0.0, END)
self.selected_list.insert(0.0, self.ichose)
root=tk.Tk()
root.title('Listbox Multi-Capture')
root.geometry('200x340')
app=App(root)
root.mainloop()
print app.ichose
# ----------------[ Listbox EXAMPLE ]----------------
self.sarcCountries = (
"Bangladesh",
"India",
"Pakistan",
"Nepal",
"Bhutan",
"Sri Lanka",
"Afghanistan"
)
self.listData = StringVar(value = self.sarcCountries)
self.listbox = Listbox(
master = self,
height = 10,
listvariable = self.listData,
selectmode = MULTIPLE,
selectbackground = "#BC80CC"
)
self.listbox.bind("<<ListboxSelect>>", self.OnListboxSelectionChanged)
self.listbox.pack(fill = BOTH, expand = 0, padx = 10, pady = 10)
# ----------------[ Listbox EXAMPLE ]----------------
def OnListboxSelectionChanged(self, val):
# NOTE: If your listbox's select mode is MULTIPLE, then you may use this portion of code
selections = val.widget.curselection()
print("---------------------------")
if (selections != ()):
for index in selections:
print(self.sarcCountries[int(index)])
print("---------------------------")

Categories