Home > Software design >  Intersect lists of different functions only in relation to the selection of the checkboxes. Error: w
Intersect lists of different functions only in relation to the selection of the checkboxes. Error: w

Time:12-28

I have a problem with 3 checkboxes intersecting when using list in checkbox functions. I would like to use intersection in relation to the quantity and combination of selected checkboxes.

I tried to insert the checkbox functions in a list and combine them with a condition if the checkboxes are only selected or deselected:

all_test = [(Button1_func()) if Checkbutton1.get() else not Checkbutton1.get(),
            (Button2_func()) if Checkbutton2.get() else not Checkbutton2.get(),
            (Button3_func()) if Checkbutton3.get() else not Checkbutton3.get()]

Next, I put the list in c = set.intersection(*all_test)

If I try to select one or more checkboxes, I get this error:

TypeError: descriptor 'intersection' for 'set' objects doesn't apply to a 'bool' object

Let me explain better, with an example, what I would like to achieve. For example if I select only checkbox1 I would like to print a, b, c, d, e. If I select all the checkboxes I would like to print only a, b, because the elements in common in the three lists are only a, b. How can I print what I said above without getting errors?

I'm looking for a solution that allows me to manage even 20 checkboxes if I need to extend the code in the future.

from tkinter import ttk
import tkinter as tk

root = tk.Tk()
root.geometry("300x300")

funclist = set()
Checkbutton1 = tk.IntVar()
Checkbutton2 = tk.IntVar()
Checkbutton3 = tk.IntVar()

#CHECKBOX'S FUNCTIONS
def Button1_func():
    test1 = ["a", "b", "c", "d", "e"]
    return test1
 
def Button2_func():
    test2 = ["a", "b", "c"]
    return test2

def Button3_func():
    test3 = ["a", "b"]
    return test3

def clicked(flag, func):
    if flag:
        funclist.add(func)
    else:
        funclist.remove(func)


#CHECKBOX
Button1 = tk.Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton1.get(), Button1_func))
Button1.place(x=10, y=36)

Button2 = tk.Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton2.get(), Button2_func))
Button2.place(x=10, y=66)

Button3 = tk.Checkbutton(root, text = "Checkbox 3", variable = Checkbutton3, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton3.get(), Button3_func))
Button3.place(x=10, y=96)


all_test = [(Button1_func()) if Checkbutton1.get() else not Checkbutton1.get(),
            (Button2_func()) if Checkbutton2.get() else not Checkbutton2.get(),
            (Button3_func()) if Checkbutton3.get() else not Checkbutton3.get()]


def try_print():
    #if each checkbox is True:
    if funclist and all(func() for func in funclist): 
        c = set.intersection(*all_test)      
        print(c)

#PRINT BUTTON
button = tk.Button(root, text="Print", command= lambda: [try_print()])
button.place(x=10, y=140)

root.mainloop()

UPDATE CODE (with addition of: saving and loading in database)

import sqlite3
from tkinter import ttk
import tkinter as tk

root = tk.Tk()
root.geometry("300x300")

conn = sqlite3.connect("xyz.db")
c = conn.cursor()

chk_lst = []
fn_lst = []
funclist = set()
Checkbutton1 = tk.IntVar()
Checkbutton2 = tk.IntVar()
Checkbutton3 = tk.IntVar()

#CHECKBOX'S FUNCTIONS
def Button1_func():
    test1 = ["a", "b", "c", "d", "e"]
    return test1
 
def Button2_func():
    test2 = ["a", "b", "c"]
    return test2

def Button3_func():
    test3 = ["a", "b"]
    return test3

def clicked(flag, func):
    if flag:
        funclist.add(func)
    else:
        funclist.remove(func)


#CHECKBOX
Button1 = tk.Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton1.get(), Button1_func))
Button1.place(x=10, y=36)

Button2 = tk.Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton2.get(), Button2_func))
Button2.place(x=10, y=66)

Button3 = tk.Checkbutton(root, text = "Checkbox 3", variable = Checkbutton3, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton3.get(), Button3_func))
Button3.place(x=10, y=96)


all_test = [(Button1_func()) if Checkbutton1.get() else not Checkbutton1.get(),
            (Button2_func()) if Checkbutton2.get() else not Checkbutton2.get(),
            (Button3_func()) if Checkbutton3.get() else not Checkbutton3.get()]


def try_print():
    if funclist and all(func() for func in funclist): 
        c = set.intersection(*all_test)      
        print(c)

chk_lst.extend([Checkbutton1, Checkbutton2, Checkbutton3])
fn_lst.extend([Button1_func, Button2_func, Button3_func])

#SAVE IN DATABASE
def save():
    conn = sqlite3.connect("xyz.db")
    c = conn.cursor()

    for idx,chk_btn in enumerate(chk_lst,start=1):
        c.execute(f'SELECT button1 FROM test WHERE id=?',(idx,))
        rec = c.fetchall()

        if rec:
            c.execute("UPDATE test SET Button1=? WHERE id=?;", (chk_btn.get(),idx))
        else:
            c.execute("INSERT INTO test VALUES (?,?,?);", (idx,chk_btn.get()))
        
    conn.commit()
    conn.close()

    messagebox.showinfo('SAVE', 'Good!')


