I'm retrieving a large list of people from a database, then looping through each person to get their note/s and phone number/s. then displaying one person at a time with PySimpleGUI.
My issue is that it I'm doing multiple sql queries rather than just one (I don't know if this is an issue), and I have to repeatedly Finalize() and close() the screen, which creates a new window each time, rather than just refreshing the current page.
Am I able to refactor this so I don't have to close and create a new window each time?
Thank you.
# get all people
people = conn.execute('''SELECT * FROM people''')
people_tuple = people.fetchall()
# loop through all people
for index, person in enumerate(people_tuple):
# get persons notes
notes = conn.execute('''SELECT * FROM notes WHERE person_id = ?''', (person[0],))
notes_list = events.fetchall()
# get persons phone number/s
phone_numbers = conn.execute('''SELECT * FROM phone_numbers WHERE person_id = ?''', (person[0],))
# redacted #
window = main_window_layout(person, phone_num_list, notes_list).Finalize()
while True:
event, values = window.read()
# many if statements checking user input #
window.close()
def main_window_layout(person, phone_num_list, notes_list):
top_left_frame_1 = [[sg.Text("ID: " + str(person[0]), key='id', pad=(2,4))],
[sg.Text("Name: " + person[1] + " " + person[2], key='name', pad=(2,4))]]
frame_2 = [
[sg.Text(note[4], key='note_date', pad=(3, (12, 3))), sg.Text(note[6], key='note_info', pad=(3, (12, 3)))]
for note in reversed(notes_list)
]
Try to create the layout of the window, all elements with key to update the content later.
Demo code
import PySimpleGUI as sg
person = [
[1, 'Ronald', 'Reagan'],
[2, 'Abraham', 'Lincoln'],
[3, 'George', 'Washington'],
[4, 'Andrew', 'Jackson'],
[5, 'Thomas', 'Jefferson'],
[6, 'Harry', 'Truman'],
]
size, index = 10, 0
total = len(person)
keys = ['ID', 'First Name', 'Last Name']
layout = [
[sg.Text(key),
sg.Push(),
sg.Text(str(person[index][i]), size=size, background_color='blue', key=key)]
for i, key in enumerate(keys)] + [
#[sg.Button('< Prev'), sg.Push(), sg.Button('Next >')],
]
window = sg.Window('Title', layout)
while True:
event, values = window.read(timeout=500)
if event == sg.WIN_CLOSED:
break
elif event == sg.TIMEOUT_EVENT:
index = (index + 1) % total
for i, key in enumerate(keys):
window[key].update(value=str(person[index][i]))
""" button events to show previous/next record
elif event in ('< Prev', 'Next >'):
delta = -1 if event == '< Prev' else 1
index = (index + delta) % total
for i, key in enumerate(keys):
window[key].update(value=str(person[index][i]))
"""
window.close()
Related
Dears,
How to add password to Tab in order to open it's content ?
I want to keep Tab1(Mobiles) and Tab3 (Computers) accessible and the other ones request password each time we click on them :
Below is code for the my layout which has 4 Tabs, 2 of them are open :
import PySimpleGUI as sg
accessible = ['Mobiles','Computers']
layout = [[sg.TabGroup([[
sg.Tab('Mobiles', [[sg.Text(f'This is the Tab 1')]],key='Mobiles'),
sg.Tab('Tabelettes', [[sg.Text(f'This is the
Tab2')]],key='Tabelettes'),
sg.Tab('Computers',[[sg.Text(f'This is the
Tab3')]],key='Computers'),
sg.Tab('Televisions',[[sg.Text(f'This is the
Tab4')]],key='Televisions')]],selected_title_color='yellow',
key='TabGroup')]]
window = sg.Window('Tab Group', layout, finalize=True)
window['TabGroup'].bind('<Button-1>', ' Change', propagate=False)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == 'TabGroup Change':
e = window['TabGroup'].user_bind_event
if e.widget.identify(e.x, e.y) == 'label':
index = e.widget.index(f'#{e.x},{e.y}')
if index in accessible:
window[f'Tab {index}'].select()
else:
if sg.popup_get_text("Password") == '2022':
window[f'Tab {index}'].select()
window.close()
Thanks in advance
Just convert the index to the key of tab.
import PySimpleGUI as sg
tabs = ['Mobiles', 'Tabelettes', 'Computers', 'Televisions']
accessible = {'Mobiles','Computers'}
layout = [[sg.TabGroup([[sg.Tab(tab, [[sg.Text(f'This is the Tab {i+1}')]], key=tab) for i, tab in enumerate(tabs)]], selected_title_color='yellow', key='TabGroup')]]
window = sg.Window('Tab Group', layout, finalize=True)
window['TabGroup'].bind('<Button-1>', ' Change', propagate=False)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == 'TabGroup Change':
e = window['TabGroup'].user_bind_event
if e.widget.identify(e.x, e.y) == 'label':
index = e.widget.index(f'#{e.x},{e.y}')
tab = tabs[index]
if tab in accessible:
window[tab].select()
else:
if sg.popup_get_text("Password") == '2022':
accessible.add(tab)
window[tab].select()
window.close()
Working on some code that uses pysimplegui as the UI and SQlite for the data sorting. I'm using SQLite's execute function to select data based on input from the user in the UI through variables. For example user wants to search for part name they input all or part of the name into the box, hit the search button which then runs my "parts_search" method, which will then only filter the result based on part name. OR the user enters information in multiple boxes which then filters based on the boxes that have information.
This here is runnable code provided you add a file base1.db in the same folder location as the script itself
import PySimpleGUI as sg
import os.path
import sqlite3
# sql var
c = None
conn = None
setup = None
# list var
parts = []
def sql():
global setup
conn_sql()
c.execute("""CREATE TABLE IF NOT EXISTS parts (part_name TEXT, part_number TEXT, part_series TEXT,
part_size INTEGER, job_type TEXT)""")
conn.commit()
if conn:
conn.close()
def conn_sql():
global c
global conn
# SQL connection var
if os.path.isfile('./base1.db'):
conn = sqlite3.connect('base1.db')
c = conn.cursor()
def main_gui_parts():
global parts
layout = [[sg.Text('Part Name: '), sg.Input(size=(20, 1), key='-PName-'), sg.Text('Part Series:'),
sg.Input(size=(10, 1), key='-PSeries-')],
[sg.Text('Part Number:'), sg.Input(size=(20, 1), key='-PNumber-'), sg.Text('Part Size:'),
sg.Input(size=(10, 1), key='-PSize-')],
[sg.Checkbox('Fit', key='-PFit-'), sg.Checkbox('Weld', key='-PWeld-'),
sg.Checkbox('Assemble', key='-PAssemble-'),
sg.Button('Search', key='-PSearch-')],
[sg.Listbox(parts, size=(58, 10), key='-PParts-')], [sg.Button('Back', key='-PBack-')]]
window = sg.Window('parts list', layout, grab_anywhere=True)
sql()
while True:
event, values = window.read()
if event == 'Close' or event == sg.WIN_CLOSED:
break
# PART WINDOW
part_name = values['-PName-']
part_series = values['-PSeries-']
part_number = values['-PNumber-']
part_size = values['-PSize-']
fit = values['-PFit-']
weld = values['-PWeld-']
assemble = values['-PAssemble-']
if event == '-PSearch-':
print('search parts')
part_search(part_name, part_series, part_number, part_size, fit, weld, assemble)
if event == '-PBack-':
break
window.close()
def part_search(part_name, part_series, part_number, part_size, fit, weld, assemble):
global parts
conn_sql()
filter_original = """SELECT * FROM parts WHERE """
filter = filter_original
if part_name:
print('part name: ' + part_name)
if filter == filter_original:
filter += """part_name LIKE ? """
else:
filter += """AND part_name LIKE ? """
if part_series:
print('part series: ' + part_series)
if filter == filter_original:
filter += """part_series=(?) """
else:
filter += """AND part_series=(?) """
if part_number:
print('part number: ' + part_number)
if filter == filter_original:
filter += """part_number LIKE ? """ ### DONT USE LIKE???
else:
filter += """AND part_number LIKE ? """ ### DONT USE LIKE???
if part_size:
print('part size: ' + part_size)
if filter == filter_original:
filter += """part_size=(?) """
else:
filter += """AND part_size=(?) """
if fit:
print('job type: ' + str(fit))
if filter == filter_original:
filter += """job_type = fit """
else:
filter += """AND job_type = fit """
if weld:
print('job type: ' + str(weld))
if filter == filter_original:
filter += """job_type = weld """
else:
filter += """AND job_type = weld """
if assemble:
print('job type: ' + str(assemble))
if filter == filter_original:
filter += """job_type = assemble"""
else:
filter += """AND job_type = assemble"""
print(filter)
#if filter != filter_original:
#c.execute(filter, ())
#else:
#c.execute("""SELECT * FROM parts""")
main_gui_parts()
THE PROBLEM: The commented code at the bottom is where I'm having trouble figuring out (in the "part_search" method). I don't use all of the variables all the time. Only filter with the variables provided by the user. which means the tuple should only have the variables which was input by the user.
If all the variables were used this is what it would look like. c.execute(filter, (part_name, part_series, part_number, part_size, fit, weld, assemble)) but more often than not only some of those variable will have been used and may need to look like this instead. c.execute(filter, (part_name, part_series, weld)) Somehow I need the variables here to be removeable(for lack of better word)
I've been learning a lot about SQLite but I could be seeing tunnel vision and can't think of a different way to go about this.
Probably the easiest way to deal with this is to put all the filter conditions and values into lists, and then only add a WHERE clause if the length of the filters list is non-zero. For example:
query = """SELECT * FROM parts"""
filters = []
values = []
if part_name:
filters.append("""part_name LIKE ?""")
values.append(part_name)
...
if len(filters):
query += ' WHERE ' + ' AND '.join(filters)
c.execute(query, tuple(values))
Note: should your filters ever include OR conditions, you need to parenthesise them when building the query to ensure correct operation i.e.
query += ' WHERE (' + ') AND ('.join(filters) + ')'
I'm trying to create an easy form to quickly populate an excel file.
The columns in the final excel file are 'Number' (enter an ID number), 'Other Details'(to enter text if specific details need adding), then several columns that relate to attributes of the objects I'm trying to record, which each have several options.
For these latter columns I've seen that radio buttons in PySimpleGUI return True/False, when I'd like to just have the text of the radio buttons saved in a single column. How do I go about turning the True/False for each button into just the text related to the buttons?
Solution below:
import PySimpleGUI as sg
import pandas as pd
EXCEL_FILE = 'data_entry.xlsx'
df = pd.read_excel(EXCEL_FILE)
lst = ('English', 'Chinese', 'Japanese', 'Russian')
lst2 = ('English', 'Chinese', 'Japanese', 'Russian')
lst3 = ('English', 'Chinese', 'Japanese', 'Russian')
lst4 = ('English', 'Chinese', 'Japanese', 'Russian')
lst5 = ('English', 'Chinese', 'Japanese', 'Russian')
layout = [
[sg.Input('', key='INPUT 1')],
[sg.Radio(text, "Radio", enable_events=True, key=f"Radio {i}")
for i, text in enumerate(lst)],
[sg.Radio(text, "Radio2", enable_events=True, key=f"Radio2 {i}")
for i, text in enumerate(lst2)],
[sg.Radio(text, "Radio3", enable_events=True, key=f"Radio3 {i}")
for i, text in enumerate(lst3)],
[sg.Radio(text, "Radio4", enable_events=True, key=f"Radio4 {i}")
for i, text in enumerate(lst4)],
[sg.Radio(text, "Radio5", enable_events=True, key=f"Radio5 {i}")
for i, text in enumerate(lst5)],
[sg.Input('', key='INPUT 2')],
[sg.Push(), sg.Button("Go"), sg.Button('Exit')],
]
window = sg.Window("test", layout, finalize=True)
def clear_input():
for key in values:
window[key]('')
return None
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, 'Exit'):
break
elif event == 'Go':
"""
radio_value = window[event].TKIntVar.get()
col = radio_value % 1000 # count from 0
row = (radio_value - col) % 100000 # count from 0
container = radio_value // 100000 # count from 1
# print(container, row, col)
"""
radio_value = window['Radio 0'].TKIntVar.get()
text = lst[radio_value % 1000] if radio_value else None
radio_value2 = window['Radio2 0'].TKIntVar.get()
text2 = lst2[radio_value2 % 1000] if radio_value2 else None
radio_value3 = window['Radio3 0'].TKIntVar.get()
text3 = lst2[radio_value3 % 1000] if radio_value3 else None
radio_value4 = window['Radio4 0'].TKIntVar.get()
text4 = lst2[radio_value4 % 1000] if radio_value4 else None
radio_value5 = window['Radio5 0'].TKIntVar.get()
text5 = lst2[radio_value5 % 1000] if radio_value5 else None
record = [values['INPUT 1'], text, text2, text3, text4, text5, values['INPUT 2']]
print(record)
df = df.append(record, ignore_index=True)
df.to_excel(EXCEL_FILE, index=False)
sg.popup('Data saved!')
clear_input()
window.close()
You cannot get the text directly from event values for it is defined as an integer variable to store the value, but you can get it by element.Text.
To get the values of elements, you can get them from dictionary values. For lot of Radio elements, you can scan which radio with value True or find the code in following script to get the selected index.
import PySimpleGUI as sg
lst = ('English', 'Chinese', 'Japanese', 'Russian')
layout = [
[sg.Input('', key='INPUT 1')],
[sg.Radio(text, "Radio", enable_events=True, key=f"Radio {i}")
for i, text in enumerate(lst)],
[sg.Input('', key='INPUT 2')],
[sg.Push(), sg.Button("Go"), sg.Button('Exit')],
]
window = sg.Window("test", layout, finalize=True)
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, 'Exit'):
break
elif event.startswith("Radio"):
text = window[event].Text
print(text)
elif event == 'Go':
"""
radio_value = window[event].TKIntVar.get()
col = radio_value % 1000 # count from 0
row = (radio_value - col) % 100000 # count from 0
container = radio_value // 100000 # count from 1
# print(container, row, col)
"""
radio_value = window['Radio 0'].TKIntVar.get()
text = lst[radio_value % 1000] if radio_value else None
record = [values['INPUT 1'], text, values['INPUT 2']]
print(record)
window.close()
This so weird, like i am trying to use if statement and the selection in combobox to do some specific command and when combobox value is selected to 'full_name' (part of elif) they return an messagebox, that is supposed to be showed only when the first if statement is executed but according to the conditions its supposed to return the elif part but it returns the if part. Is there a mistake in my code? If the Q is unclear please try referring the code or lemme knw :) Thanks in advance.
CODE:
def sp_patient():
#Creating window
sp_pat = Toplevel(update)
sp_pat.title('Choose Patient')
def search():
#Assigning variable to .get()
a = drops.get()
if a == 'id' or 'emirate_id' or 'email_adress' or 'gender' or 'DOB' or 'blood_grp' or 'COVID_test':
#Establishing connection
con = mysql.connect(host='***', user='nihaalnz',
password='****', database='nihaalnztrying')
# Making SQL command
c = con.cursor()
c.execute(f"SELECT * FROM patient_infos where `{a}` = '{e_1.get()}'")
# Executing and saving SQL command
records = c.fetchall()
if records == []:
messagebox.showinfo('Does not exist!','Sorry such patient does not exist')
else:
#Creating window
result_win = Toplevel(sp_pat)
result_win.title('Search result')
index=0
for index,x in enumerate(records):
num=0
for y in x:
lookup_label = Label(result_win,text=y)
lookup_label.grid(row=index+1,column=num)
num += 1
#Closing connection
con.close()
#Creating column header and exit button
l_1 = Label(result_win,text='ID',font=font_text)
l_2 = Label(result_win,text='Full Name',font=font_text)
l_3 = Label(result_win,text='Phone no.',font=font_text)
l_4 = Label(result_win,text='Emirates ID',font=font_text)
l_5 = Label(result_win,text='Email addr.',font=font_text)
l_6 = Label(result_win,text='Gender',font=font_text)
l_7 = Label(result_win,text='DOB',font=font_text)
l_8 = Label(result_win,text='Nationality',font=font_text)
l_9 = Label(result_win,text='Blood group',font=font_text)
l_10 = Label(result_win,text='COVID test',font=font_text)
l_11 = Label(result_win,text='Emergency no.',font=font_text)
btn_ext = Button(result_win,text='Exit',font=font_text,command=result_win.destroy,borderwidth=2,fg='#eb4d4b')
#Placing it in screen
l_1.grid(row=0,column=0,padx=20)
l_2.grid(row=0,column=1,padx=20)
l_3.grid(row=0,column=2,padx=20)
l_4.grid(row=0,column=3,padx=20)
l_5.grid(row=0,column=4,padx=20)
l_6.grid(row=0,column=5,padx=20)
l_7.grid(row=0,column=6,padx=20)
l_8.grid(row=0,column=7,padx=20)
l_9.grid(row=0,column=8,padx=20)
l_10.grid(row=0,column=9,padx=20)
l_11.grid(row=0,column=10,padx=20)
btn_ext.grid(row=index+2,columnspan=11,ipadx=240,sticky=E+W)
elif a == 'full_name' or 'ph_no' or 'nationality' or 'emergency_no':
#Creating window
result_win = Toplevel(sp_pat)
result_win.title('Search result')
#Establishing connection
con = mysql.connect(host='****', user='nihaalnz',
password='*****', database='nihaalnztrying')
# Making SQL command
c = con.cursor()
c.execute(f"SELECT * FROM patient_infos where `{a}` regexp '{e_1.get()}'")
# Executing and saving SQL command
records = c.fetchall()
index=0
for index,x in enumerate(records):
num=0
for y in x:
lookup_label = Label(result_win,text=y)
lookup_label.grid(row=index+1,column=num)
num += 1
#Closing connection
con.close()
#Creating column headers and exit button
l_1 = Label(result_win,text='ID',font=font_text)
l_2 = Label(result_win,text='Full Name',font=font_text)
l_3 = Label(result_win,text='Phone no.',font=font_text)
l_4 = Label(result_win,text='Emirates ID',font=font_text)
l_5 = Label(result_win,text='Email addr.',font=font_text)
l_6 = Label(result_win,text='Gender',font=font_text)
l_7 = Label(result_win,text='DOB',font=font_text)
l_8 = Label(result_win,text='Nationality',font=font_text)
l_9 = Label(result_win,text='Blood group',font=font_text)
l_10 = Label(result_win,text='COVID test',font=font_text)
l_11 = Label(result_win,text='Emergency no.',font=font_text)
btn_ext = Button(result_win,text='Exit',font=font_text,command=result_win.destroy,borderwidth=2,fg='#eb4d4b')
#Placing it on screen
l_1.grid(row=0,column=0,padx=20)
l_2.grid(row=0,column=1,padx=20)
l_3.grid(row=0,column=2,padx=20)
l_4.grid(row=0,column=3,padx=20)
l_5.grid(row=0,column=4,padx=20)
l_6.grid(row=0,column=5,padx=20)
l_7.grid(row=0,column=6,padx=20)
l_8.grid(row=0,column=7,padx=20)
l_9.grid(row=0,column=8,padx=20)
l_10.grid(row=0,column=9,padx=20)
l_11.grid(row=0,column=10,padx=20)
btn_ext.grid(row=index+2,columnspan=11,ipadx=240,sticky=E+W)
elif a == 'Search by...':
#Error message
messagebox.showinfo('No choice given','Please choose a valid option to search by...')
#Defining dropdown and entry box
drops = ttk.Combobox(sp_pat,value=['Search by...','id','full_name','ph_no','emirate_id','email_addr','gender','DOB','nationality','blood_grp','COVID_test','emergency_no'],state='readonly')
print(drops.get())
drops.current(0)
e_1 = Entry(sp_pat)
#Defining Labels and search button
l_sch = Label(sp_pat,text='Search',font=Font(size='20'))
l_id = Label(sp_pat,text='Enter',font=font_text)
bt_db = Button(sp_pat,text='Search',command=search)
#Placing it in screen
drops.grid(row=1,columnspan=3,ipady=5,padx=5,pady=10)
e_1.grid(row=2,column=1,ipady=5,padx=5,pady=5)
l_id.grid(row=2,column=0,padx=5,pady=5)
bt_db.grid(row=3,columnspan=2,padx=5,pady=5,sticky=E+W)
l_sch.grid(row=0,columnspan=2,sticky=E+W,padx=10,pady=10)
The problem is this line:
if a == 'id' or 'emirate_id' or...
This statement always return True. It is evaluating whether a=="id" or emirate_id is True, and a non-empty string always returns True.
You can be explicit and use:
if a == 'id' or a == 'emirate_id' or ...
Or better yet, use keyword in:
if a in ("id", "emirate_id",...)
I've created a treewidget with children which contain tables. I'd like to acces the contents of the QtableWidget but I cannot find how to do this?
The treewidget looks like:
I've generated the treewidget like:
software = QTreeWidgetItem(['Software'])
hardware = QTreeWidgetItem(['Hardware'])
beide = QTreeWidgetItem(['Beide'])
andere = QTreeWidgetItem(['Andere'])
i = 0
for key, value in sorted(data.items()):
if value['Subtype'] == 'Software':
sub = software
if value['Subtype'] == 'Hardware':
sub = hardware
if value['Subtype'] == 'Beide':
sub = beide
if value['Subtype'] == 'Andere':
sub = andere
l1 = QTreeWidgetItem(sub)
if value['Privacy'] == 'Voorzichtig':
l1.setBackgroundColor(0, QColor('orange'))
if value['Privacy'] == 'Vertrouwelijk':
l1.setBackgroundColor(0, QColor('red'))
l1.setTextColor(0, QColor('white'))
l1.setText(0, value['sDesc'])
self.treeMainDisplay.addTopLevelItem(l1)
l1_child = QTreeWidgetItem(l1)
self.item_table = QTableWidget()
self.item_table.verticalHeader().setVisible(False)
self.item_table.horizontalHeader().setVisible(False)
self.item_table.setColumnCount(5)
self.item_table.setRowCount(5)
c1_item = QTableWidgetItem("%s" % value['sDesc'].encode('utf-8'))
self.item_table.setItem(0, 0, c1_item)
c2_item = QTableWidgetItem("%s" % value['Type'].encode('utf-8'))
self.item_table.setItem(1,0, c2_item)
qt_child = self.treeMainDisplay.setItemWidget(l1_child, 0, self.item_table)
self.treeMainDisplay.addTopLevelItem(software)
self.treeMainDisplay.addTopLevelItem(hardware)
self.treeMainDisplay.addTopLevelItem(beide)
self.treeMainDisplay.addTopLevelItem(andere)
I'm iterating over the treewidgetitems but don't know how to access the table contents:
def testItems(self):
iterator = QTreeWidgetItemIterator(self.treeMainDisplay)
while iterator.value():
item = iterator.value()
if not item.text(0):
#Get Table Object?
# item.item(0,0).text()
else:
print item.text(0)
iterator += 1
It seems I can't get acces to the QTableWidget object, I only get the QTreeWidgetItem object.
All feedback is highly appreciated!
The item widgets must be access via the tree-widget using the itemWidget method:
def testItems(self):
iterator = QTreeWidgetItemIterator(self.treeMainDisplay)
while iterator.value():
item = iterator.value()
if not item.text(0):
# Get Table Object
table = self.treeMainDisplay.itemWidget(item, 0)
else:
print item.text(0)
iterator += 1