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
Related
I'm working on a tkinter database program for landscape architects to assist with selecting plants.
I have a search function which retrieves some entries with a for loop based on some user inputs, namely checkboxes for things like sun or shade (these variables are stored in search_current).
I'm trying to make delete buttons appear next to database entries, but I cannot make the button actually delete the corresponding entry. Each button will just delete the entry for the last result in the loop.
I know the problem is my delete function is being redefined in each iteration to the latest value in the loop, but I'm not sure how to approach the problem.
Here's the code.
def search():
for widgets in result_frame.winfo_children():
widgets.destroy()
conn = sqlite3.connect('plant_records.db')
c = conn.cursor()
c.execute("SELECT *, oid FROM plants")
records = c.fetchall()
for record in records:
countVar = 0
for i in search_current:
if record[i] == 1:
countVar += 1
if countVar == len(search_current):
result = tk.Frame(result_frame, bg='white', highlightbackground="Azure2", highlightthickness=1,
height=25, width=500)
result.pack()
result.grid_propagate(False)
result_name = tk.Label(result, bg='white', text=record[0])
result_name.grid(row=0, column=0)
del_button = tk.Label(result, text="Delete", bg="White", fg='Blue', cursor="hand2")
del_button.bind("<Button-1>", lambda del_button=del_button: delete())
del_button.grid(row=0, column=1)
n = record[-1]
def delete():
b = str(n)
conn = sqlite3.connect('plant_records.db')
c = conn.cursor()
c.execute('DELETE FROM plants WHERE oid = ' + b)
conn.commit()
conn.close()
conn.commit()
conn.close()
Please help, I'm quite new to programming and I've been stuck on this one for about a week, I've been reading through similar questions and answers and I can't get my head around it.
Without really understanding it, I've been trying to appropriate the solutions for my purpose, and that hasn't worked out.
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.
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()
i use python 3, tkinter and mysql connector.
I want to make an optionMenu object with my sql data i tried to do like that :
mongroupe3 = LabelFrame(app, text='nouvelle div 3').pack()
Label(mongroupe3, text='groupe3').pack()
select_Classes = ("select id,nom from classe")
cursor.execute(select_Classes)
result = cursor.fetchall()
for row in result:
id = row[0]
nom = row[1]
mongroupe3 = Label(app, text=nom).pack()
v = StringVar()
v.set(nom)
om = OptionMenu(mongroupe3, v, nom)
om.pack()
the code has to show a dropdown menu with a list of the "nom" on my "classe" table but my option menu is in my for loop and is executed as many time as i have records in my classe table .
for exemple if i have 3 record i got 3 option menu with 3 different value.
o tried to put my optionMenu out of my for loop like that :
mongroupe3 = LabelFrame(app, text='nouvelle div 3').pack()
Label(mongroupe3, text='groupe3').pack()
select_Classes = ("select id,nom from classe")
cursor.execute(select_Classes)
result = cursor.fetchall()
for row in result:
id = row[0]
nom = row[1]
mongroupe3 = Label(app, text=nom).pack()
v = StringVar()
v.set(nom)
om = OptionMenu(mongroupe3, v, nom)
om.pack()
but i got only the last record i inserted on my table.
i cant put my for loop inside my OptionMenu cause of the following shema OptionMenu(parent, default variable, var)
You got what you did not expect for this reason:
You create only one label and you override it in each iteration (the same about the class variable v). So by the end, it is logic you get only one row (because, again, you have only one label widget).
Apart from this, you have to care about the widgets and where you place them: for example, I believe mongroup3 must be the parent widget of the row you want to create, unlike what you did.
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()