5

I am building a simple GUI with pysimplegui and want to right-justify a button inside a frame. I have found details on how to do this with text but not with buttons.

For example, I would like the button below to snap to the right side of the frame with the groove around it. I want this:

enter image description here

To look more like this:

enter image description here

But without having to add in a manually adjusted blank text element to get it close as this often doesn't line up correctly (note the commented out sg.Text("", size=(22, 1)) line below).

import sys
import PySimpleGUI as sg

sg.theme("Light Blue 2")
layout = [
    [
        sg.Text("Target folder", size=(9, 1)),
        sg.InputText(default_text="Choose a folder...", size=(59, 1)),
        sg.FolderBrowse(),
    ],
    [
        sg.Frame(
            layout=[
                [
                    sg.Text("First parameter", size=(15, 1)),
                    sg.InputText(default_text="2", size=(3, 1),),
                ],
                [
                    sg.Text("Second parameter", size=(15, 1)),
                    sg.InputText(default_text="8", size=(3, 1),),
                    # sg.Text("", size=(22, 1)),
                    sg.Submit("A nice button", size=(23, 1)),
                ],
                [sg.ProgressBar(1, orientation="h", size=(50, 20))],
            ],
            title="Cool subpanel",
            relief=sg.RELIEF_GROOVE,
        )
    ],
]
window = sg.Window("Test window", layout)

while True:
    event, values = window.read()
    if event == "Cancel" or event is None:
        sys.exit()

Salvatore
  • 10,815
  • 4
  • 31
  • 69

3 Answers3

2

You can split the contents of your framed section into two sg.Columns, then set expand_x to True, element_justification to right, and vertical_alignment to bottom which will get your positioning.

import sys
import PySimpleGUI as sg

sg.theme("Light Blue 2")

l_col = sg.Column(
    [
        [
            sg.Text("First parameter", size=(15, 1)),
            sg.InputText(default_text="2", size=(3, 1)),
        ],
        [
            sg.Text("Second parameter", size=(15, 1)),
            sg.InputText(default_text="8", size=(3, 1)),
        ],
    ]
)
r_col = sg.Column(
    [[sg.Submit("A nice button", size=(23, 1))]],
    element_justification="right",
    vertical_alignment="bottom",
    expand_x=True,
)

layout = [
    [
        sg.Text("Target folder", size=(9, 1)),
        sg.InputText(default_text="Choose a folder...", size=(59, 1)),
        sg.FolderBrowse(),
    ],
    [
        sg.Frame(
            layout=[
                [l_col, r_col],
                [sg.ProgressBar(1, orientation="h", size=(50, 20))],
            ],
            title="Cool subpanel",
            relief=sg.RELIEF_GROOVE,
        )
    ],
]
window = sg.Window("Test window", layout)

while True:
    event, values = window.read()
    if event == "Cancel" or event is None:
        sys.exit()

enter image description here

The sizings are a little off on macOS it seems, but this should do what is needed.

Alex
  • 6,610
  • 3
  • 20
  • 38
  • 1
    This works. Adding `pad=(0, 0)` to each column gets rid of the unwanted spacing added by the columns themselves. – Salvatore Aug 25 '21 at 22:43
2

Your question just missed a release of PySimpleGUI that makes this operation trivial.

One problem with StackOverflow is - "nothing dies"... including old solutions. It's a genuine problem that I've yet to find a solid solution for.

This technique was released in Sept 2021 in version 4.48.0 and uses the, then new, Push element. As the name implies, the Push will push around elements. By putting one between elements, it will push the elements apart.

Here's your code with a Push added just before the button you want right justified.

import sys
import PySimpleGUI as sg

sg.theme("Light Blue 2")

layout = [
    [
        sg.Text("Target folder", size=(9, 1)),
        sg.InputText(default_text="Choose a folder...", size=(59, 1)),
        sg.FolderBrowse(),
    ],
    [
        sg.Frame(
            layout=[
                [
                    sg.Text("First parameter", size=(15, 1)),
                    sg.InputText(default_text="2", size=(3, 1),),
                ],
                [
                    sg.Text("Second parameter", size=(15, 1)),
                    sg.InputText(default_text="8", size=(3, 1),),
                    sg.Push(),
                    sg.Button("A nice button", size=(23, 1)),
                ],
                [sg.ProgressBar(1, orientation="h", size=(50, 20))],
            ],
            title="Cool subpanel",
            relief=sg.RELIEF_GROOVE,
        )
    ],
]
window = sg.Window("Test window", layout)

while True:
    event, values = window.read()
    if event == "Cancel" or event is None:
        sys.exit()


And this is the result: enter image description here

Note (that's not super important) - I've replaced Submit with Button as using Submit is perhaps confusing. Submit is nothing more than a function that returns a Button element with the text "Submit". It doesn't do anything special and in fact provides less parameter perhaps than just Button.

Mike from PSG
  • 5,312
  • 21
  • 39
  • size parms can be abbreviated for many elements now too. It can be an INT rather than tuple when height is 1.. `size=9` is the same as `size=(9,1)` in later releases. The docstrings tell you if the element you're using can use an int. Cuts down on clutter in the layout. If you really want to go pro and abbreviate, `s` can be used instead of `size` as a parameter in all elements. `s=9` is `size=(9,1)` in 3 char instead of 10. – Mike from PSG May 20 '22 at 10:14
  • Turns out, you can push from *both* sides and center your element. :) For example: `layout[...,[sg.Push(), sg.Text('Checks', size=(10,1)), sg.Push()]` This will place the word *Checks* in the center of the window. – fbicknel Feb 05 '23 at 23:59
  • 1
    Righto! The Cookbook's section on alignment has examples including centering and this one from the eCookbook https://pysimplegui.trinket.io/demo-programs#/layouts/push-and-vpush-elements – Mike from PSG Feb 06 '23 at 19:35
0

Replacing the button in-line with a column element with zero padding also works, and requires less code modification.

For older versions of PySimpleGUI, the expand_x parameter is not defined so you have to assign a key to the column and call the expand method explicitly:

import sys
import PySimpleGUI as sg

sg.theme("Light Blue 2")

layout = [
    [
        sg.Text("Target folder", size=(9, 1)),
        sg.InputText(default_text="Choose a folder...", size=(59, 1)),
        sg.FolderBrowse(),
    ],
    [
        sg.Frame(
            layout=[
                [
                    sg.Text("First parameter", size=(15, 1)),
                    sg.InputText(default_text="2", size=(3, 1),),
                ],
                [
                    sg.Text("Second parameter", size=(15, 1)),
                    sg.InputText(default_text="8", size=(3, 1),),
                    sg.Column(
                        [[sg.Submit("A nice fat button", size=(23, 1))]],
                        element_justification="right",
                        expand_x=True,
                        key="c1",
                        pad=(0, 0),
                    ),
                ],
                [sg.ProgressBar(1, orientation="h", size=(50, 20))],
            ],
            title="Cool subpanel",
            relief=sg.RELIEF_GROOVE,
        )
    ],
]
window = sg.Window("Test window", layout)
# window['c1'].expand(True, False, False) # use this when 'expand_x' flag is not available

while True:
    event, values = window.read()
    if event == "Cancel" or event is None:
        sys.exit()

enter image description here

Salvatore
  • 10,815
  • 4
  • 31
  • 69