I have checkboxes that save their status (active or inactive) in a database. They are all grouped in chk_lst = []
and then they are saved in a single column of a table (so only id, checkbox
). These are saved and loaded correctly. Obviously, as you know, either 0 or 1 is saved.
Next I want to assign a function, a class or any kind of other code to each checkbox, so that I activate the checkbox and execute the assigned code. So I call a certain checkbox like this thanks to a condition with sql, but I don't know if I'm doing it right.
I'm afraid this code may be wrong and / or have problems in the future due to something I underestimated or didn't think right. I'm not getting errors, but I don't know if I'm running it correctly, considering the code and database will be implemented with many checkboxes
conn = sqlite3.connect('....')
cursor = conn.cursor()
cursor.execute('SELECT checkbox FROM table_example')
x = cursor.fetchone()
if checkbox[0] == "1": #THIS PART
code....
else:
None
This instead, for information purposes for completeness of the answer, is the code I use to save the checkboxes in the database. It works good and properly. The problem is not here
import sqlite3
from tkinter import *
from tkinter import ttk
import tkinter as tk
import tkinter.messagebox
from tkinter import messagebox
root = tk.Tk()
root.geometry("200x200")
root.configure(bg='white')
chk_lst = []
#Checkbox
Checkbutton1 = IntVar()
Checkbutton2 = IntVar()
Button1 = Checkbutton(root, text = "Checkbox 1", variable = Checkbutton1, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white")
Button1.place(x=10, y=36)
Button2 = Checkbutton(root, text = "Checkbox 2", variable = Checkbutton2, onvalue = 1, offvalue = 0, height = 1,
bg="white", foreground='black', activebackground="white")
Button2.place(x=10, y=66)
chk_lst.extend([Checkbutton1,Checkbutton2])
# Save Function
def save():
conn = sqlite3.connect(".....")
c = conn.cursor()
for idx,chk_btn in enumerate(chk_lst,start=1):
c.execute(f'SELECT checkbox FROM table_example WHERE id=?',(idx,))
rec = c.fetchall()
if rec:
c.execute("UPDATE table_example SET checkbox=? WHERE id=?;", (chk_btn.get(),idx))
else:
c.execute("INSERT INTO table_example VALUES (?,?);", (idx,chk_btn.get()))
conn.commit()
conn.close()
messagebox.showinfo("Saved successfully","Saved successfully")
# Load Function
def load():
conn = sqlite3.connect("....")
c = conn.cursor()
c.execute("SELECT * FROM table_example")
vals = c.fetchall()
for val,chk_btn in zip(vals,chk_lst):
chk_btn.set(val[1])
conn.close()
save = Button(root, text="save", bg='#b40909', foreground='white', command= save)
save.pack()
save.place(x=10, y=96)
load()
root.mainloop()
As mentioned above, the database is just a simple table with id column and checkbox column
CodePudding user response:
Lets just forget the SQL part for a moment, I think the problem can still be fixed if we forget the SQL part. I had to read the question few times to deduce what you were trying to convery.
So to begin with, all you want to do is toggle a function each time a checkbutton is ticked or not, right? You do not have to search so much for it, there is a command
option for Checkbutton
that will get executed, each time you tick/untick a checkbutton. Then all you need is to pass the required IntVar
to the function, so you can check the value of the checkbutton.
from tkinter import *
root = Tk()
def func(var):
if var.get(): # Also same as `if var.get() == 1`
print('It is ticked') # Replace with whatever you wanted to do if the checkbutton is ticked
else:
print('Not ticked')
def new_win(cb):
top = Toplevel(root)
def cmd(cb):
cb.invoke() # Invoke the linked function, this will tick the checkbutton
Button(top,text='Click me to toggle the tickbox',command=lambda: cmd(cb)).pack(pady=5)
var = IntVar()
cb = Checkbutton(root,text='Checkbutton 1',variable=var,command=lambda: func(var))
cb.pack(padx=10,pady=10)
Button(root,text='Open new window',command=lambda: new_win(cb)).pack()
root.mainloop()
CodePudding user response:
If I understand what you’re doing. Every time you click on a checkbutton, it writes the result to the database, checking if the record is already present, it also shows you the previous value. I added record save time...
#!/usr/bin/python3
import sys
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import sqlite3 as lite
import datetime
class Main(ttk.Frame):
def __init__(self, parent, ):
super().__init__(name="main")
self.parent = parent
self.checkbutton1 = tk.BooleanVar()
self.checkbutton2 = tk.BooleanVar()
self.dict_checks = {1: self.checkbutton1, 2: self.checkbutton2}
self.init_ui()
self.init_db()
def init_db(self,):
self.con = lite.connect(self.master.kwargs["database"],
detect_types=lite.PARSE_DECLTYPES|lite.PARSE_COLNAMES,
isolation_level='IMMEDIATE')
self.con.text_factory = lite.OptimizedUnicode
sql = "CREATE TABLE IF NOT EXISTS 'examples' ('example_id' INTEGER PRIMARY KEY,'checkbox_id' INTEGER, 'status' BOOLEAN DEFAULT '1', click_date TEXT)"
cur = self.con.cursor()
cur.execute(sql, ())
self.con.commit()
def init_ui(self):
f0 = ttk.Frame(self)
f1 = ttk.Frame(f0,)
ttk.Label(f1, text="First Checkbutton:").pack()
ttk.Checkbutton(f1,
onvalue=1,
offvalue=0,
variable=self.checkbutton1,
command=self.on_callback).pack()
ttk.Label(f1, text="Second Checkbutton:").pack()
ttk.Checkbutton(f1,
onvalue=1,
offvalue=0,
variable=self.checkbutton2,
command=self.on_callback).pack()
f2 = ttk.Frame(f0,)
bts = [("Callback", 7, self.on_callback, "<Alt-k>"),
("Read", 0, self.on_read, "<Alt-r>"),
("Close", 0, self.on_close, "<Alt-c>")]
for btn in bts:
ttk.Button(f2,
text=btn[0],
underline=btn[1],
command = btn[2]).pack(fill=tk.X, padx=5, pady=5)
self.parent.bind(btn[3], btn[2])
f1.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
f2.pack(side=tk.RIGHT, fill=tk.Y, expand=0)
f0.pack(fill=tk.BOTH, expand=1)
def on_callback(self, evt=None):
print("Previous values:")
self.on_read()
cur = self.con.cursor()
now = datetime.datetime.now()
for k,v in self.dict_checks.items():
if self.check_status(k) is not None:
sql = "UPDATE examples SET status =?, click_date= ? WHERE checkbox_id =?;"
args = (v.get(),now, k)
else:
sql = "INSERT INTO examples (checkbox_id, status, click_date)VALUES(?,?,?);"
args = (k, v.get(),now)
cur.execute(sql, args)
self.con.commit()
cur.close()
print("Actual values:")
self.on_read()
def check_status(self, checkbox_id):
sql = "SELECT * FROM examples WHERE checkbox_id =?"
args = (checkbox_id,)
cur = self.con.cursor()
cur.execute(sql, args)
rs = cur.fetchone()
cur.close()
return rs
def on_read(self,):
cur = self.con.cursor()
sql = "SELECT * FROM examples;"
cur.execute(sql)
rs = cur.fetchall()
cur.close()
if rs:
for i in rs:
print(i)
print("*"*79)
def on_close(self, evt=None):
self.con.close()
self.parent.on_exit()
class App(tk.Tk):
"""Main Application start here"""
def __init__(self, *args, **kwargs):
super().__init__()
self.args = args
self.kwargs = kwargs
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_style(kwargs["style"])
self.set_title(kwargs["title"])
self.resizable(width=False, height=False)
Main(self).pack(fill=tk.BOTH, expand=1)
def set_style(self, which):
self.style = ttk.Style()
self.style.theme_use(which)
def set_title(self, title):
s = "{0}".format(title)
self.title(s)
def on_exit(self):
"""Close all"""
msg = "Do you want to quit?"
if messagebox.askokcancel(self.title(), msg, parent=self):
self.destroy()
def main():
args = []
for i in sys.argv:
args.append(i)
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
kwargs = {"style":"clam", "title":"Simple App", "database":"examples.db"}
app = App(*args, **kwargs)
app.mainloop()
if __name__ == '__main__':
main()