Refresh labels when adding a new item - python

I'm trying to make a products' management app with tkinter and sqlite 3.
I want to show the products in labels. It works correctly, but I also want to delete every label when I add an item, and then recreate new labels. This way, the list updates when adding a new item.
Otherwise the user needs to restart the app to see the new item. Here's the code:
from tkinter import *
import sqlite3
# table name = items
conn = sqlite3.connect("productManagement.db")
cursor = conn.cursor()
itemsSearch = cursor.execute("SELECT rowid, * FROM items")
itemsFetch = itemsSearch.fetchall()
window = Tk()
window.geometry("800x600")
window.config(bg="#9BB7D4")
#FUNCTIONS
itemFrame = Frame(bg="#8a8a8a",width=200,height=200)
frameTitle = Label(itemFrame,text="Products:",bg="#8a8a8a",font=("Arial Black",12))
frameTitle.pack()
def createProduct():
global itemsFetch
name = nameEntry.get()
price = priceEntry.get()
quantity = quantityEntry.get()
number = numberEntry.get()
cursor.execute(f"INSERT INTO items VALUES ('{name}',{int(price)},{int(quantity)},
{int(number)})")
conn.commit()
itemsSearch = cursor.execute("SELECT rowid, * FROM items")
itemsFetch = itemsSearch.fetchall()
#the problem is here: i create new label for every item but the old ones doesn't
dissapear, i want to delete all the labels of the items existing and create new ones
showProducts()
def showProducts():
global itemStats
for item in itemsFetch:
itemStats = Label(itemFrame,bg="#8a8a8a",font=("Italic",12),
text=f"Name: {item[1]} Price: {int(item[2])}€ Quantity: {int(item[3])}
Item no: {int(item[4])}")
deleteBtn = Button(itemFrame,text="Delete")
itemStats.pack()
showProducts()
#GUI
title = Label(text="Product Managment System",font=("Arial Black",24),bg="#9BB7D4")
nameText = Label(text="Name:",bg="#9BB7D4",font=("Italic",12))
nameEntry = Entry(font=("Italic",12))
priceText = Label(text="Price:",bg="#9BB7D4",font=("Italic",12))
priceEntry = Entry(font=("Italic",12))
quantityText = Label(text="Quantity:",bg="#9BB7D4",font=("Italic",12))
quantityEntry = Entry(font=("Italic",12))
numberText = Label(text="Product Number:",bg="#9BB7D4",font=("Italic",12))
numberEntry = Entry(font=("Italic",12))
createProductBtn = Button(text="Create item",command=createProduct)
#PACKS
title.pack(pady=20)
nameText.place(x=140,y=140)
nameEntry.place(x=190,y=140)
priceText.place(x=340,y=140)
priceEntry.place(x=387,y=140)
quantityText.place(x=125,y=200)
quantityEntry.place(x=190,y=200)
numberText.place(x=340,y=200)
numberEntry.place(x=463,y=200)
createProductBtn.place(x=190,y=260)
itemFrame.place(x=190,y=300)
conn.commit()
window.mainloop()
conn.close()

Related

How to get the Values from the Entry box in Tkinter?

def in_Vals():
in_win = Tk()
in_win.title("Check In Details")
in_win.geometry("700x700")
in_win.resizable(0,0)
# title
title = Label(in_win,text="Check In Details",font=("Harlow Solid Italic",30,"italic"),fg="black",bg="#fbb08c")
title.pack(anchor="center",pady=5)
#creating label's
_Id_ = Label(in_win,text="Id :",font=("Times New Roman",15,"italic"),fg="black",bg="#fbb08c")
_Name_ = Label(in_win,text="Name :",font=("Times New Roman",15,"italic"),fg="black",bg="#fbb08c")
_Date_ = Label(in_win,text="Date :",font=("Times New Roman",15,"italic"),fg="black",bg="#fbb08c")
_Time_ = Label(in_win,text="Time :",font=("Times New Roman",15,"italic"),fg="black",bg="#fbb08c")
_Number_ = Label(in_win,text="Number :",font=("Times New Roman",15,"italic"),fg="black",bg="#fbb08c")
_Id_.pack(anchor='w',padx=10,pady=20)
_Name_.pack(anchor='w',padx=10,pady=20)
_Date_.pack(anchor='w',padx=10,pady=20)
_Time_.pack(anchor='w',padx=10,pady=20)
_Number_.pack(anchor='w',padx=10,pady=20)
# creating submit function
def submit():
print(f"{in_val_1}\n{in_val_2}\n{in_val_3}\n{in_val_4}\n{in_val_5}")
# creating entries
Id = Entry(in_win,width=25,font=("Courier",15,'bold'))
Name = Entry(in_win,width=25,font=("Courier",15,'bold'))
Date = Entry(in_win,width=25,font=("Courier",15,'bold'))
Time = Entry(in_win,width=25,font=("Courier",15,'bold'))
Number = Entry(in_win,width=25,font=("Courier",15,'bold'))
Id.place(x=100,y=87)
Name.place(x=100,y=157)
Date.place(x=100,y=227)
Time.place(x=100,y=293)
Number.place(x=100,y=360)
#getting values
in_val_1 = Id.get()
in_val_2 = Name.get()
in_val_3 = Date.get()
in_val_4 = Time.get()
in_val_5 = Number.get()
# creating submit button
submit = Button(in_win,text="Submit",font=("Wild Latin",15,"bold"),command=submit)
submit.place(x = 250,y=450)
in_win.config(bg="#fbb08c")
in_win.mainloop()
Here the function in_vals() is a coded to take data from the ID, Name, Date, Time, Number Entries and assign the values of The entries to the variables in_val_1 to in_val_5 ,to get the values from the entry box I have used the .get() Method. but when I try to Print the Variables that I assigned to the .get() method, it prints some white Space's.
The solution for the problem same as mine is
defining the values outside the the button function does not get anything.
here I have defined out side the button function
after defining it inside the button function it gives me the desired output

Got the AttributeError: 'FarmerClass' object has no attribute 'farmer_name' in the following code

I am trying to work around autocomplete dropdown combobox which works fine with database. but when i try to fetch data after updating database in runtime I got AttributeError: 'FarmerClass' object has no attribute 'farmer_name'. I tried other available solutions but still error is not solved. as of now, typo and syntax looks fine from the reference code which i was following.
the class which throws error
class FarmerClass(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.veg = []
self.farmer = []
self.buyers = []
self.fetch_data()
self.farmer_name = ttk.Combobox(self)
self.farmer_name['values'] = self.farmer
self.farmer_name.focus()
self.farmer_name.bind('<KeyRelease>', self.check_name)
self.farmer_name.bind('<<ComboboxSelected>>', self.get_data)
self.farmer_name.place(relx=0.028, rely=0.243, width=240, height=24)
self.product = ttk.Combobox(self )
self.product['values'] = self.veg
self.product.bind('<KeyRelease>', self.check_veg)
self.product.place(relx=0.028, rely=0.380,width=240, height=24)
self.buyer = ttk.Combobox(self )
self.buyer['values'] = self.buyers
self.buyer.bind('<KeyRelease>', self.check_buyer)
self.buyer.place(relx=0.028, rely=0.5237,width=240, height=24)
#======================= Entry btn ====================
self.entry_btn = tk.Button(self,Btn_base, text='Entry', command=self.entry_to_bill)
self.entry_btn.place(relx=0.481, rely=0.525,width=134, height=24)
def fetch_data(self, event=None):
cur.execute('SELECT * FROM vegetable ')
for i in cur.fetchall():
self.veg.append(i[0])
cur.execute('SELECT rowid, * FROM farmers ')
for i in cur.fetchall():
self.farmer.append(i[2])
cur.execute('SELECT rowid,name FROM buyers_avail ')
for i in cur.fetchall():
self.buyers.append(i[1])
self.farmer_name.configure(values= self.farmer) # getting error here
self.product.configure(values= self.veg)
self.buyer.configure(values= self.buyers)
def entry_to_bill(self, event=None):
name = self.buyer.get().lower()
cur.execute('SELECT name FROM buyers_avail WHERE name = ? ', [name])
bnames = cur.fetchall()
if bnames:
print(f'buyer {bnames} found')
else:
cur.execute('INSERT INTO buyers_avail (name) VALUES (?)',[name,])
db.commit()
self.buyer.delete(0, tk.END)
self.buyer.focus()
self.fetch_data()
if i try without those lines, farmer_name looks fine, product gets values of buyers and buyer dropdown goes empty.
please ask if anything required related to question.
The fetch_data function accesses farmer_name but you call it before defining farmer_name, which therefore doesn't exist at that point. You need to call fetch_data after defining farmer_name.

Insert data from a SQL query into a tkinter Entry field

I'm trying to put data from a database (SQLite3) into a set of entry fields in Tkinter.
My hope is that the data-snippets that exist in the database query will be put into the entries to show the user what info is in the db and give the choice to update empty fields.
I however have a hard time dealing with the returned None fields from the DB. None cannot be inserted into entries using .insert()
I've tried to sanitize the data first but since the different data are ints and text's I have not find a suitable replacement. I would also prefer the entries to be empty unless there is actual data to place there.
I've also tried to do an if statement before each line in the vendors_to_fields function but that did not work and seemed really messy.
Bonus question:
Is there a better way to insert values from a tuple into the different entries? I've been thinking about making 2 lists and using list comprehension but I could not solve it.
I hope I make sense, this has been a long coding session
Thank you for all input
My code:
def Order_window():
ord_win = Toplevel(root)
ord_win.title('Orders')
ord_win.geometry('800x600')
i = 0
# Functions
def controller():
vendor_list = list(vendors)
if i <= len(vendor_list):
vendor = vendor_list[i]
print(vendor)
data_from_db(vendor)
else:
vendor_name['text'] = 'All orders are done'
def data_from_db(vendor):
vendor_info_tuple = db.execute(
'SELECT * FROM vendors WHERE (vendor_id = ?)', [vendor])
vendor_info_tuple = vendor_info_tuple.fetchone()
connection.commit()
vendor_info = list(vendor_info_tuple)
if vendor_info[0] is None:
vendor_name['text'] == 'Vendor not in DB, better call Sal'
else:
print(vendor_info)
vendor_to_fields(vendor_info)
def vendor_to_fields(vendor_info):
for field in vendor_info:
if field is None:
vendor_info[field] = 0
print(vendor_info)
vendor_name['text'] = vendor_info[1]
vendor_min1.insert(0, vendor_info[5])
vendor_email.insert(0, vendor_info[2])
vendor_cc.insert(0, vendor_info[3])
vendor_message.insert(0, vendor_info[4])
def next_vendor():
pass
def update_db():
pass
# Layout order window
Label(ord_win, text='Vendor').grid(row=0)
Label(ord_win, text='Min order value').grid(row=1)
Label(ord_win, text='Email').grid(row=2)
Label(ord_win, text='CC').grid(row=3)
Label(ord_win, text='Message').grid(row=4)
vendor_name = Label(ord_win).grid(row=0, column=1)
vendor_min1 = Entry(ord_win)
vendor_min1.grid(row=1, column=1)
vendor_email = Entry(ord_win)
vendor_email.grid(row=2, column=1)
vendor_cc = Entry(ord_win)
vendor_cc.grid(row=3, column=1)
vendor_message = Entry(ord_win)
vendor_message.grid(row=4, column=1)
controller()

can't get my database to connect to my maths game

Basically I am trying to get my database to connect to my GUI and display a random question, however it is simply not working, any idea?      
SQL = 'SELECT * FROM tblQuestion'
cursor = Databaseconnector.SELECT(SQL)
rows = cursor.fetchall()
rows = random.choice(rows)
print rows.Question, rows.Hint, rows.A1, rows.A2, rows.A3, rows.A4, rows.CorrectAnswer
#def create_widgets(self):
#create welcome label
label1 = Tkinter.Label(self, text = (rows(1).Question))
label1.grid(row = 0, column = 1, columnspan = 2, sticky = 'W')
ERROR: TypeError: ‘pydodbc.Row’ object is not
rows is first a collection of pydodbc.Row objects, but then you alter it to be a single pydodbc.Row object by calling random.choice:
rows = cursor.fetchall() # rows is a list
rows = random.choice(rows) # now rows is a single object
Then you try to call that object using ():
label1 = Tkinter.Label(self, text = (rows(1).Question))
which fails with the error message you provided (partially):
ERROR: TypeError: ‘pydodbc.Row’ object is not callable
The best way to solve this to use a new variable for the single row:
rows = cursor.fetchall()
random_row = random.choice(rows)
...
label1 = Tkinter.Label(self, text = (random_row.Question))

Updating a Qtablewidget from contextmenu linedit-pyqt

I have a QTableWidget with which I would like to update from a QLinEdit embedded into a context menu. Now, in the QLinEdit a server name is entered, when the key is pressed the program scans MySQL database to see if the server name is in it, if it is, it updates the QTableWidgetwith the data from the server name table, if it is not found, it gives an error messageBox.
What I can not do is connect the context menu QLinEdit to update the QTableWidget.
connecting QTableWidget to context menu:
self.table1.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.table1.customContextMenuRequested.connect(self.handleHeaderMenu)
contextmenu:
def handleHeaderMenu(self, pos):
self.custom_choice = QtGui.QLineEdit()
self.menu = QtGui.QMenu()
self.custom_choice.setPlaceholderText("Server")
self.wac = QtGui.QWidgetAction(self.menu)
self.wac.setDefaultWidget(self.custom_choice)
self.menu.setStyleSheet("QMenu::item {background-color: #264F7D;color: white; font-weight:bold;}")
self.menu.addAction("Choose Server to Monitor:")
self.menu.addSeparator()
self.actionJuliet = self.menu.addAction('Juliet')
self.actionJulietleft = self.menu.addAction('JulietLeft')
self.actionPong = self.menu.addAction('Pong')
self.actionHulk = self.menu.addAction('Hulk')
self.actionCustom = self.menu.addAction(self.wac)
action = self.menu.exec_(QtGui.QCursor.pos())
self.connect(self.custom_choice, QtCore.SIGNAL("returnPressed()"),self.refreshdata)
Data fetcher/scanner:
def get_data(self):
self.tx = self.custom_choice.text()
self.model.execute("show TABLES;")
table_array = []
table_names = self.model.fetchall()
for lines in table_names:
lines = str(lines)
lines = lines.strip("()""''"",")
table_array.append(lines)
if any("%s" % self.tx in s for s in table_array):
table_name = self.tx
self.model.execute("""SELECT computer_name
FROM %s""" % (table_name))
new_user_name = self.model.fetchall()
print new_user_name,table_name
self.model.execute("""SELECT idle_time
FROM %s""" % (table_name))
new_idle = self.model.fetchall()
self.model.execute("""SELECT files_opened
FROM %s""" % (table_name))
new_files = self.model.fetchall()
self.model.execute("""SELECT active_time
FROM %s""" % (table_name))
new_active = self.model.fetchall()
self.model.execute("""SELECT session_type
FROM %s""" % (table_name))
new_session = self.model.fetchall()
self.model.execute("""SELECT cpu
FROM %s""" % (table_name))
new_cpu_load = self.model.fetchall()
self.model.execute("""SELECT avg_disk_queue
FROM %s""" % (table_name))
new_disk_queue_load = self.model.fetchall()
new_data_user = [item0[0] for item0 in new_user_name]
new_data_idle = [item1[0] for item1 in new_idle]
new_data_files = [item2[0] for item2 in new_files]
new_data_active = [item3[0] for item3 in new_active]
new_data_session = [item4[0] for item4 in new_session]
new_data_cpu_load = [item5[0] for item5 in new_cpu_load]
new_data_disk_queue_load = [item6[0] for item6 in new_disk_queue_load]
self.lista = new_data_user
self.listb = new_data_disk_queue_load
self.listc = new_data_cpu_load
self.listd = new_data_active
self.liste = new_data_files
self.listf = new_data_session
self.listg = new_data_idle
self.mystruct2 = {'A':self.lista, 'B':self.listb, 'C':self.listc,'E':self.liste,'D':self.listd,'F':self.listf,'G':self.listg}
The design of your handleHeaderMenu is a bit off. One of the main issues with the way it is currently structured is that you connect a signal to the QLineEdit after the popup menu has already finished. So you would miss that signal.
action = self.menu.exec_(QtGui.QCursor.pos())
self.connect(self.custom_choice,
QtCore.SIGNAL("returnPressed()"),
self.refreshdata)
QMenu.exec_() is a blocking call. It starts the event loop for the menu and waits for it to finish. Once it closes and returns the QAction that was selected, you then make a connection. I will get into a correction for this after my next point...
The menu you are building from scratch each time doesn't have to be saved to member attributes and used externally. There are two ways to go about doing a custom popup menu. If its primarily static, then you can build it once in your class init, or make it it's own class, and then just reuse the instance. Or in your case, you could build it up each time which is fine. But instead of relying on persistant references to the components of the menu and using a signal, why not just build it temporarily, and explicitly handle the results?
def handleHeaderMenu(self, pos):
menu = QtGui.QMenu()
menu.setStyleSheet("""
QMenu::item {
background-color: #264F7D;
color: white;
font-weight:bold;}
""")
text = menu.addAction("Choose Server to Monitor:")
text.setEnabled(False)
menu.addSeparator()
actionJuliet = menu.addAction('Juliet')
actionJulietleft = menu.addAction('JulietLeft')
actionPong = menu.addAction('Pong')
actionHulk = menu.addAction('Hulk')
wac = QtGui.QWidgetAction(menu)
custom_choice = QtGui.QLineEdit()
custom_choice.setPlaceholderText("Server")
wac.setDefaultWidget(custom_choice)
menu.addAction(wac)
menu.setActiveAction(wac)
custom_choice.returnPressed.connect(wac.trigger)
action = menu.exec_(QtGui.QCursor.pos())
if action:
if action == wac:
self.tx = str(custom_choice.text()).strip()
else:
self.tx = str(action.text())
self.refreshdata()
def refreshdata(self):
print self.tx
Here we just create a bunch of temp widgets for the menu that will get garbage collected. After showing the menu, we check the returned action and then manually set our table attribute, and call refresh. Also, we needed to set the signal from the custom QLineEdit to trigger its widget action internally.
Lastly, is it really necessary to do 8 sql queries and a whole bunch of data reorganizing every time you want to load this data? This could be highly simplified:
def get_data(self):
table_check = """
SELECT table_name FROM information_schema.tables
WHERE table_schema = %s AND table_name = %s
"""
table_name = self.tx
count = self.model.execute(table_check, (self.theDatabaseName, table_name))
if not count:
# warn the user that the table name does not exist
warn_user_of_bad_table()
return
sql = """
SELECT
computer_name, idle_time, files_opened,
active_time, session_type, cpu, avg_disk_queue
FROM %s
""" % table_name
count = self.model.execute(sql)
if not count:
warn_database_error()
return
results = self.model.fetchall()
user, idle , files, active, session, cpu, disk = zip(*results)
self.lista = user
self.listb = disk
self.listc = cpu
self.listd = active
self.liste = files
self.listf = session
self.listg = idle
self.mystruct2 = {
'A' : self.lista,
'B' : self.listb,
'C' : self.listc,
'E' : self.liste,
'D' : self.listd,
'F' : self.listf,
'G' : self.listg
}
You only need two queries here. The first really simple one to check if the table exists, by using the scheme, instead of parsing through a big SHOW TABLES output. And the second which gets all your data in one query (as a bunch of rows, and then uses zip to regroup them into columns.

Categories