Having problems pulling out check box values in a loop - python

I want to make a food selector page where food items being stored in a database are being printed out with check boxes but I'm having problems getting the value from the check boxes
def foodSelector():
editor = Tk()
editor.title('Food Items')
editor.geometry("400x400")
conn = sqlite3.connect('food.db')
c = conn.cursor()
c.execute("SELECT *, oid FROM foods")
records = c.fetchall()
def show():
myLabel = Label(editor, text=record).pack()
v = []
for i, record in enumerate(records):
v.append(IntVar(value=1))
query = Checkbutton(editor, text=record, variable = v[i])#record
query.pack()
myButton = Button(editor, text="Show Selection", command=show).pack()

Posting as an answer as its too big for comments:
from tkinter import *
editor = Tk()
editor.title('Food Items')
editor.geometry("400x400")
records = [(1,2,3,4),(3,2,1,3),(12,31,5,12)]
def show(rec):
global items
items = []
for i, record in enumerate(records):
if v[i].get()==1:
items.append(record)
def final():
Label(editor, text=items).pack()
v = []
for i, record in enumerate(records):
v.append(IntVar(value=0))
query = Checkbutton(editor, text=record, variable = v[i],command=lambda i=record:show(i))#record
query.pack()
myButton = Button(editor, text="Show Selection", command=final).pack()
editor.mainloop()
Is this what you wanted? I've used a random list of tuple here to mimic your records fetched from database. Keep in mind to not use the button as it will give the error.
Anyway for small parts of explanation, what lambda i=record:show(i) does is that, it holds the value of record(while iterating) in a parameter which is then passed to show()(when clicked on checkbutton) and then that is used in show(records) to put the text rec on the label, with text=rec.

In function show, it take variable record as label text, so it always show last value at end of for loop.
Example for show,
# records = ['Bread', 'Beef', 'Pork']
def show():
items = [record for i, record in enumerate(records) if v[i].get()==1]
text = 'Selected items: ' + ','.join(items) if items else 'No items selected !'
myLabel = Label(editor, text=text).pack()

Related

Python. Cannot place list items into individual variables. When I do, the variable contains the whole list items

