如何使用 Tkinter Listbox 小部件在 Sqlite3 table 中获取一行?
How can I get a row in Sqlite3 table with Tkinter Listbox widget?
我有 Python 程序在前端使用 Tkinter 连接到 Sqlite3 数据库。我的数据库 table(主题列表)由四列组成:[id(唯一整数)、主题(文本)、serial(唯一整数)、is_active(布尔整数)]。这是我的程序:
import sqlite3
from tkinter import *
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('SELECT COUNT() FROM subjectlist WHERE is_active = 1')
number = c.fetchone()[0]
c.execute('SELECT * FROM subjectlist WHERE is_active = 1 ORDER BY serial')
data = c.fetchall()
c.close
conn.close()
root = Tk()
listbox = Listbox(root)
listbox.pack()
for i in range(number):
listbox.insert(END, data[i][1])
def get_serial():
print(listbox.get(listbox.curselection()))
btn = Button(root, text="Show row", command=lambda: get_serial())
btn.pack()
mainloop()
当前在运行时,当我单击列表框上的项目(基本上显示同一行上具有 is_active=1 的所有主题列值)然后按 Tkinter 按钮时,我得到了我单击的主题。相反,我想获得我单击的整行。
关于 table 需要考虑的事项很少:
- 主题列可能在两个或多个不同的行上具有相同的值。
- 列表框中的项目按序号排列
- 如果行 is_active 值为 0 (False),它将不会显示在列表框中。列表框中将没有空行,下一个 is_active=1 (True) 行将取而代之。
考虑这个 table(左)及其在 GUI 上的表示(右):
我希望 GUI 首先显示列表框中的所有 is_active=1 个主题。然后单击“Dogs”(列表框显示的第三项),然后单击按钮,我希望程序打印整行(id=1,subject=Dogs,serial=5,is_active =1).
我将如何实现这一目标?
我能想到的使用 Listbox
并提取整行值的唯一方法是将值插入到列表框中,并与字典中的引用一起保存,以及通常增加的数字。字典是{idx:[id,subject]}
的形式,确实你不需要在列表中包含主题,你也可以只用id,但它可以让你更容易理解带有主题的选择。
看看:
from tkinter import *
import sqlite3
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('SELECT * FROM subjectlist ORDER BY serial')
data = c.fetchall()
conn.close()
root = Tk()
dictio = {} # Empty dictionary to keep reference of appended values
listbox = Listbox(root)
listbox.pack()
a = 0 # A normally increasing number as the key of the dict
tot_rows = len(data) # Total number of rows
for i in range(tot_rows):
if data[i][3]: # If is_active == 1
dictio[a] = [data[i][0],data[i][1]] # Append the subject as the a-th item to dict, along with its id number
listbox.insert(END, data[i][1]) # Inseert the data #add the subject to listbox
a += 1 # Increase the number by 1
def get_serial():
conn = sqlite3.connect('database.db')
c = conn.cursor()
val = listbox.curselection()[0] # Index of our current selection
sel = dictio[val] # Get value from the dictionary based on the indexed number
ids = sel[0] # Index the first item of the list
c.execute('SELECT * FROM subjectlist WHERE `id`=?',(ids,)) # Search the database based on id of item
print(c.fetchall()) # Print the item out as a tuple
conn.close() # Close the connection
btn = Button(root, text="Show row", command=get_serial)
btn.pack()
listbox.bind('<Double-Button-1>',lambda e=None:get_serial()) # Bonus :p
mainloop()
我对代码进行了大量扩展以使其更易于理解,我希望这也是您提出问题的意思。我对代码进行了注释,以使其在旅途中也易于理解。
输出:
(1,'Dogs', 5, 1) #(Id, subject, serial, is_active)
尽管如果您要使用 ttk.Treeview
,您实际上可以创建两列,一列带有 id,另一列带有主题,因此从中提取数据比使用列表框要容易得多,并且将信息保存在字典中,稍后用它来搜索数据库。
您可以使用 row_factory
或 sqlite3
创建字典游标并获得您想要的类似输出:
import sqlite3
from tkinter import *
def dict_factory(cursor, row):
return {col[0]:row[idx] for idx, col in enumerate(cursor.description)}
conn = sqlite3.connect('database.db')
conn.row_factory = dict_factory
c = conn.cursor()
c.execute('SELECT * FROM subjectlist WHERE is_active = 1 ORDER BY serial')
data = c.fetchall()
c.close
conn.close()
root = Tk()
listbox = Listbox(root)
listbox.pack()
for rec in data:
listbox.insert(END, rec["subject"])
def get_serial():
selected = listbox.curselection()
if selected:
print(data[selected[0]])
else:
print("No item selected")
btn = Button(root, text="Show row", command=get_serial)
btn.pack()
mainloop()
并且输出:
{'id': 1, 'subject': 'Dogs', 'serial': 5, 'is_active': 1}
我有 Python 程序在前端使用 Tkinter 连接到 Sqlite3 数据库。我的数据库 table(主题列表)由四列组成:[id(唯一整数)、主题(文本)、serial(唯一整数)、is_active(布尔整数)]。这是我的程序:
import sqlite3
from tkinter import *
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('SELECT COUNT() FROM subjectlist WHERE is_active = 1')
number = c.fetchone()[0]
c.execute('SELECT * FROM subjectlist WHERE is_active = 1 ORDER BY serial')
data = c.fetchall()
c.close
conn.close()
root = Tk()
listbox = Listbox(root)
listbox.pack()
for i in range(number):
listbox.insert(END, data[i][1])
def get_serial():
print(listbox.get(listbox.curselection()))
btn = Button(root, text="Show row", command=lambda: get_serial())
btn.pack()
mainloop()
当前在运行时,当我单击列表框上的项目(基本上显示同一行上具有 is_active=1 的所有主题列值)然后按 Tkinter 按钮时,我得到了我单击的主题。相反,我想获得我单击的整行。
关于 table 需要考虑的事项很少:
- 主题列可能在两个或多个不同的行上具有相同的值。
- 列表框中的项目按序号排列
- 如果行 is_active 值为 0 (False),它将不会显示在列表框中。列表框中将没有空行,下一个 is_active=1 (True) 行将取而代之。
考虑这个 table(左)及其在 GUI 上的表示(右):
我希望 GUI 首先显示列表框中的所有 is_active=1 个主题。然后单击“Dogs”(列表框显示的第三项),然后单击按钮,我希望程序打印整行(id=1,subject=Dogs,serial=5,is_active =1).
我将如何实现这一目标?
我能想到的使用 Listbox
并提取整行值的唯一方法是将值插入到列表框中,并与字典中的引用一起保存,以及通常增加的数字。字典是{idx:[id,subject]}
的形式,确实你不需要在列表中包含主题,你也可以只用id,但它可以让你更容易理解带有主题的选择。
看看:
from tkinter import *
import sqlite3
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('SELECT * FROM subjectlist ORDER BY serial')
data = c.fetchall()
conn.close()
root = Tk()
dictio = {} # Empty dictionary to keep reference of appended values
listbox = Listbox(root)
listbox.pack()
a = 0 # A normally increasing number as the key of the dict
tot_rows = len(data) # Total number of rows
for i in range(tot_rows):
if data[i][3]: # If is_active == 1
dictio[a] = [data[i][0],data[i][1]] # Append the subject as the a-th item to dict, along with its id number
listbox.insert(END, data[i][1]) # Inseert the data #add the subject to listbox
a += 1 # Increase the number by 1
def get_serial():
conn = sqlite3.connect('database.db')
c = conn.cursor()
val = listbox.curselection()[0] # Index of our current selection
sel = dictio[val] # Get value from the dictionary based on the indexed number
ids = sel[0] # Index the first item of the list
c.execute('SELECT * FROM subjectlist WHERE `id`=?',(ids,)) # Search the database based on id of item
print(c.fetchall()) # Print the item out as a tuple
conn.close() # Close the connection
btn = Button(root, text="Show row", command=get_serial)
btn.pack()
listbox.bind('<Double-Button-1>',lambda e=None:get_serial()) # Bonus :p
mainloop()
我对代码进行了大量扩展以使其更易于理解,我希望这也是您提出问题的意思。我对代码进行了注释,以使其在旅途中也易于理解。
输出:
(1,'Dogs', 5, 1) #(Id, subject, serial, is_active)
尽管如果您要使用 ttk.Treeview
,您实际上可以创建两列,一列带有 id,另一列带有主题,因此从中提取数据比使用列表框要容易得多,并且将信息保存在字典中,稍后用它来搜索数据库。
您可以使用 row_factory
或 sqlite3
创建字典游标并获得您想要的类似输出:
import sqlite3
from tkinter import *
def dict_factory(cursor, row):
return {col[0]:row[idx] for idx, col in enumerate(cursor.description)}
conn = sqlite3.connect('database.db')
conn.row_factory = dict_factory
c = conn.cursor()
c.execute('SELECT * FROM subjectlist WHERE is_active = 1 ORDER BY serial')
data = c.fetchall()
c.close
conn.close()
root = Tk()
listbox = Listbox(root)
listbox.pack()
for rec in data:
listbox.insert(END, rec["subject"])
def get_serial():
selected = listbox.curselection()
if selected:
print(data[selected[0]])
else:
print("No item selected")
btn = Button(root, text="Show row", command=get_serial)
btn.pack()
mainloop()
并且输出:
{'id': 1, 'subject': 'Dogs', 'serial': 5, 'is_active': 1}