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.
https://www.PySimpleGUI.com
Other
13.36k stars 1.84k forks source link

Possible Bug: Frames vertically centered #3293

Closed mconger closed 4 years ago

mconger commented 4 years ago

Type of Issues (Enhancement, Error, Bug, Question)

Possible Bug in Frame behavior

Operating System

Linux Mint 19.3 MATE, kernel 5.4.0-42-generic

Python version

Python 3.6.9

PySimpleGUI Port and Version

4.28.0 Released 3-Aug-2020 <module 'PySimpleGUI' from '/home/markc/.local/lib/python3.6/site-packages/PySimpleGUI/init.py'>

Your Experience Levels In Months or Years

1 month: Python programming experience Decades but not as a professional developer: Programming experience overall Dabbled with tkinter a few days until finding PSG: Have used another Python GUI Framework (tkinter, Qt, etc) previously (yes/no is fine)?

You have completed these steps:

Description of Problem / Question / Details

When I put two Frames side by side in a window layout the frame with less height gets centered vertically in the window. If using two Columns the columns are top justified. A shorter Frame beside a Column, and the Frame is centered vertically. There are no vertical justification or alignment parameters in the call reference, just left, center, and right. How can I control this? I prefer the top jusitification like Columns display but the adjustments such as title that Frame allows is really what I need.

Code To Duplicate

import PySimpleGUI as sg
print(sg)
print(sg.version)

## Paste your code here
import PySimpleGUI as sg
sg.theme('LightBlue')   # I like this one! 
tallerside = [[sg.Text('40 x 20', background_color='lightblue', size=(40,20))], [sg.Button('Quit')]]
shorterside = [[sg.Text('40 x 16. Will be v centered.', background_color='lightgreen', size=(40,16))], [sg.Button('Exit')]]
layout = [[ sg.Frame('TALLER', tallerside, font='Any 12', title_color='DarkBlue'), sg.Frame('SHORTER', shorterside, font='Any 12', title_color='DarkGreen'),]]
window = sg.Window('Frame V Alignment Bug Demo', layout)
while True:
    event, values = window.read()
    if event in (None, 'Quit', 'Exit'):
        break
window.close()
PySimpleGUI commented 4 years ago

There is no control for this. Vertical alignment isn't controllable. It can be added as an enhancement. There's no easy hack / workaround that I can think of at this time.

I'm looking into the problem of column justification today so I'll be in the part of the code that controls the layout. I'll look at this problem as well.

mconger commented 4 years ago

Thank you for such a quick response.

This issue is not front burner priority for me. I am still very new to PSG and love it. Being so new I wanted to confirm the vertical alignment wasn't just something I was doing wrong.

If vertical alignment of certain PSG components could be a future addition I think that would be helpful. And I'll leave it at that. It's not a bug as I thought initially.

mconger commented 4 years ago

I forgot to include a screen capture in the original post text so including it here for future reference. I have a vertical separator and some additional text in this one which differs slightly from my example code above. Note, the separator doesn't affect the issue if removed.

Screenshot-psg-frame-bug

jason990420 commented 4 years ago

In GUI, the most problem I encounter is the alignment between elements. One for alignment of position, another one for alignment of size.

It seems no simple relationship between width/height of the font and pixel in screen, so most of time, I must make some manual fine-tuning for alignment. Of course, it will be great for any element able to be aligned by some reference position and set to any size.

Maybe it is not easy to change the source code to provide this function, but one simple solution for you here.

Example like this, sg.Canvas(size=(10, 69)), here 69 pixels added and no reason for it, just tuning.

import PySimpleGUI as sg

sg.theme('LightBlue')   # I like this one!

tallerside = [
    [sg.Text('40 x 20', background_color='lightblue', size=(40,20))],
    [sg.Button('Quit')],
]

shorterside = [
    [sg.Text('40 x 16. Will be v centered.', background_color='lightgreen', size=(40,16))],
    [sg.Canvas(size=(10, 69))],
    [sg.Button('Exit')],
]

layout = [
    [sg.Frame('TALLER', tallerside, font='Any 12 bold', title_color='DarkBlue'),
     sg.VerticalSeparator(),
     sg.Frame('SHORTER', shorterside, font='Any 12 bold', title_color='DarkGreen'),]]

window = sg.Window('Frame V Alignment Bug Demo', layout)

while True:

    event, values = window.read()

    if event in (None, 'Quit', 'Exit'):
        break

window.close()

image

PySimpleGUI commented 4 years ago

I could SWEAR that both Columns and Frames behaved like "normal" layouts where the elements are placed at the top of each layout.

For example, the main test harness has a table and a tree on the same row in a Frame. I thought the headers always lined up at the top, but it's clear they're not. I tested back to release 4.17.0 and it still didn't align them to the top.

image

I changed it to a column for this test, but the result is the same. image

I guess I've simply forgotten that elements are all vertically centered on a row. This is a text and a listbox running on version 4.11.0

image

Same layout running on current code shows the same kind of alignment

image

PySimpleGUI commented 4 years ago

One way through this is to make it possible to set the alignment in Columns and Frames and leave the window alignment at centered. This would allow you to add a column to get a different kind of alignment. This would need to be a new enhancement.

I'm just about done with the bug fix for elements alignments inside columns (the other bug)

jason990420 commented 4 years ago

