Python Forum
PySimpleGUI Bugging out
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
PySimpleGUI Bugging out
#1
Hello,

Please see complete code below. The issue is, when you load the program, you can go to the "Open Requests" tab and it works, however if you go onto any other tab, and then click on the "Open Requests" tab, it crashes. This is the same when you go from the "Open Requests" tab, back into it.

The code should make it reset but there is no error message, the program just stops responding. I'm aware there is a lot of code (At least from my point of view), but i thought it best to include the whole thing.

Everything else works, so I believe it is an issue in the last function, which works the "Open Requests" tab.

import PySimpleGUI as sg
import csv
from csv import reader
import sqlite3
sg.theme("DarkAmber")
entry = []
equipm = []
a = ""
ti = []
t = [810,390]
p = ("")
xy = "NA"
yz = "NA"
zx = "NA"
admins = [["Admin","Administrator"],["Admin","OneTwoTree"]]
con = sqlite3.connect(r'equipment.db') # FIGURE OUT HOW TO ACCESS SHARED DRIVE !#
cur = con.cursor()
def startup():        
    for row in cur.execute('SELECT * FROM user_equipment'):
        entry.append(row)
    login()
def login():
    global b
    layout0 = [[sg.T("")],[sg.T("Admin Login",font=("arial,15"))],[sg.T("Username")],[sg.InputText(key = "usr")],[sg.T("Password")],[sg.InputText(key = "pwd")],[sg.Button("OK", bind_return_key = True)],[sg.T("")],[sg.T("")],[sg.B("Guest Login")]]
    window0 = sg.Window("IT Portal", layout0, location=(t[0],t[1]), size = (600,500),finalize = True)
    event,values = window0.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            break
        if event == "OK":
            u = window0.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            b = str(values['usr'])
            c = str(values['pwd'])
            if b in admins[0] and c in admins[1]:
                window0.close()
                main()                
                break
            if b not in admins or c not in admins:
                sg.popup('Invalid Login.','Please try again.', location = (t[0],t[1]))
                window0.close()
                login()
                break
        if event == "Guest Login":
            u = window0.CurrentLocation()
            window0.close()
            t.append(u[0])
            t.append(u[1])
            guestmain()
            break
#########################################################################GUEST SECTION#########################################################################
def guestmain():
    layout10 = [[sg.T("")],[sg.B("Request Equipment"),sg.B("Raise Ticket")]]
    window10 = sg.Window("Guest Portal", layout10,location = (t[0],t[1]), size = (600,500),finalize = True)
    event, values = window10.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            con.close()
            break
        if event == "Request Equipment":
            u = window10.CurrentLocation()
            window10.close()
            t.append(u[0])
            t.append(u[1])
            equipreq()
            break
        if event == "Raise Ticket":
            u = window10.CurrentLocation()
            window10.close()
            t.append(u[0])
            t.append(u[1])
            newticket()
            break
def newticket():
    layout11 = [[sg.T("")],[sg.B("Request Equipment"),sg.B("Raise Ticket")],[sg.T("")],[sg.T("Topic:"),sg.T("                    "),sg.T("Issue Description:")],[sg.Combo(values = ("Office Products","Other"),key = "D"),sg.Multiline(size = (45,5),key = "E")],
                [sg.T("Email Address:")],[sg.InputText(key="F")],[sg.T("")],[sg.T("")],[sg.B("Submit Ticket"),sg.T("Please include as much information as you can.")]]
    window11 = sg.Window("Guest Portal",layout11,location=(t[0],t[1]),size=(600,500), finalize = True)
    event,values = window11.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            con.close()
            break
        if event == "Request Equipment":
            u = window11.CurrentLocation()
            window11.close()
            t.append(u[0])
            t.append(u[1])
            equipreq()
            break
        if event == "Raise Ticket":
            u = window11.CurrentLocation()
            window11.close()
            t.append(u[0])
            t.append(u[1])
            newticket()
            break
        if event == "Submit Ticket":
            x = values["D"]
            y = values["E"]
            z = values["F"]
            ti = []
            for row in cur.execute('select * from tickets'):
                ti.append(row)
            cur.execute('INSERT INTO tickets values('+ str(len(ti)+1) +',"'+ str(x) + '","' + str(y[:-1])+ '",' + "false" + ',"' + str(z) + '")')
            con.commit()
            u = window11.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window11.close()
            newticket()
            break
def equipreq():
    layout12 = [[sg.T("")],[sg.B("Request Equipment"),sg.B("Raise Ticket")],[sg.T("")],[sg.T("Name:")],[sg.InputText(key="G")],[sg.T("")],[sg.T("Equipment Type:")],[sg.Combo(values = ("Monitor","Screen","Mobile","Desktop","Laptop","Mouse/Keyboard","Other"),key="H")],[sg.T("If you selected 'Other' please specify in the box below.")],[sg.T("Please say why you need the equipment:")],[sg.Multiline(size=(45,5),key="I")],[sg.T("")],[sg.T("")],[sg.B("Submit")]]
    window12 = sg.Window("Guest Portal", layout12,location = (t[0],t[1]), size = (600,500), finalize = True)
    event,values = window12.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            con.close()
            break
        if event == "Request Equipment":
            u = window12.CurrentLocation()
            window12.close()
            t.append(u[0])
            t.append(u[1])
            equipreq()
            break
        if event == "Raise Ticket":
            u = window12.CurrentLocation()
            window12.close()
            t.append(u[0])
            t.append(u[1])
            newticket()
            break
        if event == "Submit":
            x = values["G"]
            y = values["H"]
            z = values["I"]
            ti = []
            for row in cur.execute('select * from equip_request'):
                ti.append(row)
            cur.execute('INSERT INTO equip_request values('+ str(len(ti)+1) + ',"' + str(x) + '","' + str(y) + '","' + str(z[:-1])+'")')
            con.commit()
            u = window12.CurrentLocation()
            window12.close()
            t.append(u[0])
            t.append(u[1])
            equipreq()
            break
#########################################################################END OF GUEST SECTION#########################################################################
#########################################################################ADMIN SECTION#########################################################################
def main():
    layout1 = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")]]
    window1 = sg.Window("IT Admin Portal", layout1,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window1.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            con.close()
            break
        if event == "User List":
            u = window1.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window1.close()
            user_list()
            break
        if event == "View Logged Equipment":            
            u = window1.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window1.close()
            out_equipment()
            break
        if event == "Log Equipment Out":
            u = window1.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window1.close()
            new_entry()
            break
        if event == "Open Tickets":
            u = window1.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window1.close()
            tickets()
            break
        if event == "Open Requests":
            u = window1.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window1.close()
            xy = "NA"
            yz = "NA"
            zx = "NA"
            requestlist()
            break
def user_list():
    entry.clear()
    for row in cur.execute('select * from user_equipment'):
            entry.append(row)
    user = []
    user.append(entry[0][1])
    x = 0
    global a
    for x in range(len(entry)):        
        if entry[x][1] not in user:
            user.append(entry[x][1])
            x += 1  
        x += 1        
    user_list1 = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T("")],
                        [sg.Listbox(values=user,size = (30,10),key = "userid")],[sg.Button("Select", bind_return_key = True)]]
    window2 = sg.Window("IT Admin Portal - User List", user_list1,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window2.read()
    t.clear()
    while True:
            if event == sg.WIN_CLOSED:
                con.close()
                break
            if event == "User List":
                u = window2.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window2.close()
                user_list()
                break
            if event == "View Logged Equipment":            
                u = window2.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window2.close()
                out_equipment()
                break
            if event == "Open Tickets":            
                u = window2.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window2.close()
                tickets()
                break
            if event == "Log Equipment Out":
                u = window2.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window2.close()
                new_entry()
                break
            if event == "Select":
                a = str(values['userid'])
                u = window2.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window2.close()
                user_equip()
                break
            if event == "Open requests":
                u = window2.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window2.close()
                xy = "NA"
                yz = "NA"
                zx = "NA"
                requestlist()
                break
def user_equip():
    equip = []
    serial = []
    x = 0
    entry.clear()
    for row in cur.execute('select * from user_equipment'):
            entry.append(row)
    global a
    for x in range(len(entry)):
        if a[2:5] in entry[x][1]:
            equip.append(entry[x][2])
            serial.append(entry[x][3])
            x += 1    
    user_list2 = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T(a)],[sg.T("Type"),sg.T("           "),sg.T("Serial")],
                    [sg.Listbox(values=equip,size = (10,10),key = "user_equip"),sg.Listbox(values=serial,size=(33,10),key = "D")],[sg.T("")],[sg.T("")],[sg.T("An equipment return form must be filled out, scanned and saved.")],[sg.T("Select the serial number of the returned item.")],[sg.Button("Return")]]
    window3 = sg.Window("IT Admin Portal - User Details", user_list2,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window3.read()
    t.clear()
    while True:
            if event == sg.WIN_CLOSED:
                con.close()
                break
            if event == "User List":
                u = window3.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window3.close() 
                user_list()
                break
            if event == "View Logged Equipment":    
                u = window3.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window3.close()
                out_equipment()
                break
            if event == "Log Equipment Out":
                u = window3.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window3.close()
                new_entry()
                break
            if event == "Open Tickets":
                u = window3.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window3.close()
                tickets()
                break
            if event == "Return":
                entry.clear()
                for row in cur.execute('select * from user_equipment'):
                        entry.append(row)
                z = str(values["D"])  
                u = window3.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                for y in range(len(entry)):
                    if z[2:-2] == entry[y][3]:
                        cur.execute('delete from user_equipment where serial="'+str(entry[y][3])+'";')                  
                        con.commit()
                window3.close()
                entry.clear()
                login()                
                break
            if event == "Open requests":
                u = window3.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window3.close()
                xy = "NA"
                yz = "NA"
                zx = "NA"
                requestlist()
                break
                
def new_entry():
    new_ntr = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T("")],
                    [sg.T("Name")],[sg.InputText(key = "A")],[sg.T("Equipment Type")],[sg.Combo(values = ("Monitor","Desktop","Laptop","Mobile"),size=(15,15),key = "B")],[sg.T("Serial")],[sg.InputText(key = "C")],[sg.T("")],[sg.T("")],
               [sg.T("")],[sg.T("An issue form must also be filled out, scanned, and saved.")],[sg.Button("Save", bind_return_key = True)]]
    window5 = sg.Window("IT Admin Portal - Log Equipment Out", new_ntr,location = (t[0],t[1]), size = (600,500), finalize = True)
    event, values = window5.read()
    t.clear()
    while True:
            if event == sg.WIN_CLOSED:
                con.close()
                break
            if event == "User List":
                u = window5.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window5.close()
                user_list()
                break
            if event == "View Logged Equipment":            
                u = window5.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window5.close()
                out_equipment()
                break
            if event == "Log Equipment Out":
                u = window5.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window5.close()
                new_entry()
                break
            if event == "Open Tickets":
                u = window5.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window5.close()
                tickets()
                break
            if event == "Save":
                entry.clear()
                for row in cur.execute('select * from user_equipment'):
                        entry.append(row)
                x = values["A"]
                y = values["B"]
                z = values["C"]
                a = int(len(entry)+1)
                cur.execute('insert into user_equipment values('+ str(a) + ',"' + x + '","' + y + '","' + z + '");')
                con.commit()
                entry.clear()
                u = window5.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window5.close()
                startup()
                break
            if event == "Open requests":
                u = window5.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window5.close()
                xy = "NA"
                yz = "NA"
                zx = "NA"
                requestlist()
                break
