Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Column scroll distance not updated until window is manually resized #38

Open
sfreemire opened this issue Oct 14, 2024 · 2 comments
Open
Labels
bug Something isn't working question Further information is requested

Comments

@sfreemire
Copy link

sfreemire commented Oct 14, 2024

I'm having trouble with using tabs or the "visible" property of frames within a column that has scrolling enabled.

I'm trying to create a layout that fits vertically on the screen when the app is started, so I made some of the frames invisible, and allow them to be made visible when needed. I've tried tabs and the "visible" property, but the scrollbars of the containing column are not updating correctly.

If the frames are hidden to begin with, the main column scrollbars are set for the minimized content, and they don't update when the content is maximized. If the frames are visible to begin with, the scrollbars are set correctly - but when the frames are minimized they reset to the smaller size, and when the frames are maximized, they don't update again.

For some reason, the scrollbars reset when minimizing sections, but not when maximizing sections.

If you maximize sections and then manually resize the window by any amount, the scrollbars will reset to the current view. But this does not happen when programmatically resizing the window, so it's not a workaround.

import FreeSimpleGUI as sg

def collapse(title, layout, key):
    """
    Helper function that creates a Column that can be later made hidden, thus appearing "collapsed"
    :param layout: The layout for the section
    :param key: Key used to make this seciton visible / invisible
    :return: A pinned column that can be placed directly into your layout
    :rtype: sg.pin
    """
    # return sg.pin(sg.Column(layout, key=key))
    return sg.pin(sg.Frame(title, layout, border_width=6,
        relief="ridge", expand_x=True, visible=False, key=key))

test_1_multiline = [
   [sg.Sizer(h_pixels=3),
    sg.Multiline(size=(83, 13),
    font=('Courier', 14, 'bold'), background_color='#fdfdfc',
    expand_x=True, disabled=True,
    no_scrollbar=True, key='TEST_1_MLINE'),
    sg.Sizer(h_pixels=3)],
   [sg.Sizer(h_pixels=0, v_pixels=5)]
]

test_1_col1 = [
   [sg.Frame('Test Frame 1',
    test_1_multiline, expand_x=True, border_width=1, relief='ridge',
    font=('Helvetica', 13, 'bold'), title_location=sg.TITLE_LOCATION_TOP)]
]

test_1_col2 = [
   [sg.Text('Test text 1')]
]

test_1_layout = [
   [sg.Column(test_1_col1, element_justification='centered',
    expand_x=True)],
   [sg.Column(test_1_col2, expand_x=True)]
]

sec1 = sg.Column(
         [
            [sg.T(sg.SYMBOL_RIGHT, enable_events=True, k='OPEN_TEST1SEC'),
             sg.T('Binary Operations', enable_events=True,
                  font=(None, 14,"bold"), k='OPEN_TEST1SEC_TEXT')],
            [collapse('', test_1_layout, 'TEST1SEC'), sg.Sizer(h_pixels=5)]
         ],
         key='SEC1_KEY'
      )

# App Control Button Frame
sec5 = sg.Frame("",
   [
      [
         sg.Column(
            [
               [
                  sg.Button('Example', font='Helvetica 11', key='-EXAMPLE-'),
                  sg.Button('Clear', font='Helvetica 11', key='-CLEAR-'),
                  sg.Text('', text_color='red', font='None 14 bold',
                          key='-BTN_MESSAGES-'),
                  sg.Push(),
                  sg.Button('About', font=('Helvetica', 12)),
                  sg.Button(' Exit ', font=('Helvetica', 12, 'bold'))
               ]
            ],
            expand_x=True,
         )
      ]
   ],
   expand_x=True,
   border_width=6,
   relief="ridge",
)

page_layout = [
      [sec1],
      # [sec2],
      # [sec3],
      # [sec4],
      [sg.Sizer(h_pixels=5), sec5, sg.Sizer(h_pixels=10)],
      [sg.Sizer(v_pixels=8)]
]

layout = [
            # [results_frame],
            [sg.Column(page_layout,
               expand_x=True,
               expand_y=True,
               scrollable=True,
               # vertical_scroll_only=True,
               key='LAYOUT_COLUMN'),
            ]
         ]

# window = sg.Window('IP MAP Calculator', layout, size=(796, 500), 
# window = sg.Window('IP MAP Calculator', layout, size=(771, 200), 
window = sg.Window('IP MAP Calculator', layout, size=(700, 200), 
            resizable=True, enable_close_attempted_event=True,
            finalize=True,
            location=sg.user_settings_get_entry('-location-', (None, None))) # resizable=True, # size=(777, 1000)

