PySimpleGUI / PySimpleGUI

Python GUIs for Humans! PySimpleGUI is the top-rated Python application development environment. Launched in 2018 and actively developed, maintained, and supported in 2024. Transforms tkinter, Qt, WxPython, and Remi into a simple, intuitive, and fun experience for both hobbyists and expert users.

Home Page:https://www.PySimpleGUI.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Question] Is it possible to create columns inside a listbox?

EdwardChamberlain opened this issue · comments

commented

Question


Operating System

Mac OS

PySimpleGUI Port (tkinter, Qt, Wx, Web)

any


Versions

Python version (sg.sys.version)

3.8.x

PySimpleGUI Version (sg.__version__)

latest

GUI Version (tkinter (sg.tclversion_detailed), PySide2, WxPython, Remi)


Anything else you think would be helpful?
see below


Troubleshooting

These items may solve your problem. Please check those you've done by changing - [ ] to - [X]

  • Searched main docs for your problem www.PySimpleGUI.org
  • Looked for Demo Programs that are similar to your goal Demos.PySimpleGUI.org
  • If not tkinter - looked for Demo Programs for specific port
  • For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
  • Run your program outside of your debugger (from a command line)
  • Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org
  • Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released

Detailed Description

I am looking create a gui to quickly classify financial transactions (into things like "food", "bills", etc) and would currently have them all shown in a listbox. What I would like to do is add a column to this listbox such that the user can select from a combo box what the transaction is.

Alternatively if you can think of a better way of doing this Im all ears! I just need a simple way to present a long list (maybe 50 items) to the user and allow them to tell me what category they are (they may already be populated though so its an 'editor' rather than a direct input)

Code To Duplicate

question, no code.

This pre-formatted code block is all set for you to paste in your bit of code:

No code.

Screenshot, Sketch, or Drawing


Watcha Makin?

as above

It cannot be different layout in a Listbox element.

Maybe a popup window to show all the selections when necessary.

import PySimpleGUI as sg

category ={
    'Net Income': ['Regular paycheck', 'Pension benefits', 'Work bonus', 'Work savings plan', 'Rental Income', 'Royalty Income', 'Support payments', 'Government benefits', 'Investment interest'],
    'Housing': ['Mortgage', 'Rent', 'Property Taxes', 'HOA dues', 'Fire Insurance', 'Renters insurance', 'Maintenance', 'Appliances'],
    'Utilities': ['Natural Gas', 'Electricity', 'Water', 'Cell phone', 'Cable', 'Internet', 'Garbage collection'],
    'Transportation': ['Car payment', 'Car Insurance', 'Registration fees', 'Gas', 'Vehicle maintenance', 'Other vehicle repairs', 'Transit fees', 'Tolls', 'Parking fees'],
    'Food': ['Groceries', 'Restaurants', 'Coffee/snacks', 'Meal Kit Delivery'],
    'Personal Debt': ['Loan payments', 'Revolving line of credit', 'Credit card payments', 'Student loan payments', 'Retail store credit card'],
    'Education': ['College tuition', 'Books/school supplies', 'Private lessons', 'Online courses'],
    'Child Care': ['Daycare', 'Babysitting', 'Child support payments', 'School Supplies', 'School lunches', 'Clothes', 'Registration fees', 'Sports equipment', 'Private school tuition', 'Tutoring', 'School field trips'],
    'Pets': ['Pet food', 'Pet supplies', 'Vet costs', 'Toys', 'Grooming', 'Daycare', 'Insurance premiums'],
    'Insurance Expenses': ['Health insurance', 'Dental insurance', 'Life insurance', 'Illness insurance'],
    'Personal Care Expenses': ['Soap/Shampoo', 'Skincare products', 'Razors/shaving cream', 'Clothes', 'Shoes', 'Hair appointments', 'Hair color', 'Appointments', 'Manicure/pedicure', 'Massage therapy', 'Gym membership'],
    'Healthcare Expenses': ['Prescriptions', 'Glasses/Contact lenses', 'Medical visits', 'First Aid equipment', 'Mobility aids'],
    'Household Items': ['Cleaning supplies', 'Laundry detergent', 'Dishwasher detergent', 'Lightbulbs', 'Smoke alarms', 'Fire extinguisher', 'Paper towels', 'Vacuum', 'Kitchen appliances'],
    'Miscellaneous Expenses': ['Bank fees', 'Credit card annual fees', 'Membership dues', 'Misc. user fees'],
    'Gifts': ['Wedding gifts', 'Birthday gifts', 'Anniversary gifts', 'For a teacher', 'For a coworker'],
    'Entertainment Expenses': ['Sporting events', 'Movie tickets', 'Streaming subscriptions', 'Camping', 'Hunting or Fishing'],
    'Charitable Giving': ['Tithing', 'Charitable Donation', 'Child Sponsorship', 'Donation'],
    'Savings/Investment': ['Retirement savings', 'Emergency Fund', 'Education savings', 'Health savings', 'Vacation fund'],
}