def out_equipment():
    entry.clear()
    for row in cur.execute('select * from user_equipment'):
        entry.append(row)
    mob = 0
    des = 0
    lap = 0
    mon = 0
    global p
    global equipm
    equip = []
    for x in range(len(entry)):
        if "Mon" in entry[x][2]:
            mon += 1
        if "Des" in entry[x][2]:
            des += 1
        if "Lap" in entry[x][2]:
            lap += 1
        if "Mob" in entry[x][2]:
            mob += 1    
    out_equip = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T("")],
                   [sg.T("Monitors"),sg.T("       "),sg.T("Desktops"),sg.T("       "),sg.T("Laptops"),sg.T("       "),sg.T("Mobiles")],
                 [sg.T("     " +str(mon)+ "         "),sg.T("             " +str(des)+ "           "),sg.T("          " +str(lap)+ "   "),sg.T("                  " +str(mob))],[sg.T("")],[sg.T("")],[sg.T("")],[sg.T("")],
                 [sg.Combo(values = ("Monitor","Desktop","Laptop","Mobile"),default_value=("Filter by"),key = "filterby"),sg.T(p)],[sg.Button("Filter"),sg.Listbox(values = equipm, size = (35,10))]]
    window4 = sg.Window("IT Admin Portal - View Logged Equipment", out_equip,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window4.read()
    t.clear()
    while True:
            if event == sg.WIN_CLOSED:
                con.close()
                break
            if event == "User List":
                u = window4.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window4.close()
                user_list()
                break
            if event == "View Logged Equipment":
                u = window4.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window4.close()
                out_equipment()
                break
            if event == "Log Equipment Out":
                u = window4.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window4.close()
                new_entry()
                break
            if event == "Filter":
                equipm = []
                z = values["filterby"]
                p = values["filterby"]
                for x in range(len(entry)):
                    if z in entry[x]:
                        equipm.append(entry[x][1])
                        equipm.append(entry[x][3])
                    x += 1
                u = window4.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window4.close()
                out_equipment()
                break
            if event == "Open Tickets":
                u = window4.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window4.close()
                tickets()
                break
            if event == "Open requests":
                u = window4.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window4.close()
                xy = "NA"
                yz = "NA"
                zx = "NA"
                requestlist()
                break
def tickets():
    global ti
    ti = []
    for row in cur.execute('select * from tickets where open_close = false'):
        ti.append(row)
    layout12 = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T("")],[sg.Listbox(values = ti, size = (60,10),key="J"),sg.B("Select")]]
    window12 = sg.Window("IT Admin Portal - Open Tickets", layout12,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window12.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            con.close()
            break
        if event == "Open Tickets":
                u = window12.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window12.close()
                tickets()
                break
        if event == "User List":
                u = window12.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window12.close()
                user_list()
                break
        if event == "View Logged Equipment":
                u = window12.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window12.close()
                out_equipment()
                break
        if event == "Log Equipment Out":
                u = window12.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window12.close()
                new_entry()
                break
        if event == "Select":
                u = window12.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                ti.clear()
                ti = values["J"]
                if len(ti) < 1:
                    sg.popup("Invalid Selection","Please select a ticket",location = (t[0],t[1]))
                    tickets()
                window12.close()
                selection()
                break
        if event == "Open requests":
                u = window12.CurrentLocation()
                t.append(u[0])
                t.append(u[1])
                window12.close()
                xy = "NA"
                yz = "NA"
                zz = "NA"
                requestlist()
                break
def selection():
    global ti
    layout13 = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T("")],[sg.T("ID:      "),sg.T(ti[0][0])],[sg.T("Topic: "),sg.T(ti[0][1])],[sg.T("Issue: "),sg.T(ti[0][2])],[sg.T("Name: "),sg.T(ti[0][4])],[sg.B("Clear")]]
    window13 = sg.Window("IT Admin portal - View Ticket", layout13,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window13.read()
    t.clear()
    while True:
        if event == sg.WIN_CLOSED:
            con.close()
            break
        if event == "Open Tickets":
            u = window13.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window13.close()
            tickets()
            break
        if event == "User List":
            u = window13.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window13.close()
            user_list()
            break
        if event == "View Logged Equipment":
            u = window13.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window13.close()
            out_equipment()
            break
        if event == "Log Equipment Out":
            u = window13.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window13.close()
            new_entry()
            break
        if event == "Clear":
            u = window13.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window13.close()
            cur.execute('update tickets set open_close = true where id = '+str(ti[0][0])+';')
            con.commit()
            ti.clear()
            tickets()
            break
        if event == "Open requests":
            u = window13.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window13.close()
            xy = "NA"
            yz = "NA"
            zx = "NA"
            requestlist()
            break
def requestlist():
    req = []
    requ = []
    global xy
    global yz
    global zx
    for row in cur.execute('select * from equip_request;'):
        req.append(list(row))
    if len(req) > 0:
        for row in range(len(req)):
            requ.append(str(req[row][1]))
    layout14 = [[sg.T("")],[sg.Button("View Logged Equipment"),sg.Button("User List"),sg.Button("Log Equipment Out"),sg.B("Open Tickets"),sg.B("Open Requests")],[sg.T("")],[sg.T("")],[sg.T("Requests for equipment:")],[sg.Listbox(values = (requ),size = (15,10),key = "K"),sg.B("Details")],[sg.T("Details: ")],[sg.T("Name: "+str(xy))],[sg.T("Equipment Requested: "+str(yz))],[sg.T("Reason: "),sg.Multiline(default_text=str(zx))]]
    window14 = sg.Window("IT Admin Portal - View Open Requests", layout14,location=(t[0],t[1]), size = (600,500), finalize = True)
    event, values = window14.read()
    t.clear()
    xy = "NA"
    yz = "NA"
    zx = "NA"
    while True:
        if event == sg.WIN_CLOSED:
            break
        if event == "Details":
            q = str(values["K"])
            for f in range(len(req)):
                if q[2:-2] in req[f]:
                    xy = str(req[f][1])
                    yz = str(req[f][2])
                    zx = str(req[f][3])
            u = window14.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window14.close()
            requestlist()
            break
        if event == "Open Tickets":
            u = window14.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window14.close()
            tickets()
            break
        if event == "User List":
            u = window14.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window14.close()
            user_list()
            break
        if event == "View Logged Equipment":
            u = window14.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window14.close()
            out_equipment()
            break
        if event == "Log Equipment Out":
            u = window14.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window14.close()
            new_entry()
            break
        if event == "Open requests":
            u = window14.CurrentLocation()
            t.append(u[0])
            t.append(u[1])
            window14.close()
            xy = "NA"
            yz = "NA"
            zx = "NA"
            requestlist()
            break
#########################################################################END OF ADMIN SECTION#########################################################################

startup()
while dad_has_cigs == True:
    happiness = True
    if dad_has_cigs == False:
    print("Dad come home!")
    happiness = not happiness
    break
Reply
#2
You put window.read() in the wrong place. It needs to be placed inside the while True: loop. Your code can only process one event per window. That is why you have to keep having to redraw the window all the time. The way you are processing events is probably why your program crashes. It is not worth your time trying to figure out this particular bug because there are so many things being done incorrectly that can all be traced back to that one fundamental mistake.

There is a PySimpleGUI cookbook that you should read. It will help you redesign your program. And you need to redesign your program.

Be happy. You won't have to remember and restore window positions anymore!
Reply
#3
(Sep-22-2021, 05:26 PM)deanhystad Wrote: You put window.read() in the wrong place. It needs to be placed inside the while True: loop. Your code can only process one event per window. That is why you have to keep having to redraw the window all the time. The way you are processing events is probably why your program crashes. It is not worth your time trying to figure out this particular bug because there are so many things being done incorrectly that can all be traced back to that one fundamental mistake.

There is a PySimpleGUI cookbook that you should read. It will help you redesign your program. And you need to redesign your program.

Be happy. You won't have to remember and restore window positions anymore!

Hello,

I figured out it was crashing because the event call had one letter in a different case, so there was no code for the event to run. Works fine now.

Thanks,
James
while dad_has_cigs == True:
    happiness = True
    if dad_has_cigs == False:
    print("Dad come home!")
    happiness = not happiness
    break
Reply
#4
I played around with your code. It is an, um, er, interesting approach. I would never have come up with the idea of destroying and re-creating windows just to update the widgets. The top row of buttons is also an unusual way to present different views.

Here are some ideas you may find interesting. I modified the code to remove recursion.

Recursion is when a function calls itself, either directly or indirectly through other functions. Your code has a lot of recursion. Functions call themselves to update the window or call functions to draw other windows that may in turn call the original function. This is a bad thing because it eats up memory. It is so bad that Python places an upper limit on how many levels of function calls are allowed. If you program reaches that limit, an exception is thrown.

To remove the recursion I rewrote the code to return control to a window switcher which calls the function to draw the next window. Instead of login() calling main(), login() now sets a variable and returns. The window switcher.
switch_window(login)  # Start with login window
while next_window:
    next_window() # execute function to draw next window
To switch from the current window to a new window, the window event loop assigns "next_window" to be the function that draws the next window, then the current window exits its event loop and lets control return to the window switcher loop. It uses a couple of convenience functions to help with this.
def switch_window(window_func):
    '''Close current window and set function to open new window'''
    global next_window, window_open
    next_window = window_func
    window_open = False

def show_window(title, layout):
    '''Create new window using layout.  Position window in same location as current window'''
    global window, window_open
    if window:
        window.close()
    window = sg.Window(title, layout, size=(600, 500), enable_close_attempted_event=True, location=sg.user_settings_get_entry('-WINDOW_LOCATION-', (None, None)))
    window_open = True
switch_window() sets the next_window function variable and sets window_open to False, causing the event loop to exit. show_window() draws the new window.

I changed the way window location was saved and restored. I have the window send an event if you click on the close window decoration. In the event handler I capture that event, save the window location, and close the window. I save the window location in a PySimpleGUI user setting named '-WINDOW_LOCATION-', and when the new window is drawn it uses the user setting to set the location of the new window.

I rewrote the login window to allow multiple login attempts without having to redraw the window. If the user enters in invalid username or password it clears the inputs, displays a message in a popup, and sets focus back to the user input.

Clearing the inputs is easy. You can set a flag to automatically clear an input when it is read, and I did that in the layout
    layout = [
        [sg.T("Username")],
        [sg.InputText(key = "-USER-", do_not_clear=False)],
        [sg.T("Password")],
        [sg.InputText(key = "-PASSWORD-", do_not_clear=False)],
        [sg.Button("OK", bind_return_key=True, key="-OK-")],
    ]
Setting the focus back to the user input was a bit trickier. I had to call the set_focus() method for the user input.
                window['-USER-'].set_focus()  Give keyboard focus to the user input widget
The entire program:
import PySimpleGUI as sg

accounts = {"Admin":"Administrator", "User":"OneTwoThree"}  # use database or dictionary for passwords. Easier to use than lists of lists.
window = None  # Variables used by the window switcher
window_open = False
next_window = None

def switch_window(window_func):
    '''Close current window and set function to open new window'''
    global next_window, window_open
    next_window = window_func
    window_open = False

def show_window(title, layout):
    '''Create new window using layout.  Position window in same location as current window'''
    global window, window_open
    if window:
        window.close()
    window = sg.Window(title, layout, size=(600, 500), enable_close_attempted_event=True, location=sg.user_settings_get_entry('-WINDOW_LOCATION-', (None, None)))
    window_open = True

def main_window_menu(event, values):
    '''Process events common to all windows'''
    if event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT:
        sg.user_settings_set_entry('-WINDOW_LOCATION-', window.current_location())  # Save window location before closing
        window.close()
    if event == sg.WIN_CLOSED:
        switch_window(login)
    if event == "User List":
        switch_window(user_list)
    if event == "View Logged Equipment":            
        switch_window(user_equip)

def login():
    '''User login window'''
    layout = [
        [sg.T("Username")],
        [sg.InputText(key = "-USER-", do_not_clear=False)],
        [sg.T("Password")],
        [sg.InputText(key = "-PASSWORD-", do_not_clear=False)],
        [sg.Button("OK", bind_return_key=True, key="-OK-")],
    ]
    show_window("Login", layout)
    while window and window_open:
        event, values = window.read()  # window.read() belongs inside while loop
        if event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT:
            window.close()
        if event == sg.WIN_CLOSED:
            switch_window(None)
        if event == "-OK-":
            if accounts.get(values['-USER-']) == values['-PASSWORD-']:
                switch_window(user_list)
            else:
                sg.popup('Invalid Login.','Please try again.')
                window['-USER-'].set_focus()

def user_list():
    '''Some window that does something'''
    layout = [
        [sg.B("View Logged Equipment"), sg.B("User List")],
        [sg.B("User List Push Me", bind_return_key=True, key='-PUSH_ME-')]
    ]
    show_window("User List", layout)
    while window and window_open:
        event, values = window.read()
        if event == "-PUSH_ME-":  # Do event handling specific to this window first
            print('In user list window')
        else:
            main_window_menu(event, values)  # Handle events common to many windows (the top buttons)
 
def user_equip():
    '''Some window that does different things'''
    layout = [
        [sg.B("View Logged Equipment"), sg.B("User List")],
        [sg.B("User Equipment Push Me", bind_return_key=True, key='-PUSH_ME-')]
    ]
    show_window("User Equipment", layout)
    while window and window_open:
        event, values = window.read()
        if event == "-PUSH_ME-":  
            print('In user equipment window')
        else:
            main_window_menu(event, values)
  
switch_window(login)  # Start with login window
while next_window:
    next_window() # execute function to draw next window
I do not think this is the right way to write this program. I would make a tabbed window and create tabs for Logged Equipment, User List, Log Equipment Out, Open Tickets and Open Requests. Instead of destroying and re-creating the windows, the event loop would update the existing widgets to display new information. The resulting program would maybe be 200 lines long to do everything your program currently does.
Reply
#5
(Sep-23-2021, 12:57 PM)deanhystad Wrote: I played around with your code. It is an, um, er, interesting approach. I would never have come up with the idea of destroying and re-creating windows just to update the widgets. The top row of buttons is also an unusual way to present different views.

Here are some ideas you may find interesting. I modified the code to remove recursion.

Recursion is when a function calls itself, either directly or through indirectly. Your code has a lot of recursion. Functions call themselves to update the window or call functions to draw other windows that may in turn call the original function. This is a bad thing because it eats up memory. It is so bad that Python places an upper limit on how many levels of function calls are allowed. If you program reaches that limit, an excpetion is thrown.

To remove the recursion I rewrote the code to return control to a window switcher which calls the function to draw the next window. Instead of login() calling main(), login() now sets a variable and returns. The window switcher.
switch_window(login)  # Start with login window
while next_window:
    next_window() # execute function to draw next window
To switch from the current window to a new window, the window event loop assigns "next_window" to be the function that draws the next window, then the current window exits its event loop and lets control return to the window switcher loop. It uses a couple of convenience functions to help with this.
def switch_window(window_func):
    '''Close current window and set function to open new window'''
    global next_window, window_open
    next_window = window_func
    window_open = False

def show_window(title, layout):
    '''Create new window using layout.  Position window in same location as current window'''
    global window, window_open
    if window:
        window.close()
    window = sg.Window(title, layout, size=(600, 500), enable_close_attempted_event=True, location=sg.user_settings_get_entry('-WINDOW_LOCATION-', (None, None)))
    window_open = True
switch_window() sets the next_window function variable and sets window_open to False, causing the event loop to exit. show_window() draws the new window.

I changed the way window location was saved and restored. I have the window send an event if you click on the close window decoration. In the event handler I capture that event, save the window location, and close the window. I save the window location in a PySimpleGUI user setting named '-WINDOW_LOCATION-', and when the new window is drawn it uses the user setting to set the location of the new window.

I rewrote the login window to allow multiple login attempts without having to redraw the window. If the user enters in invalid username or password it clears the inputs, displays a message in a popup, and sets focus back to the user input.

Clearing the inputs is easy. You can set a flag to automatically clear an input when it is read, and I did that in the layou
    layout = [
        [sg.T("Username")],
        [sg.InputText(key = "-USER-", do_not_clear=False)],
        [sg.T("Password")],
        [sg.InputText(key = "-PASSWORD-", do_not_clear=False)],
        [sg.Button("OK", bind_return_key=True, key="-OK-")],
    ]
Setting the focus back to the user input was a bit trickier. I had to call the set_focus() method for the user input.
                window['-USER-'].set_focus()
The entire program:
import PySimpleGUI as sg

accounts = {"Admin":"Administrator", "User":"OneTwoThree"}
window = None
window_open = False
next_window = None

def switch_window(window_func):
    '''Close current window and set function to open new window'''
    global next_window, window_open
    next_window = window_func
    window_open = False

def show_window(title, layout):
    '''Create new window using layout.  Position window in same location as current window'''
    global window, window_open
    if window:
        window.close()
    window = sg.Window(title, layout, size=(600, 500), enable_close_attempted_event=True, location=sg.user_settings_get_entry('-WINDOW_LOCATION-', (None, None)))
    window_open = True

def main_window_menu(event, values):
    '''Process events common to all windows'''
    if event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT:
        sg.user_settings_set_entry('-WINDOW_LOCATION-', window.current_location())  # Save window location before closing
        window.close()
    if event == sg.WIN_CLOSED:
        switch_window(login)
    if event == "User List":
        switch_window(user_list)
    if event == "View Logged Equipment":            
        switch_window(user_equip)

def login():
    '''User login window'''
    layout = [
        [sg.T("Username")],
        [sg.InputText(key = "-USER-", do_not_clear=False)],
        [sg.T("Password")],
        [sg.InputText(key = "-PASSWORD-", do_not_clear=False)],
        [sg.Button("OK", bind_return_key=True, key="-OK-")],
    ]
    show_window("Login", layout)
    while window and window_open:
        event, values = window.read()
        if event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT:
            window.close()
        if event == sg.WIN_CLOSED:
            switch_window(None)
        if event == "-OK-":
            if accounts.get(values['-USER-']) == values['-PASSWORD-']:
                switch_window(user_list)
            else:
                sg.popup('Invalid Login.','Please try again.')
                window['-USER-'].set_focus()

def user_list():
    '''Some window that does something'''
    layout = [
        [sg.B("View Logged Equipment"), sg.B("User List")],
        [sg.B("User List Push Me", bind_return_key=True, key='-PUSH_ME-')]
    ]
    show_window("User List", layout)
    while window and window_open:
        event, values = window.read()
        if event == "-PUSH_ME-":
            print('In user list window')
        else:
            main_window_menu(event, values)
 
def user_equip():
    '''Some window that does different things'''
    layout = [
        [sg.B("View Logged Equipment"), sg.B("User List")],
        [sg.B("User Equipment Push Me", bind_return_key=True, key='-PUSH_ME-')]
    ]
    show_window("User Equipment", layout)
    while window and window_open:
        event, values = window.read()
        if event == "-PUSH_ME-":
            print('In user equipment window')
        else:
            main_window_menu(event, values)
  
switch_window(login)  # Start with login window
while next_window:
    next_window() # execute function to draw next window
I do not think this is the right way to write this program. I would make a tabbed window and create tabs for Logged Equipment, User List, Log Equipment Out, Open Tickets and Open Requests. Instead of destroying and re-creating the windows, the event loop would update the existing widgets to display new information. The resulting program would maybe be 200 lines long to do everything your program currently does.

Hello mate,

See I wanted to have one window that updates based on which tab the user wanted to view, however i couldn't figure out how to have a single dynamic window.

Could you show me how you'd have two layouts and have a single window update based on user input?

If that is even possible :')

I appreciate your feedback, it's really helping me understand further.
while dad_has_cigs == True:
    happiness = True
    if dad_has_cigs == False:
    print("Dad come home!")
    happiness = not happiness
    break
Reply
#6
Look at tabs. There is an example in the cookbook.
Reply
#7
Hello, me again!

I've taken on-board your advice and have begun redesigning the program. What do you think of below?

There are still some global variables and I still have to destroy and recreate some windows as I can't figure out how to dynamically update output's, such as text.

But I've redesigned the windows, renamed all the variabls to something more understandable etc the only thing I've not done is comments XD

Let me know what you think so far.

import PySimpleGUI as sg
import sqlite3
sg.theme("DarkAmber")
windowlocation = [1311,0]
con = sqlite3.connect(r'equipment.db') # FIGURE OUT HOW TO ACCESS SHARED DRIVE !#
cur = con.cursor()
filtered_equipment = []
filter_ = ("")
def login():
    global windowlocation
    admins = [["Admin","Administrator"],["Admin","OneTwoTree"]]
    layout0 = [[sg.T("")],[sg.T("Admin Login",font=("arial,15"))],[sg.T("Username")],[sg.InputText(key = "usr")],[sg.T("Password")],[sg.InputText(key = "pwd")],[sg.Button("OK", bind_return_key = True)],[sg.T("")],[sg.T("")],[sg.B("Guest Login")]]
    window0 = sg.Window("IT Portal", layout0, location=(windowlocation[0],windowlocation[1]), size = (600,500),finalize = True)
    event,values = window0.read()
    windowlocation.clear()
    while True:
        if event == sg.WIN_CLOSED:
            break
        if event == "OK":
            newlocation = window0.CurrentLocation()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            b = str(values['usr'])
            c = str(values['pwd'])
            if b in admins[0] and c in admins[1]:
                window0.close()
                adminmain()                
                break
            if b not in admins or c not in admins:
                sg.popup('Invalid Login.','Please try again.', location = (windowlocation[0],windowlocation[1]))
                window0.close()
                login()
                break
        if event == "Guest Login":
            newlocation = window0.CurrentLocation()
            window0.close()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            guestmain()
            break
def guestmain():
    ticket_layout = [[sg.T("Topic:"),sg.T("                    "),sg.T("Issue Description:")],[sg.Combo(values = ("Office Products","Email","Hardware","Other"),key = "topic"),sg.Multiline(size = (45,5),key = "description")],
                [sg.T("Email Address:")],[sg.InputText(key="email")],[sg.T("")],[sg.T("")],[sg.B("Submit Ticket"),sg.T("Please include as much information as you can.")]]
    equipment_request_layout = [[sg.T("Name:")],[sg.InputText(key="UserName")],[sg.T("")],[sg.T("Equipment Type:")],[sg.Combo(values = ("Monitor","Screen","Mobile","Desktop","Laptop","Mouse/Keyboard","Other"),key="Equipment_type")],[sg.T("If you selected 'Other' please specify in the box below.")],[sg.T("Please say why you need the equipment:")],[sg.Multiline(size=(45,5),key="Why")],[sg.T("")],[sg.T("")],[sg.B("Submit Request")]]
    window1_layout = [[sg.TabGroup([[sg.Tab('New Ticket',ticket_layout),sg.Tab('Equipment',equipment_request_layout)]])]]
    window1 = sg.Window('Guest Portal', window1_layout, location=(windowlocation[0],windowlocation[1]),size = (600,500), finalize = True)
    while True:
        event, values = window1.read()
        if event == sg.WIN_CLOSED:
            break
        if event == "Submit Ticket":
            topic = values["topic"]
            ticket_desc = values["description"]
            user_email = values["email"]
            all_tickets = []
            for row in cur.execute('select * from tickets'):
                all_tickets.append(row)
            cur.execute('insert into tickets values('+str(len(all_tickets)+1) + ',"'+str(topic)+ '","' + str(ticket_desc[:-1]) + '",' + "false" + ',"' + str(user_email) + '")')
            con.commit()
            newlocation = window1.CurrentLocation()
            windowlocation.clear()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            window1.close()
            guestmain()
            break
        if event == "Submit Request":
            name = values["UserName"]
            equipment = values["Equipment_type"]
            reason = values["Why"]
            all_requests = []
            for row in cur.execute('select * from equip_request'):
                all_requests.append(row)
            cur.execute('insert into equip_request values(' + str(len(all_requests)+1) + ',"'+str(name)+'","' + str(equipment)+'","' + str(reason[:-1])+'")')
            con.commit()
            newlocation = window1.CurrentLocation()
            windowlocation.clear()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            window1.close()
            guestmain()
            break
def adminmain():
    global filtered_equipment, filter_, windowlocation
    open_tickets = []
    user_equipment = []
    for row in cur.execute('select * from tickets where open_close = false'):
        open_tickets.append(row)
    for row in cur.execute('select * from user_equipment'):
        user_equipment.append(row)
    username = []
    username.append(user_equipment[0][1])
    x = 0
    for x in range(len(user_equipment)):
        if user_equipment[x][1] not in username:
            username.append(user_equipment[x][1])
            x += 1
        x += 1
    mobiles = 0
    desktops = 0
    laptops = 0
    monitors = 0
    for x in range(len(user_equipment)):
        if "Mon" in user_equipment[x][2]:
            monitors += 1
        if "Mob" in user_equipment[x][2]:
            mobiles += 1
        if "Des" in user_equipment[x][2]:
            desktops += 1
        if "Lap" in user_equipment[x][2]:
            laptops += 1
    
    admin_ticket_layout = [[sg.T("Open Tickets")],[sg.Listbox(values = open_tickets, size = (60,10),key="tickets"),sg.B("Select")],[sg.T(""),sg.B("Refresh")]]
    equipment_by_user = [[sg.T("")],[sg.T("Name")],[sg.Listbox(values=username,size = (30,10),key = "userid")],[sg.Button("Select User", bind_return_key = True)]]
    total_equipment = [[sg.T("Monitors"),sg.T("       "),sg.T("Desktops"),sg.T("       "),sg.T("Laptops"),sg.T("       "),sg.T("Mobiles")],
                 [sg.T("     " +str(monitors)+ "         "),sg.T("             " +str(desktops)+ "           "),sg.T("          " +str(laptops)+ "   "),sg.T("                  " +str(mobiles))],[sg.T("")],[sg.T("")],[sg.T("")],[sg.T("")],
                 [sg.Combo(values = ("Monitor","Desktop","Laptop","Mobile"),default_value=("Filter by"),key = "filterby"),sg.T(filter_)],[sg.Button("Filter"),sg.Listbox(values = filtered_equipment, size = (35,10))]]

    window2_layout = [[sg.TabGroup([[sg.Tab('Out Equipment',total_equipment),sg.Tab('Open Tickets',admin_ticket_layout),sg.Tab('Equipment',equipment_by_user)]])]]
    window2 = sg.Window('IT Portal', window2_layout, location=(windowlocation[0],windowlocation[1]),size = (600,500), finalize = True)
    
    while True:
        event,values = window2.read()
        if event == sg.WIN_CLOSED:
            break
        if event == "Refresh":
            windowlocation = []
            newlocation = window2.CurrentLocation()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            window2.close()
            adminmain()
        if event == "Filter":
            filtered_equipment.clear()
            filter_ = values["filterby"]
            for x in range(len(user_equipment)):
                if filter_ in user_equipment[x]:
                    filtered_equipment.append(user_equipment[x][1])
                    filtered_equipment.append(user_equipment[x][3])
                x += 1
            windowlocation = []
            newlocation = window2.CurrentLocation()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            window2.close()
            adminmain()
            break
        if event == "Select":
            windowlocation = []
            newlocation = window2.CurrentLocation()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            selected_ticket = values["tickets"]
            if len(selected_ticket) < 1:
                sg.popup("Invalid Selection","Please Choose A Ticket.", location = (windowlocation[0],windowlocation[1]))
                adminmain()
                break
            notes = [[]]
            for row in cur.execute('select * from notes where id =' + str(selected_ticket[0][0]) + ';'):
                notes.append(row)
            if len(notes) == 1:
                for x in range(4):
                    notes[0].append("NA")
            selection = [[sg.T("")],[sg.T("ID:      "),sg.T(selected_ticket[0][0])],[sg.T("Topic: "),sg.T(selected_ticket[0][1])],[sg.T("Issue: "),sg.T(selected_ticket[0][2])],[sg.T("Name: "),sg.T(selected_ticket[0][4])],[sg.B("Clear")],[sg.T(notes[len(notes)-1][-1])],[sg.T(notes[len(notes)-1][-2])],[sg.T("")],[sg.B("New Note")]]
            window4 = sg.Window("IT Admin portal - View Ticket", selection,location=(windowlocation[0],windowlocation[1]), size = (300,300), finalize = True)
            while True:
                event,values = window4.read()
                if event == sg.WIN_CLOSED:
                    window2.close()
                    adminmain()
                    break
                if event == "Clear":
                    cur.execute('update tickets set open_close = True where id =' + str(selected_ticket[0][0]) + ';')
                    con.commit()
                    selected_ticket.clear()
                    window4.close()
                    window2.close()
                    adminmain()
                if event == "New Note":
                    windowlocation = []
                    newlocation = window2.CurrentLocation()
                    windowlocation.append(newlocation[0])Ad
                    windowlocation.append(newlocation[1])
                    new_note_layout = [[sg.T("Date: "),sg.InputText(key = "notedate")],[sg.T("Note: "),sg.InputText(key = "notetxt")],[sg.B("OK")]]
                    window5 = sg.Window('Note Taker', new_note_layout, size = (200,100))
                    while True:
                        event, values = window5.read()
                        if event == sg.WIN_CLOSED:
                            break
                        if event == "OK":
                            notedate = values['notedate']
                            notetxt = values['notetxt']
                            cur.execute('insert into notes values('+str(selected_ticket[0][0])+',"'+str(notetxt)+'","'+str(notedate)+'")')
                            con.commit()
                            window5.close()
                            window4.close()
                            window2.close()
                            adminmain()
                            break
        if event == "Select User":
            windowlocation = []
            newlocation = window2.CurrentLocation()
            windowlocation.append(newlocation[0])
            windowlocation.append(newlocation[1])
            user_id = str(values["userid"])
            equip = []
            serial = []
            if len(user_id) < 3:
                sg.popup("Invalid Selection","Please Choose From The List",location = (windowlocation[0],windowlocation[1]))
                window2.close()
                adminmain()
                break            
            for x in range(len(user_equipment)):
                if user_id[2:-2] in user_equipment[x][1]:
                    equip.append(user_equipment[x][2])
                    serial.append(user_equipment[x][3])
                    x += 1
            user_equipment_details = [[sg.T("Type"),sg.T("           "),sg.T("Serial"),sg.T("                                                    "),sg.B("Back")],[sg.Listbox(values=equip,size = (10,10),key = "user_equip"),sg.Listbox(values=serial,size=(33,10),key = "serial")],[sg.T("")],[sg.T("")],
                          [sg.T("An equipment return form must be filled out, scanned and saved.")],[sg.T("Select the serial number of the returned item.")],[sg.Button("Return")]]
            window3 = sg.Window('IT Admin Portal - User Details', user_equipment_details, location = (windowlocation[0],windowlocation[1]), size = (600,500), finalize = True)
            while True:
                event,values = window3.read()
                if event == sg.WIN_CLOSED:
                    window2.close()
                    adminmain()
                    break
                if event == "Back":
                    windowlocation = []
                    newlocation = window2.CurrentLocation()
                    windowlocation.append(newlocation[0])
                    windowlocation.append(newlocation[1])
                    window3.close()
                    window2.close()
                    adminmain()
                if event == "Return":
                    chosen_serial = values["serial"]
                    cur.execute('delete from user_equipment where serial ="' + str(chosen_serial)+'";')
                    con.commit()
                    window3.close()
                    window2.close()
                    adminmain()
                    break
                
login()



                     
while dad_has_cigs == True:
    happiness = True
    if dad_has_cigs == False:
    print("Dad come home!")
    happiness = not happiness
    break
Reply
#8
Remaking the window just to update the contents is not acceptable. The flash will annoy your users and your program has to be much more compilated because it is taking on window manager responsibilities. Updating the window without redrawing is easy. Far easier than what you are doing. Look at the pattern 2B in the cookbook. Here's an example using your code base.
import random
import PySimpleGUI as sg

def update_open_tickets(window, open_tickets):
    window['-TICKETS_LIST-'].update(open_tickets)

def open_a_ticket(window, open_tickets):
    open_tickets.append(random.choice(['Billie Eilish', 'Billy Joel', 'Taylor Swift', 'BTS', 'Bob Dylan']))
    update_open_tickets(window, open_tickets)

def select_tickets(window, open_tickets):
    if new_tickets := window['-TICKETS_LIST-'].get():
        open_tickets.extend(new_tickets)
        update_open_tickets(window, open_tickets)

def adminmain():
    ticket_column = [
        [sg.B("Select", expand_x=True, expand_y=True, key='-TICKETS_SELECT-')],
        [sg.B("Refresh", expand_x=True, expand_y=True, key='-TICKETS_REFRESH-')]
    ]
    ticket_tab = [
        [sg.Listbox(values=[], size=(40, 10), key="-TICKETS_LIST-"), sg.Column(ticket_column, expand_y=True)]
    ]
    equipment_tab = [
        [sg.T('Nothing to see here.  Move along.')]
    ]

    layout = [[sg.TabGroup([[sg.Tab('Equipment', equipment_tab), sg.Tab('Open Tickets', ticket_tab)]])]]
    window = sg.Window('IT Portal', layout, finalize=True)

    open_tickets = ['Bruce Springsteen']
    update_open_tickets(window, open_tickets)

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event == "-TICKETS_REFRESH-":
            open_a_ticket(window, open_tickets)
        elif event == "-TICKETS_SELECT-":
            select_tickets(window, open_tickets)

adminmain()
Pressing the refresh button adds a random ticket to the list. No getting the window position. No redrawing the window. No forcing the user to re-select the tab after you redraw the window. Simple.

Your event loop looks terrible. If processing an event requires many lines of code, write a function and call the function from the loop. Event code in the loop should be 5 lines tops. You can get away with lots of code for processing an event when you only have a couple of events, Event then I think it is a bad idea to have one monster "do it all" function. A side benefit of using functions to process your events is you can use the same functions to populate your lists and other controls when you first draw your windows. Notice that I used an empty list in the ticket layout listbox and updated the listbox after the window was drawn. Currently your layouts have a lot of code because they are populating all the controls with info from the database. You should move all that code into functions that you can use for initializing and updating the window, create the layout using empty values, and then call you functions to initialize the window.

Another thing about layouts. Use keys for everything. Notice how easy it is to find events in my event loop because of how the events are named. Think of how this would look if all your user ticket tab controls had keys that started with '-USER_' and all the total equipment tab controls had keys that started with '-EQUIP_'. It would make it really easy to find the event code associated with a particular control on a particular tab. Far better than 'select'. select what? select where?

Another thing about layouts. You have a lot of blank labels that you use for spacers. Often vertical, but sometimes horizontal to make controls line up on different rows. That is going to be a problem if you ever change your font and it may be sensitive to changing themes. If you need vertically aligned widgets, use columns, or better yet rethink your layout so vertical alignment is not needed. Read through the documents and become familiar with the command line arguments and methods for each element. Most elements share the same arguments and methods so this won't take lone.

Stop using so many variable names. Why do you have window0, window1 when you only ever have 1 window? window0 is a bad variable name. main_window, login_dialog, error_message are meaningful names. They say what they are. window0 and window1? What do they mean?
Reply
#9
It is hard to be certain since I don't have your database, but the program flow seems awkward to me.

First off I think it odd to have a login screen appear when the program starts. Normally if you require a login, the login is a control at the top of the screen (along with a logout), and operations are enabled/disabled by the login status. This would eliminate the Guest Login as that would be the reduced capability when not logged in. I would change the program so it opens to the guest window. The guest window has a login button near the top right corner. Clicking that opens a login popup. If the login is successful you can erase the guest window and replace with the admin main window. This window has a logout button near the top right corner. Clicking that closes the admin main window and draws the guest window.

User equipment is odd. To do a return you go to the Equipment tab and press the select button. This draws another screen that has lists of equipment checked out by the user. For some reason the list is split inti equipment type and serial number. On this page you can select a serial number and press the return button to return the item.

I think it would be much more natural to have a screen that displays he checked out equipment tickets. The entire ticket (is it a ticket or is it called something else? checkout?), not just the user id. At least the user id, equipment type and serial number so you can select a ticket/checkout without having to click on the user id to display additional info. There should be a way to filter tickets by user ID and equipment type. These should not require an additional window, only updating the tickets displayed in the equipment tab list. There should be a button on this page for returning the equipment. Press this button and it might pop up a dialog to complete the return. When the dialog is filled out, the ticket is removed from the database and all tabs should automatically update their displays. There should not be any refresh buttons anywhere.

Essentially the interface should be arranged such that everything you need to complete an activity is visible in one place and you don't have to move between screens. Confirmation screens are the one exception, but those should be modal dialogs that appear over (but don't completely occlude) the main window.

