【问题标题】:How to save and restore the status of a variable number of tkinter Checkbuttons in a sqlite database?如何在sqlite数据库中保存和恢复可变数量的tkinter Checkbuttons的状态?
【发布时间】:2022-01-26 22:33:14
【问题描述】:

我有将其状态(活动或非活动)保存在数据库中的复选框。它们都分组在chk_lst = [] 中,然后保存在表的单个列中(所以只有id, checkbox)。这些已正确保存和加载。显然,如您所知,0 或 1 都被保存了。

接下来我想为每个复选框分配一个函数、一个类或任何其他类型的代码,以便我激活该复选框并执行分配的代码。因此,由于 sql 的条件,我调用了这样的某个复选框,但我不知道我是否做得对。

我担心由于我低估或认为不正确的事情,这段代码可能是错误的和/或将来会出现问题。我没有收到错误,但我不知道我是否正确运行它,考虑到代码和数据库将通过许多复选框实现

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

为了确保答案的完整性,这是我用来将复选框保存在数据库中的代码。它运行良好且正常。问题不在这里

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()

如上所述,数据库只是一个简单的表,有id列和复选框列

【问题讨论】:

  • "它们都分组在 chk_lst = []...": 不,没有复选框存储在那里。只有 tkinter 控制变量(IntVar)在chk_lst
  • 请不要忘记花时间在这里发布答案的人:)

标签: python python-3.x sqlite tkinter checkbox


【解决方案1】:

让我们暂时忘记 SQL 部分,我认为如果我们忘记 SQL 部分,问题仍然可以解决。我不得不阅读这个问题几次才能推断出你想要传达的内容。

首先,您要做的就是在每次勾选或不勾选复选按钮时切换一个功能,对吗?您不必搜索太多,Checkbuttoncommand 选项将在您每次勾选/取消勾选复选按钮时执行。然后您只需将所需的IntVar 传递给函数,这样您就可以检查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()

【讨论】:

  • 感谢回复,但不是我的情况有问题。在我的情况下,复选框窗口是一个辅助窗口,用 tk.Toplevel (父级)调用。第二个复选框窗口使用这个:class Options (tk.Frame): def init __ (self, master, ** kw): super () . init __ (master, ** kw)。从主窗口调用复选框时。如何使用从主窗口调用 checkboc?在主窗口中,我应该使用类似 if var is check?
  • @DragomirCro 您的问题非常不清楚。您能否在问题中发布所有相关信息和代码。虽然这个问题对你来说似乎很清楚,但作为一个陌生人,我阅读你的问题几乎一无所知。我通过猜测和假设您的需要来回答。如果你能更清楚,它可以帮助我,谢谢:)
  • 有时我在晚上很累而且不太清楚的时候写问题,所以我问他们是错误的。感谢您的帮助和善意。我真的很感激 :) 明天,冷静地,我会更详细、更准确地写出这个问题。但是,我只需从辅助窗口中激活复选框并在主窗口中使用 ckeckbox 功能。再次感谢你的帮助。明天我会改进这个问题,显然投票并接受你的回答。对不起,谢谢你:)
  • @DragomirCro 同时,看看更新答案
  • 对不起,我现在才回答。这些天我有个人健康问题,我无法集中注意力,无法安心地改善问题。我会尽快改进这个问题。别担心,我没有忘记,因为我还需要答案。我检查了你的更新,但它不是我要找的。无论如何,谢谢你的好意。几天后,我将编辑问题并给您发表评论。谢谢和抱歉
【解决方案2】:

如果我明白你在做什么。 每次单击检查按钮时,它都会将结果写入数据库,检查记录是否已经存在,它还会显示之前的值。我添加了记录保存时间...

    #!/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()            
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2020-03-22
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    相关资源
    最近更新 更多