def nextPage():
conn = sqlite3.connect('xyz.db')
c = conn.cursor()
c.execute("INSERT INTO persons VALUES (?,?)",(text.get(),text1.get()))
conn.commit()
conn.close()
def submit():
conn = sqlite3.connect('xyz.db')
c =conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS persons(
name1 TEXT,
name2 TEXT)''')
conn.commit()
conn.close()
def query():
conn = sqlite3.connect('xyz.db')
c = conn.cursor()
c.execute('SELECT * FROM persons')
records = c.fetchall()
print(records[0])
conn.commit()
conn.close()
import sqlite3
from tkinter import *
from tkinter import ttk
import tkinter as tk
ws = Tk()
ws.geometry('770x400')
ws.title('PythonGuides')
a = Label(ws ,text = "Name").grid(row = 1,column = 0)
b = Label(ws ,text = "Name of Spouse or CP, if applicable").grid(row = 2,column = 0)
text = Entry(ws)
text.grid(row = 1 , column = 1)
text1 = Entry(ws)
text1.grid(row = 2 , column = 1)
btn = ttk.Button(ws ,text="Submit", command = submit).grid(row=4,column=0)
Button(
ws,
text="Next Page", command=nextPage).grid(row = 5,column = 10)
query()
ws.mainloop
#OUTPUT
#('JOHN', '')
I am working on a project using Tkinter and sqlite. Even thou I wanted to print only the 1st item from the list, the whole list was outputted. I want to place the items into individual variables, but each time, the whole list gets stored into a variable. Any help would be appreciated.
I suppose the problem is the line records = c.fetchall(). fetchall() returns a list of tuples, where each tuple is a row from the database. So when you then print(records[0]), you're printing the entire first tuple.
To troubleshoot, try print(records), to print the entire list records, and see what that one looks like. You can then adjust the indexing of your print function to print only the exact stuff you wantt to print.
records = c.fetchall()
print(records[0])
The value stored into records is a list of tuples, so records[0] is a tuple.
In Python tuples are iterables, so that are indexed and are accessibles like lists:
print(records[0][0])

How can I get the value of a row in a column in SQLite 3 table with Tkinter Listbox widget?

I have Python program connected to SQLite 3 database with Tkinter on the frontend. My database table (subjectlist) consists of three columns: [id (unique interger), subject (text), serial (unique integer)]. Here is my program:
import sqlite3
from tkinter import *
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('SELECT COUNT() FROM subjectlist')
number = (c.fetchone()[0])
c.execute('SELECT * FROM subjectlist 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 serial", command=lambda: get_serial())
btn.pack()
mainloop()
Currently at runtime when I click item on listbox (witch basically shows all subject column values) and then press Tkinter button I get the subject I clicked. Instead I want to get serial corresponding to the subject. Notice that subject column may have same value on two or more different rows. How would I go about achieving this?
Here is just one more example; If I have this table:
I want the GUI to show first all of the subjects in the listbox. Then I click "Cats" (on the the id row 3) and then I click the button, I want the program to print me serial 4.
Well, this should also be easy. But since there is a database in your code that I can't currently test this with it, I made some assumptions. Try this out:
def get_letter():
conn = sqlite3.connect('database.db')
c = conn.cursor()
ids = listbox.curselection()[0]+1 # Getting the index number starting from 1
c.execute('SELECT * FROM subjectlist WHERE `id`=?;',(ids,)) # Searching the database for items with selected items index
rows = c.fetchall()
print(rows[0]) # Print the first and hopefully the only item in the list
conn.close() # Close the connection
This should print the rows which corresponds to the id, and since usually id is a unique number, it will only print out one row. I'm also assuming that you have both the database and the listbox in the same order or this might not work.
You can use the index of the item inside listbox to get the serial from data:
import sqlite3
from tkinter import *
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('SELECT * FROM subjectlist 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[1])
def get_serial():
selected = listbox.curselection()
if selected:
idx = selected[0]
print(data[idx][2]) # print serial of selected item
btn = Button(root, text="Show serial", command=get_serial)
btn.pack()
mainloop()
Note that you should make sure data and listbox are synchronised.

How to delete from Mysql Database an item selected in a Listbox Python Tkinter

i have made a database with 3 columns(id, name, price) and since i can't display all the columns in the Listbox i am displaying only the column "name", so i want to be able to delete an item in the database based on the name of the product i am clicking on the Listbox.
here is the code, i hope it helps:
import tkinter
from tkinter import *
import mysql.connector
root = Tk()
root.geometry('700x500')
con = mysql.connector.connect(user = '', password = '', host = '127.0.0.1', database = 'anime')
concursor = con.cursor()
concursor.execute('select * from prod')
query = concursor.fetchall()
l = Listbox(root)
for x,y,z in query:
l.insert(x+1, y)
l.pack(anchor='w')
#function to delete prod
def delp():
sel_items = l.curselection()
for item in sel_items:
concursor.execute("delete from prod where name = ('{}')".format(item))
con.commit()
button1 = Button(root, text = 'prod del', command = delp)
button1.pack(anchor='w')
root.mainloop()
and this is the database picture:
the python code works only if i replace "name" with "id" in the query in the "delp" function, however when i select the 1st item in the listbox, it deletes the 2nd item int the database, and i want to be able to delete based on the name.
so i figured it out, so heres the answer for ones whom are/will be looking for this.
first we wont need the curselection()
we need to get the active item or Anchor and "string it" and then use it in the query with format.
heres the code to make sense
def delp():
sel_items = l.get(ACTIVE)
string_item = str(sel_items)
for item in sel_items:
concursor.execute("delete from prod where name = ('{}')".format(string_item))
con.commit()
this code will delete the items in the database based on the name select in the listbox.

Create different entries each loop python tkinter

I created a function to create entry boxes (tkinter) but I want to be able to access the data in the entry boxes after. Therefore, I can't call all the boxes the same name e.g. Entry1=Entry(Solo) - I have to have Entry1, Entry2 etc...
I thought that I might be able to store the Entry Names in an array but it doesn't work. I can't just store the data in a list because when creating the entry boxes there is no data to store yet.
[Update] I tried to store an entry box in an list but it's not supported.
TypeError: 'set' object does not support item assignment
This is a snippet of code from my program (the code works without the lines with inputlist[i] on it):
StudentsArray1 = c.fetchall()
c.execute('SELECT Count(*) from students WHERE solo = 1;')
x = c.fetchone()[0]
a = 0
rownum = 1
inputlist = []
for i in range(0, x):
label1 = Label(Solo, text=StudentsArray1[a][0], font=font4, bg="white")
label1.grid(row=rownum, column=1)
label2 = Label(Solo, text=StudentsArray1[a][1], font=font4, bg="white")
label2.grid(row=rownum, column=2)
inputlist[i] = Entry(Solo)
inputlist[i].grid(row=rownum, column=2)
rownum = rownum + 1
a = a + 1

Python Tkinter: Delete label not working

I have a GUI that contains all the database records. Upon clicking the "search" button, I want all the records to be cleared from the screen, and the records relevant to the user's search to appear. I am trying to reference my labels and call the "destroy" method like this: a.destroy() but the program is not recognizing these labels as widgets.
class DBViewer:
def __init__(self, rows):
# Display all records
row_for_records = 2
for record in rows:
a = tkinter.Label(self.main_window, text=record[0])
a.grid(row=row_for_records, column=0)
b = tkinter.Label(self.main_window, text=record[1])
b.grid(row=row_for_records, column=1)
# More labels here
self.display_rows(rows)
tkinter.mainloop()
def display_rows(self, rows):
# Where I'm having trouble
def main():
global db
try:
dbname = 'books.db'
if os.path.exists(dbname):
db = sqlite3.connect(dbname)
cursor = db.cursor()
sql = 'SELECT * FROM BOOKS'
cursor.execute(sql)
rows = cursor.fetchall()
DBViewer(rows)
db.close()
Edit: Separated widget assignment and grid but still facing have the same problem. Anyone want to help out a programming newbie?
In order to delete something, you must have a reference to it. You aren't saving references to the widgets you are creating. Try saving them to a list or dictionary.
When creating them:
...
self.labels = []
for record in rows:
a = Tkinter.Label(...)
self.labels.append(a)
...
When you want to delete them:
for label in self.labels:
label.destroy()

Categories

Resources