This may make more sense:
import PySimpleGUI as sg

saved_location = (None, None) # Remember where window was when closed

class Shutdown(Exception):
    '''Custom exception for exiting this program'''

def show_window(title, layout, parent=None, **kwargs):
    '''Window create convenience function.  Position window on top of parent if provided,
    else restore saved location
    '''
    location = (x+70 for x in parent.current_location()) if parent else saved_location
    return sg.Window(title, layout, finalize=True, enable_close_attempted_event=True, location=location, **kwargs)

def close_window(window):
    '''Window close convenience function.  Saves window location'''
    global saved_location
    saved_location = window.current_location()
    window.close()

def verify_quit(parent):
    '''Verify that you want to quit the application.  Returns True if user wamts to quit'''
    window = show_window("Verify Quit", [
        [sg.T("Are you sure you want to quit.  Press 'Yes' to quit")],
        [sg.Button("Yes", size=10, key="-QUIT_YES-"), sg.Button("No", size=10, key="-QUIT_NO-")]],
        modal=True, parent=parent)

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event in (sg.WINDOW_CLOSE_ATTEMPTED_EVENT, "-QUIT_NO-", "-QUIT_YES-"):
            window.close()  # Do not save location of this window
            return event == "-QUIT_YES-"
    return False


def login(parent):
    '''Dialog window for logging into admin level'''
    accounts = {"Admin":"Administrator", "User":"ABC"}
    window = show_window("Login", [
        [sg.T("Username", size=8), sg.InputText(key = "-LOGIN_USER-", size=20)],
        [sg.T("Password", size=8), sg.InputText(key = "-LOGIN_PASSWORD-", size=20, password_char='*')],
        [sg.Button("Enter", size=10, key="-LOGIN_ENTER-"), sg.Button("Cancel", size=10, key="-LOGIN_CANCEL-")]],
        modal=True, parent=parent)

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event in (sg.WINDOW_CLOSE_ATTEMPTED_EVENT, "-LOGIN_CANCEL-"):
            window.close()  # Do not save location of this window
        elif event == "-LOGIN_ENTER-":
            if accounts.get(values['-LOGIN_USER-']) == values['-LOGIN_PASSWORD-']:
                window.close()  # Do not save location of this window
                return True
            sg.popup('Invalid user id or password')
    return False


def guest_main():
    '''Reduced access window'''
    window = show_window('Guest Portal', [
        [sg.T("Topic:", size=15), sg.Combo(values = ("Office Products", "Email", "Hardware", "Other"), key='-GUEST_TOPIC-'), \
            sg.T("", expand_x=True), sg.B('Login', border_width=0, key='-GUEST_LOGIN-')],
        [sg.T("Issue Description:", size=15), sg.Multiline(size = (45,5), expand_x=True, key="-GUEST_DESCRIPTION-")],
        [sg.T("Email Address:", size=15), sg.InputText(expand_x=True, key="-GUEST_EMAIL-")],
        [sg.T("")],
        [sg.B("Submit Ticket", key='-GUEST_SUBMIT'), sg.T("Please include as much information as you can.")]])
    window['-GUEST_LOGIN-'].update(button_color=window.BackgroundColor) # Blend login button

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event == sg.WINDOW_CLOSE_ATTEMPTED_EVENT:
            if verify_quit(window):
                close_window(window)
                raise Shutdown()
        elif event == '-GUEST_LOGIN-':
            if login(window):
                # Return True to indicate successful login
                close_window(window)
                return True
    return False


def admin_main():
    '''Full access window.  Closing window logs out of admin access'''
    window = show_window('Admin', [
        [sg.T("Topic:", size=15), sg.Combo(values = ("Office Products", "Email", "Hardware", "Other"), key='-ADMIN_TOPIC-'), \
            sg.T("", expand_x=True), sg.B('Logout', border_width=0, key='-ADMIN_LOGOUT-')],
        [sg.T("Issue Description:", size=15), sg.Multiline(size = (45,5), expand_x=True, key="-ADMIN_DESCRIPTION-")],
        [sg.T("Email Address:", size=15), sg.InputText(expand_x=True, key="-ADMIN_EMAIL-")],
        [sg.T("")],
        [sg.B("Submit Ticket", key='-ADIMIN-SUBMIT'), sg.T("Please include as much information as you can.")]])
    window['-ADMIN_LOGOUT-'].update(button_color=window.BackgroundColor) # Blend logout button

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event in (sg.WINDOW_CLOSE_ATTEMPTED_EVENT, '-ADMIN_LOGOUT-'):
            close_window(window)
    return False