len1 = max(map(len, category.keys()))
len2 = max(map(lambda x:max(map(len, x)), category.values()))

def selection():
    font = ('Courier New', 11, 'bold')
    sg.set_options(font=font)
    sg.theme('DarkGrey8')
    cols, layout, line = 6, [], []
    len0 = len(category)-1
    for i, (key, item) in enumerate(category.items()):
        line.append(sg.Frame(key, [[sg.Listbox(item, size=(len2+1, 5), pad=(0, 0), enable_events=True, key=key)]], pad=(0, 0)))
        if i % cols == cols-1 or i==len0:
            layout.append(line)
            line = []
    event, values = sg.Window('Selection', layout, margins=(0, 0), modal=True).read(close=True)
    if event == sg.WIN_CLOSED:
        return None
    else:
        return (event, values[event][0])

layout = [
    [sg.Text('Category:'), sg.Push(), sg.Input('', disabled=True, key='Kind')],
    [sg.Text('Item:'),     sg.Push(), sg.Input('', disabled=True, key='Item')],
    [sg.Push(), sg.Button('Select')],
]
window = sg.Window('Expense Category Selection', layout)

while True:

    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    elif event == 'Select':
        result = selection()
        if isinstance(result, tuple) and len(result)==2:
            kind, item = result
            window['Kind'].update(kind)
            window['Item'].update(item)

window.close()

cols = 6
image

cols = 5
image

Very nice but how to select an item and then if OK confirm using ENTER?

You can bind Return key to window to generate an event to return from your popup window.

window.bind('<Return>', '-RETURN-')        # After window finalized

Following script show the way in a pop window by using a Confirm button or the Return key to confirm the selection.

def selection():
    font = ('Courier New', 11, 'bold')
    sg.set_options(font=font)
    sg.theme('DarkGrey8')
    cols, layout, line = 5, [], []
    len0 = len(category)-1
    for i, (key, item) in enumerate(category.items()):
        line.append(sg.Frame(key, [[sg.Listbox(item, size=(len2+1, 5), pad=(0, 0), enable_events=True, key=key)]], pad=(0, 0)))
        if i % cols == cols-1 or i==len0:
            layout.append(line)
            line = []
    layout.append([sg.Push(), sg.Button('Confirm', key='-CONFIRM-'), sg.Button('Cancel', key='-CANCEL-')])
    window = sg.Window('Selection', layout, margins=(0, 0), modal=True, finalize=True)
    window.bind('<Return>', '-RETURN-')
    selection = None
    while True:
        event, values = window.read()
        if event in (sg.WIN_CLOSED, '-CANCEL-', '-CONFIRM-', '-RETURN-'):
            result = None
            if event in ('-CONFIRM-', '-RETURN-'):
                if selection is None:
                    continue
                else:
                    result = (selection, values[selection][0])
            break
        elif event in category:
            if selection is not None:
                window[selection].update(set_to_index=[])
            selection = event
    window.close()
    return result

image

@jason990420 Learning by functional incremented examples, nothing better... Thank you.

commented

This example is quite close to what I am looking for @jason990420 !

What I have is a list of vendors (in a dict currently):

{
    "MCDONALDS": RetailerCategory.EATING_OUT,
    "LIDL GB": RetailerCategory.BILLS,
    "FARM SHOP": RetailerCategory.EATING_OUT,
    "B&Q_DIY": RetailerCategory.HOME_IMPROVEMENT,
    "ZOO": RetailerCategory.HOLIDAYS,
}

What I want is to present the user with a list of maybe 50 or 100 + vendors and allow them to input through the GUI what category they are (from Holidays, Eating out, Home Improvement, Bills, etc) to allow them to create this dictionary! (rather than me having to manually code it all out!)

rather than me having to manually code it all out!

I like the not wanting to "manually code it" part... but you do have to code it. The learning process takes time. One must consume, digest, ponder, and experiment. Quick answers via Google and asking on StackOverflow is not what creates great developers.

Glad you've got a good head-start with the examples provided. There are 100s of them in the Demo Programs, 100 more in the Cookbook and eCookbook, and 100's of pages of documentation that should give you much of what you'll need, if not all of it.

Feel free to ask questions and get help. Try not to use them as a way to educate yourself though. I think you understand what I mean by this.

When you've got something you can show, PLEASE post a screenshot! Love seeing what you're all creating.