@PySimpleGUI

I didn't find you set the option anchor in pack method for sg.Frame, default value of anchor is CENTER. The same for sg.Text, not sure how about other elements.

Is it the reason why Frame aligned center ?

[Edit] I add option anchor=tk.N into pack method for sg.Frame, then aligned top. Just for column alignment.

PySimpleGUI commented 4 years ago

I've added a new parameter to Column called vertical_alignment. It can be top, bottom, center. The default is basically whatever tkinter thinks it should be (like now) which is centered it would appear.

If you want to force an element to be aligned in a particular way, then place it in a column element and set the vertical alignment for the column

This is the test harness I am using for the testing of the fix for element_justification. I also used it to demonstrate this new parameter.

image

import PySimpleGUI as sg

def main():

    radio_col = sg.Col([[sg.T('Column')],
                        [sg.R('Radio1',1), sg.R('Radio2', 1)]], key='c4', element_justification='l')

    layout = [[sg.T('*'*150)],
              [radio_col],
              [sg.Text('Text'), sg.Button('Button')],
              [sg.Text('On row with listbox'), sg.LB(list(range(6)), size=(5,4))],
                [sg.Col([[sg.Text('On row with listbox')]], vertical_alignment='t', pad=(0,0)), sg.LB(list(range(6)), size=(5,4))],
              [sg.Button('Next Color', key='btnNext')]]

    main_window = sg.Window('1 Pixel Graph Troubleshooter', layout, resizable=True, element_justification='c', finalize=True)

    while True:
        event, _ = main_window.read()
        if event in (None, 'Quit'):   # if user closes window or clicks Quit
            break

main()

Now, at least for the tkinter port, we'll be able to create vertical alignment by placing elements to be aligned into a Column element. The Column has become a bit of a catchall for a lot of these settings. It's a way of achieving the result without adding an alignment parameter to every element.

PySimpleGUI commented 4 years ago

You care correct Jason that all of the elements have no anchor set so that they center align. This is why the Frames aligned the way they did. It's how it's always been.

By adding a parameter to Column it's now possible to change that. I can't force frames to be top aligned at this point with all the existing code out there working the way it is.

jason990420 commented 4 years ago

One more alignment option for sg.Frame and default value is tk.CENTER, should all existing code work the same ?

PySimpleGUI commented 4 years ago

I was a little concerned about adding it to Frame thinking that it may be misleading, but I guess it's no more confusing to add it there as well. What this setting does not do is change the alignment of everything inside in a recursive way. It merely aligns that element. The Column element is being used as an alignment mechanism that will work on all other elements. If you want an element's alignment to be changed, you add it to a Column and set the alignment.

I guess there's no harm done in adding it to the Frame too? Part of the hesitation is to make sure that it can work across all of the ports. That's always a concern when I start adding parameters to elements, so I tend to limit the changes as much as possible.

I'll add it to Frame as well. If there's a portability problem, then I'll address it then.

PySimpleGUI commented 4 years ago

4.28.0.9 has vertical_alignment added to the Frame element. Defaults to None / not set just as it is today.

mconger commented 4 years ago

Wow. I step out to run some errands for a couple hours and come home to find the issue not only with a workaround but actual code change in PSG! How cool is that? LOL

Thank you. I'm going to go try it now after updating PSG.

PySimpleGUI commented 4 years ago

New Vertical Alignment Layout Helper Functions

While working on a problem with Column element justification, I added the ability to vertically align Column elements. The result is that if you want to vertically align a particular element, you can place it inside of a Column, and then vertically align the Column. It's not the most compact way of doing things, but it gets the designed result nicely. As long as you set the pad=(0,0) on the Column, you won't know it's there.

Additionally, to make it even easier to use on a single element basis, 3 new layout helper functions were added vtop, vcenter and vtop. Use these like the pin helpful function today.

By default, layouts CENTER the elements on a row. This is how the tkinter port has always worked. Until now it's not been possible to vertically align.

Example layout using the new calls:

import PySimpleGUI as sg

def main():

    layout = [[sg.Text('Text'), sg.Button('Button')],
              [sg.vtop(sg.Text('On row with listbox')), sg.LB(list(range(6)), size=(5,4)), sg.vbottom(sg.Text('On row with listbox')),],
              [sg.Button('Ok'), sg.B('Quit')]]

    window = sg.Window('Vertical Layout Example', layout, )

    while True:
        event, values = window.read()
        if event in (None, 'Quit'):   # if user closes window or clicks Quit
            break

main()

It produces this window

image

mconger commented 4 years ago

I would like to update PSG to the 4.28.0.9 release to get the vertical alignment mods but pip3 doesn't see anything beyond 4.28.0 and the documentation about updating via github says there is a problem going that route with Linux, and I'm using Linux.

Is the documentation still correct about this? If so, is there a manual method that is possible without causing hiccups for later updates via pip3?

PySimpleGUI commented 4 years ago

The upgrade using sg.main() should work on Linux now.

But, if you want to take the safest approach to temporarily use the latest GitHub release then download the file PySimpleGUI.py from GitHub and place that file in your application's folder. Then when it imports, it will import the downloaded copy.

mconger commented 4 years ago

I was able to upgrade via the test harness. Very slick and no problems. LOVE the new tag for Frame to adjust vertical alignment.