Home > Software engineering >  Python - "'function' object is not iterable " in GUI Combobox with multiple func
Python - "'function' object is not iterable " in GUI Combobox with multiple func

Time:11-19

The purpose of the codes is

  1. For each of three questions (GUI interface with Combobox style), I have to choose one item.
  2. Each item to the corresponding question represents a set of numbers.
  3. Based on what I chose for three questions, the codes will calculate the intersection of sets and show the answer on the screen.

Vall, Vcs, V360...are vectors of intergers. Suppose they are given. Ex: Vall = [6,8,13,17,23,38]... Of course, all of vectors are of the same dimension.

Codes:

import openpyxl
import numpy as np
from tkinter import *
import tkinter.ttk as ttk
from openpyxl import Workbook  # or "from openpyxl import Workbook": create workbook
from openpyxl import load_workbook # open/excess excel file or spreadsheet existed
from IPython.display import clear_output

# The following defines the function for each question shown on screen. 

def selected1(event):   # Type 
    if mycombobox.get() == 'Type':
        return Vall
    if mycombobox.get() == 'clam shell':
        return Vcs
    if mycombobox.get() == '360\u00b0':
        return V360

def selected2(event):   # WLAN1
    if mycombobox.get() == 'WLAN1 ant. position':
        return Vall
    if mycombobox1.get() == 'hinge':
        return Vhinge1
    if mycombobox1.get() == 'top':
        return Vtop1

def selected3(event):    # WLAN2
    if mycombobox.get() == 'WLAN2 ant. position':
        return Vall
    if mycombobox2.get() == 'hinge':
        return Vhinge2
    if mycombobox2.get() == 'top':
        return Vtop2

# The following function does the intersection of three sets obtained above. 

def set_intersection(xx1,xx2,xx3):
    collect_all = [xx1,xx2,xx3]
    recc = set.intersection(*map(set,collect_all))   # <----------------------
    my_list = list(recc)
    my_list.sort()
    return my_list

# ================== The main part: GUI. ====================== 

root = Tk()
root.title('Industry Solution')
root.geometry("500x800")

#  === Type (first question: type of computer), three choices: Type, clam shell... ===

label_a = Label(root, text="1. type of computer")
label_a.pack(side = TOP, pady=1) 
type_com = ['Type', 'clam shell', '360\u00b0']
mycombobox = ttk.Combobox(root, values = type_com)
mycombobox.current(0)
mycombobox.bind('<<ComboboxSelected>>',selected1)
mycombobox.pack(side = TOP, pady=1) 
recc1 = selected1

#  === WLAN1 position (second question: where is the WLAN1 antenna position)===

label_b = Label(root, text="2. WLAN1 antenna position")
label_b.pack(side = TOP, pady=1) 
WLAN1_ant = ['WLAN1 ant. position', 'hinge', 'top']
mycombobox1 = ttk.Combobox(root, values = WLAN1_ant)
mycombobox1.current(0)
mycombobox1.bind('<<ComboboxSelected>>',selected2)
mycombobox1.pack(side = TOP, pady=1) 
recc2 = selected1

#  === WLAN2 position (third question: where is the WLAN2 antenna position) ===

label_c = Label(root, text="3. WLAN2 antenna position")
label_c.pack(side = TOP, pady=1) 
WLAN2_ant = ['WLAN2 ant. position', 'hinge', 'top']
mycombobox2 = ttk.Combobox(root, values = WLAN2_ant)
mycombobox2.current(0)
mycombobox2.bind('<<ComboboxSelected>>',selected3)
mycombobox2.pack(side = TOP, pady=1) 
recc3 = selected3

# === Result (After choosing answers, push button, and then codes will do calculation)===

mybutton = Button(root, text = 'OK, send out', command = set_intersection(recc1,recc2,recc3))  # <----------------------
mybutton.pack(side = TOP, pady=10)


root.mainloop()

When I ran the codes, it shows an error:

TypeError: 'function' object is not iterable
--> 55     recc = set.intersection(*map(set,collect_all))
--> 40 mybutton = Button(root, text = 'OK, send out', command = set_intersection(recc1,recc2,recc3))

I think I should have put an parameter in selectedi(), i=1~3, function like

recc1 = selected1(values)
recc2 = selected2(values)
recc3 = selected3(values)

However, values has been used in the Combobox. I have no idea how to correct my codes.
Any helpful suggestions are appreciated.

CodePudding user response:

set_intersection(recc1,recc2,recc3) this code is executed when declared and returns a list. Lists cant be a command of a button. Follow the link to solve this issue.

In addition selected1 till 3 will return values that arent defined. Anyway what you need to do.