commented

Feel free to ask questions and get help. Try not to use them as a way to educate yourself though. I think you understand what I mean by this.

@PySimpleGUI I'm sorry, I have no idea what you mean by that.

I am not saying I want a copy paste example if that is what you are implying, I am saying I do not want to have to manually enter each vendor into a python dictionary as code in my IDE (which is my current and very upsetting solution!). I want to create a GUI that allows a user to quickly categories transactions that is then exported into a JSON which can later be re-imported / shared later.

Jasons example is a really nice selection dialogue but I am also struggling with how to best present the data that you would typically view in a database / table type layout to the user since I cannot split the listbox into columns. I suppose you could do this with some clever formatting and padding with spaces but it seems like a poor workaround.

When you've got something you can show, PLEASE post a screenshot! Love seeing what you're all creating.

Is there somewhere to share PySimpleGUI projects? I have been using this library for a couple of years now and love the simplicity it brings, for both me in terms of writing the code and for users who aren't python savvy in terms of program usability.

@PySimpleGUI I'm sorry, I have no idea what you mean by that.

Thank you for letting me know I didn't explain what I meant very well.

The point is that the GitHub issues are a fine place to ask for help with how things work, get some advice, etc, but there's a point where questions can change from "I need a little help" to "write this for me".

Or, as you put it a copy paste example. You nailed it

image

I don't think you would do that..... especially since you restated the problem I was describing.... and you've been writing PySimpleGUI programs for TWO YEARS?!

Posting Screenshots

If you click on the "Issues" link at the top of the page, there are a number of "Pinned" issues at the top

image

One of them is to Issue Number Ten, which is where users can post screenshots. You can also post them on the Wiki.

We're working on a Gallery feature that will enable you to take the screenshot and upload it to the "PySimpleGUI Gallery" from PySimpleGUI itself. A first version of the code to take a screenshot was added to the last release 4.60.0. It has quite a bit more work left to do to get the feature fully complete, but we're well on the way! I'm willing to work on longer-term features like this one where it takes several releases to get the full feature complete.

User Settings APIs

If you're thinking of using JSON as a simple database, something I think would work fine in many situations, then you may find the PySimpleGUI User Settings APIs to be of help. They're worth taking a look at.

Your Application

Jasons example is a really nice selection dialogue but I am also struggling with how to best present the data that you would typically view in a database / table type layout to the user since I cannot split the listbox into columns. I suppose you could do this with some clever formatting and padding with spaces but it seems like a poor workaround.

I wouldn't think about this in terms of trying to modify any element, like a listbox, but instead think in terms of your entire window and how you can build what you're after using individual elements. If you want a "row" of a table to have text and combo boxes and checkboxes, then make a layout that has rows with those items.

What would an ideal "Row" of your table look like? I mean in terms of Text, Input, Combo, etc?

commented

and you've been writing PySimpleGUI programs for TWO YEARS‽

Sadly time is a poor metric of capability! My experience with PySimpleGui has never really extended beyond very static GUIs usually as a supplement to a script for very basic user input (like file browsing, file naming, or perhaps input of a parameter). Thats something I would like to expand on with this project for sure.

I think I got myself caught up thinking about using a Listbox with columns but I like your suggestion of thinking about the entire window instead. I came up with this which I think works quite well as a mini demo of the concept using a column:

import PySimpleGUI as sg

options = ["Option 1", "Option 2",]

def row(row_id):
    row_layout = [
        sg.Input(str(row_id), disabled=True, size=(3, 1), justification='right'),
        sg.Input("Placeholder name", size=(50, 1), disabled=True),
        sg.Combo(options, size=(20, 1))
    ]
    return row_layout

rows = [row(i) for i in range(20)]

layout = [
    [sg.Column(rows, scrollable=True, size=(None, 200))],
]
window = sg.Window('Demo Window', layout)

while True:
    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break

window.close()

Im using disabled Input fields here as I think stylistically they look better next to the combo box in this context but also for the ability to copy+paste!

What would an ideal "Row" of your table look like? I mean in terms of Text, Input, Combo, etc?

For this example I think just text and a combo box would work for me but using my example above I dont see why this couldn't be expanded to any element the PySimpleGui which is quite nice! Edit: I suppose you could also add a button element here to trigger the above picker, which may even be quicker than a combo if you end up with a lot of options!

Sadly time is a poor metric of capability!

Evidently not! You whipped out a sample program in an hour. Very nice!

I'm using disabled Input fields here as I think stylistically they look better next to the combo box in this context but also for the ability to copy+paste!

See... those 2 years were not wasted. This isn't something a complete beginner with PySimpleGUI would have thought to have done. Way to go! You're doing great.

image