# Handle Guest/Admin.  Start as guest
try:
    logged_in = False
    while True:
        logged_in = admin_main() if logged_in else guest_main()
except Shutdown:
    print('Shutting down')  # Replace with cleanup code
Notice the show_window(), close_window() convenience functions? When you see the same lines of code repeated over and over and over and over and over you should make it a function. Even if the code is only repeated 2-3 times it is worth writing a function. It reduces the overall amount of code. It documents that this code is related and performs a well defined task. It puts all the code in one place so you only have to fix bugs once. I cannot emphasize enough how important it is for you to stop using copy/paste when writing code.
Reply
#10
I updated post #8 to show how you can change text.
import random
import PySimpleGUI as sg

def update_open_tickets(window, open_tickets):
    window['-TICKETS_LIST-'].update(open_tickets)
    window['-TICKETS_COUNT-'].update(f'{len(open_tickets):>3}')  # Update ticket count text

def open_a_ticket(window, open_tickets):
    open_tickets.append(random.choice(['Billie Eilish', 'Billy Joel', 'Taylor Swift', 'BTS', 'Bob Dylan']))
    update_open_tickets(window, open_tickets)

def select_tickets(window, open_tickets):
    if new_tickets := window['-TICKETS_LIST-'].get():
        open_tickets.extend(new_tickets)
        update_open_tickets(window, open_tickets)

def adminmain():
    ticket_column = [
        [sg.B("Select", expand_x=True, expand_y=True, key='-TICKETS_SELECT-')],
        [sg.B("Refresh", expand_x=True, expand_y=True, key='-TICKETS_REFRESH-')]
    ]
    ticket_tab = [
        [sg.Listbox(values=[], size=(40, 10), key="-TICKETS_LIST-"), sg.Column(ticket_column, expand_y=True)],
        [sg.T('Number of Tickets:'), sg.T('  0', key='-TICKETS_COUNT-', size=3)]  # Added a te
    ]
    equipment_tab = [
        [sg.T('Nothing to see here.  Move along.')]
    ]

    layout = [[sg.TabGroup([[sg.Tab('Equipment', equipment_tab), sg.Tab('Open Tickets', ticket_tab)]])]]
    window = sg.Window('IT Portal', layout, finalize=True)

    open_tickets = ['Bruce Springsteen']
    update_open_tickets(window, open_tickets)

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event == "-TICKETS_REFRESH-":
            open_a_ticket(window, open_tickets)
        elif event == "-TICKETS_SELECT-":
            select_tickets(window, open_tickets)

adminmain()
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020