First change the positional argument to a optional keyword argument for selected1-3. This makes you abel to call these functions without a event object, as an alternative you could pass None.

def selected1(event=None):   # Type 

Next thing is you want the returned values not the stored functions, so execute them:

collect_all = [xx1(),xx2(),xx3()]

You also need to use the right comboboxes to get the right value:

if mycombobox1.get() == 'WLAN1 ant. position':

While I dont know the purpose of this line set.intersection(*map(set,collect_all)) I'll leave it to you to solve

#import openpyxl
#import numpy as np
from tkinter import *
import tkinter.ttk as ttk
#from openpyxl import Workbook  # or "from openpyxl import Workbook": create workbook
#from openpyxl import load_workbook # open/excess excel file or spreadsheet existed
#from IPython.display import clear_output

# The following defines the function for each question shown on screen. 

def selected1(event=None):   # Type 
    if mycombobox.get() == 'Type':
        return 'hello'#Vall
    if mycombobox.get() == 'clam shell':
        return Vcs
    if mycombobox.get() == '360\u00b0':
        return V360

def selected2(event=None):   # WLAN1
    if mycombobox1.get() == 'WLAN1 ant. position':
        return 'world'#Vall
    if mycombobox1.get() == 'hinge':
        return Vhinge1
    if mycombobox1.get() == 'top':
        return Vtop1

def selected3(event=None):    # WLAN2
    if mycombobox2.get() == 'WLAN2 ant. position':
        return 'and all other'#Vall
    if mycombobox2.get() == 'hinge':
        return Vhinge2
    if mycombobox2.get() == 'top':
        return Vtop2

# The following function does the intersection of three sets obtained above. 

def set_intersection(xx1,xx2,xx3):
    collect_all = [xx1,xx2,xx3]
    print(collect_all)
    recc = set.intersection(*map(set,collect_all))   # <----------------------
    my_list = list(recc)
    my_list.sort()
    return my_list

# ================== The main part: GUI. ====================== 

root = Tk()
root.title('Industry Solution')
root.geometry("500x800")

#  === Type (first question: type of computer), three choices: Type, clam shell... ===

label_a = Label(root, text="1. type of computer")
label_a.pack(side = TOP, pady=1) 
type_com = ['Type', 'clam shell', '360\u00b0']
mycombobox = ttk.Combobox(root, values = type_com)
mycombobox.current(0)
mycombobox.bind('<<ComboboxSelected>>',selected1)
mycombobox.pack(side = TOP, pady=1) 
recc1 = selected1

#  === WLAN1 position (second question: where is the WLAN1 antenna position)===

label_b = Label(root, text="2. WLAN1 antenna position")
label_b.pack(side = TOP, pady=1) 
WLAN1_ant = ['WLAN1 ant. position', 'hinge', 'top']
mycombobox1 = ttk.Combobox(root, values = WLAN1_ant)
mycombobox1.current(0)
mycombobox1.bind('<<ComboboxSelected>>',selected2)
mycombobox1.pack(side = TOP, pady=1) 
recc2 = selected2

#  === WLAN2 position (third question: where is the WLAN2 antenna position) ===

label_c = Label(root, text="3. WLAN2 antenna position")
label_c.pack(side = TOP, pady=1) 
WLAN2_ant = ['WLAN2 ant. position', 'hinge', 'top']
mycombobox2 = ttk.Combobox(root, values = WLAN2_ant)
mycombobox2.current(0)
mycombobox2.bind('<<ComboboxSelected>>',selected3)
mycombobox2.pack(side = TOP, pady=1) 
recc3 = selected3

# === Result (After choosing answers, push button, and then codes will do calculation)===

mybutton = Button(root, text = 'OK, send out', command = lambda:set_intersection(recc1(),recc2(),recc3()))  # <----------------------
mybutton.pack(side = TOP, pady=10)


root.mainloop()

CodePudding user response:

The only problem I see is you are dumping the entire function call in the command argument. That's not how it works. command should equal a reference to the function you want to call, like this:

command=set_intersection

However, you have a bunch of args that you want to pass. You could make those args global or you can just wrap the whole thing in a lambda. One way to do it is like this:

command = lambda r1=recc1, r2=recc2, r3=recc3: set_intersection(r1,r2,r3)

when you do this: command = set_intersection(recc1,recc2,recc3) you are telling python that command equals my_list (i.e. the return from your set_intersection function). command is supposed to equal a function, not a list, and that's why it is telling you that "function object is not iterable". What it is saying (in clearer terms) is: "you can't assign a list where I expect a function"

  • Related