#LOAD WHEN OPEN WINDOWS
def load():
    conn = sqlite3.connect("xyz.db")
    c = conn.cursor()
    c.execute("SELECT * FROM test")
    vals = c.fetchall()

    for val, chk_btn, func in zip(vals, chk_lst, fn_lst):
        chk_btn.set(val[1])
        
        if val[1] == '1': #update the funclist set based on the data fetched from the database
            funclist.add(func)

    conn.close()



#PRINT BUTTON
button = tk.Button(root, text="Print", command= lambda: [try_print()])
button.place(x=10, y=140)

load()

root.mainloop()

CodePudding user response:

The following should work as you require (with some inline comments):

import tkinter as tk

root = tk.Tk()
root.geometry("300x300")

# store the output of the functions in a list rather than a set
datalist = []

Checkbutton1 = tk.IntVar()
Checkbutton2 = tk.IntVar()
Checkbutton3 = tk.IntVar()


#CHECKBOX'S FUNCTIONS
def Button1_func():
    # put these in a set
    test1 = set(["a", "b", "c", "d", "e"])
    return test1


def Button2_func():
    test2 = set(["a", "b", "c"])
    return test2


def Button3_func():
    test3 = set(["a", "b"])
    return test3


def clicked(flag, func):
    if flag:
        # append set to the list
        datalist.append(func())
    else:
        # remove set from the list
        datalist.remove(func())


#CHECKBOX
Button1 = tk.Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton1.get(), Button1_func))
Button1.place(x=10, y=36)

Button2 = tk.Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton2.get(), Button2_func))
Button2.place(x=10, y=66)

Button3 = tk.Checkbutton(root, text = "Checkbox 3", variable = Checkbutton3, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton3.get(), Button3_func))
Button3.place(x=10, y=96)


def try_print():
    # check that there is something in the list
    if len(datalist) > 0:
        c = set.intersection(*datalist)      
        print(c)

#PRINT BUTTON
button = tk.Button(root, text="Print", command=try_print)
button.place(x=10, y=140)

root.mainloop()

Note: due to using sets the order of the lists will not necessarily be preserved. If preserving the order is important then another method of finding the intersection will be needed (see, e.g., the various answers here).

Update

An updated answer to try and work with the updated code is:

import sqlite3
from tkinter import ttk
import tkinter as tk

root = tk.Tk()
root.geometry("300x300")

conn = sqlite3.connect("xyz.db")
c = conn.cursor()

chk_lst = []
fn_lst = []
datalist = []

Checkbutton1 = tk.IntVar()
Checkbutton2 = tk.IntVar()
Checkbutton3 = tk.IntVar()

#CHECKBOX'S FUNCTIONS
def Button1_func():
    test1 = set(["a", "b", "c", "d", "e"])
    return test1
 
def Button2_func():
    test2 = set(["a", "b", "c"])
    return test2

def Button3_func():
    test3 = set(["a", "b"])
    return test3

def clicked(flag, func):
    if flag:
        datalist.append(func())
    else:
        datalist.remove(func())


#CHECKBOX
Button1 = tk.Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton1.get(), Button1_func))
Button1.place(x=10, y=36)

Button2 = tk.Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton2.get(), Button2_func))
Button2.place(x=10, y=66)

Button3 = tk.Checkbutton(root, text = "Checkbox 3", variable = Checkbutton3, onvalue = 1, offvalue = 0, height = 1,
                         bg="#d9d9d9", foreground='black', activebackground="#d9d9d9",
                         command=lambda: clicked(Checkbutton3.get(), Button3_func))
Button3.place(x=10, y=96)


def try_print():
    if len(datalist) > 0:
        c = set.intersection(*datalist)      
        print(c)

chk_lst.extend([Checkbutton1, Checkbutton2, Checkbutton3])
fn_lst.extend([Button1_func, Button2_func, Button3_func])

#SAVE IN DATABASE
def save():
    conn = sqlite3.connect("xyz.db")
    c = conn.cursor()

    for idx,chk_btn in enumerate(chk_lst,start=1):
        c.execute(f'SELECT button1 FROM test WHERE id=?',(idx,))
        rec = c.fetchall()

        if rec:
            c.execute("UPDATE test SET Button1=? WHERE id=?;", (chk_btn.get(),idx))
        else:
            c.execute("INSERT INTO test VALUES (?,?,?);", (idx,chk_btn.get()))
        
    conn.commit()
    conn.close()

    messagebox.showinfo('SAVE', 'Good!')


#LOAD WHEN OPEN WINDOWS
def load():
    conn = sqlite3.connect("xyz.db")
    c = conn.cursor()
    c.execute("SELECT * FROM test")
    vals = c.fetchall()

    for val, chk_btn, func in zip(vals, chk_lst, fn_lst):
        chk_btn.set(val[1])
        
        if val[1] == '1': #update the funclist set based on the data fetched from the database
            datalist.append(func())

    conn.close()


#PRINT BUTTON
button = tk.Button(root, text="Print", command= lambda: [try_print()])
button.place(x=10, y=140)

load()

root.mainloop()
  • Related