# Main Event Loop
# opened1, opened2, opened3 = False, False, False
opened1 = False
count = 0

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

   if event in (' Exit ', sg.WINDOW_CLOSE_ATTEMPTED_EVENT):
      # Save screen location when closing window
      sg.user_settings_set_entry('-location-', window.current_location())
      break

   if event.startswith('OPEN_TEST1SEC'):
      opened1 = not opened1
      window['OPEN_TEST1SEC'].update(sg.SYMBOL_DOWN if opened1 else sg.SYMBOL_RIGHT)
      window['TEST1SEC'].update(visible=opened1)
      window['LAYOUT_COLUMN'].contents_changed() # per Controls > Column > scrollable - Description
      # a, b = window.size
      # window.size = (700, b + 1)
      # print(window.size)
      # window.refresh()

# print(window.size) # on any event

window.close()
Scroller_Size_Test.mov

macOS Sonoma 14.7
Python 3.12.4
FSG Version: 5.1.1
tkinter version 8.6

@spyoungtech spyoungtech added the bug Something isn't working label Oct 15, 2024
@spyoungtech
Copy link
Owner

Thank you for the very detailed report and the recording. I think it is clear to me what the unexpected/expected behaviors are, though the cause is not immediately apparent. Tentatively, I will call this a bug.

At this moment, I can't make any promises as to timelines for a fix, but I will investigate as my time allows and try to come up with a fix or workaround. I'll also be happy to collaborate with any other interested people to investigate and/or review PRs that address this.

Thanks again for the report!

@spyoungtech spyoungtech added the question Further information is requested label Oct 15, 2024
@sfreemire
Copy link
Author

sfreemire commented Oct 17, 2024

Possibly helpful info:

I just searched through the PSG issues and found #5017 that suggested adding both of these after changing the scrollable column's contents (in my case, changing visibility of pinned frames):

window.refresh()
window['LAYOUT_COLUMN'].contents_changed()

With my first example script (above), this only worked if there was only one element that changed size, but not if there were multiple elements that changed size.

After more testing, adding these lines is giving mixed results. I was able to create one layout that seems to work when using them. The problem may have to do with the depth of nesting in container elements within the top-level, scrollable column.

Layout that is working better:

import FreeSimpleGUI as sg

def collapse(num):
   return [
        sg.Column(
            [
                [sg.T(sg.SYMBOL_RIGHT, enable_events=True,
                    k=f'OPEN_FRAME_{num}'),
                 sg.T(f'Frame {num}', enable_events=True,
                    font=(None, 14, "bold"), k=f'OPEN_FRAME_{num}_TEXT')
                ],
                [sg.pin(sg.Frame(f'Frame {num}',
                                 [[sg.T(f'Section {num} text')]],
                                   border_width=6, relief="ridge",
                                   expand_x=True, visible=False,
                                   key=f"FRAME_{num}")
                    )
                ]
            ]
        )
   ]

frames_layout = [ collapse(i) for i in range(1, 5) ]

scroll_layout = [
    [sg.Column(frames_layout,
     scrollable=True,
     vertical_scroll_only=True,
     expand_y=True,
     key='SCROLL')]
]

main_column = [
    [scroll_layout]
]

layout = [
    [sg.Text('Window line 1')],
    [sg.Text('Window line 2')],
    [main_column],
    [sg.Button(' + '), sg.Push(), sg.Button(' Exit ')]
]

# Open/close frames
opened1, opened2, opened3, opened4 = False, False, False, False

def opened(idx):
    if idx == 1:
        opened = opened1
    elif idx == 2:
        opened = opened2
    elif idx == 3:
        opened = opened3
    elif idx == 4:
        opened = opened4

    window[f'OPEN_FRAME_{idx}'].update(sg.SYMBOL_DOWN if opened
                                       else sg.SYMBOL_RIGHT)
    window[f'FRAME_{idx}'].update(visible=opened)
    window.refresh()
    window['SCROLL'].contents_changed()

window = sg.Window('Test Window', layout,
                   enable_close_attempted_event=True,
                   location=sg.user_settings_get_entry('-location-', (None, None)),
                   resizable=True, finalize=True
                  )

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

    if event in (' Exit ', sg.WINDOW_CLOSE_ATTEMPTED_EVENT):
       # Save screen location when closing window
       sg.user_settings_set_entry('-location-', window.current_location())
       break

    if event == ' + ':
        window.extend_layout(window['SCROLL'], [[sg.Text(f"Extra Text Line {cnt}")]])
        cnt += 1
        window.refresh()
        window['SCROLL'].contents_changed()

    if event.startswith('OPEN_FRAME_1'):
        opened1 = not opened1
        opened(1)

    if event.startswith('OPEN_FRAME_2'):
        opened2 = not opened2
        opened(2)

    if event.startswith('OPEN_FRAME_3'):
        opened3 = not opened3
        opened(3)

    if event.startswith('OPEN_FRAME_4'):
        opened4 = not opened4
        opened(4)

    print(sg.DEFAULT_FONT)

window.close()

I'm going to try and add all of contents of my app layout into this template, and see how it works. If it works, I may not need an open issue.

Thank you,
Scott

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants