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.43k stars 1.83k forks source link

[Bug] scrollable column with expand=True is not scrollable outside of content #5338

Closed milahu closed 2 years ago

milahu commented 2 years ago

continue https://github.com/PySimpleGUI/PySimpleGUI/issues/1779#issuecomment-1093052916

tldr:

Screenshot_2022-04-08_19-12-58 psg bug scrollable column expand

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

Bug


Operating System

linux

PySimpleGUI Port (tkinter, Qt, Wx, Web)

tkinter


Versions

Python version (sg.sys.version)

3.9

PySimpleGUI Version (sg.__version__)

32d5481f5097fdbfb151927956023cbde377ffb5

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


Your Experience In Months or Years (optional)

Years Python programming experience

Years Programming experience overall

Have used another Python GUI Framework? (tkinter, Qt, etc) (yes/no is fine)

Anything else you think would be helpful?


Troubleshooting

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

Detailed Description

Code To Duplicate

#! /usr/bin/env python

import PySimpleGUI as sg

column_layout = []
for i in range(0, 20):
    column_layout.append([sg.Text("test")],)

layout = [
    [sg.Column(
        column_layout,
        scrollable=True,
        vertical_scroll_only=True,
        expand_x=True,
    )],
]

window = sg.Window('test', layout, size=(400, 200))
event, values = window.read()
window.close()

Screenshot, Sketch, or Drawing

Screenshot_2022-04-08_19-12-58 psg bug scrollable column expand


Watcha Makin?

If you care to share something about your project, it would be awesome to hear what you're building.

contributing to https://github.com/FHPythonUtils/Cli2Gui

Screenshot_2022-04-08_18-48-00 psg bug scrollable column expand

more interesting: ansi terminal emulator widget for PySimpleGUI : ) see https://github.com/FHPythonUtils/Cli2Gui/pull/9

jason990420 commented 2 years ago

Debug information

Following binding removed in __init__ of class TkScrollableFrame.

        self.unhookMouseWheel(None)
        self.TKFrame.bind("<Enter>", self.hookMouseWheel)
        self.TKFrame.bind("<Leave>", self.unhookMouseWheel)

and binding with these direcly, the element is the argument passed to __init__ of class TkScrollableFrame, then it work.

        if element.Scrollable:
            self.canvas.bind_all('<4>', self.yscroll,  add='+')
            self.canvas.bind_all('<5>', self.yscroll,  add='+')
            self.canvas.bind_all("<MouseWheel>", self.yscroll,  add='+')
            if not element.VerticalScrollOnly:
                self.canvas.bind_all("<Shift-MouseWheel>", self.xscroll, add='+')

        self.bind('<Configure>', self.set_scrollregion)

Not sure why mousewheel binding only if mouse enter the Column in PySimpleGUI.py ?

PySimpleGUI commented 2 years ago

Not sure why mousewheel binding only if mouse enter the Column in PySimpleGUI.py ?

I've not spent any time yet looking at this.

We made changes some time back so that bind of mouse scrollwheel only happens when the mouse enters the element. This was critical for situations when there was embedded elements. If a listbox was inside of a Column, then only the listbox should scroll, not the entire column.

I've not added the new ttk scrollbars to Columns yet as I'm aware of these scroll problems. I want to get through the new ttk stuff first and then I'll come back to these column scoll problems.

PySimpleGUI commented 2 years ago

Again, I'm not well-versed on the particulars here, but wanted to show this example in case it's at all relevant.

The red text element is not in the Column element and this when scrolled over it will not scroll the column.

When the mouse is over the Listbox, only the listbox is scrolled, etc.

pycharm64_Q7y5bcHhTR

PySimpleGUI commented 2 years ago

Now that ttk scrollbars are futher along, I'm marking this urgent was I want to make sure it gets addressed in the upcoming release.

PySimpleGUI commented 2 years ago

Finally got working on this final problem for the 4.60.0 release.

I HOPE I got this right as it impacts SO many programs potentially.

It seems like the big problem was binding to the Frame rather than binding to the Canvas.

The sample program provided by @milahu works now. Thank you for providing something that was elegantly simple to show the problem!

The Expanded Column Example

import PySimpleGUI as sg

column_layout = []
for i in range(0, 20):
    column_layout.append([sg.Text("test")],)

layout = [
    [sg.Column(
        column_layout,
        scrollable=True,
        vertical_scroll_only=True,
        expand_x=True,
    )],
]

window = sg.Window('test', layout, size=(400, 200))
event, values = window.read()
window.close()

Exapanded column

The Nested Scrollable Elements Problem

The single column in a layout I'm not concerned about so much.... it's nested scrollable elements that is the bigger issue that makes my stomach ache.

I used this test harness to give things a try. It's not perfect, but it does seem to function correctly most of the time. I welcome additional help on debugging that scrollable column code. It may be a tkinter issue under it all with enter and leave events.

It scares me to make this change, but I'll be brave and give it a go!

import PySimpleGUI as sg

"""
    Demonstrates how to use the Window.layout_extend method.
    Layouts can be extended at the Window level or within any container element such as a Column.
    This demo shows how to extend both.
    Note that while you can extend, add to, a layout, you cannot delete items from a layout.  Of course you
    can make them invisible after adding them.

    When using scrollable Columns be sure and call Column.visibility_changed so that the scrollbars will
        be correctly reposititioned

    Copyright 2020, 2022 PySimpleGUI
"""

col2 = sg.Column([[sg.Multiline('\n'.join([str(x) for x in range(40)]), size=(20,10), no_scrollbar=False), sg.T('Some text')]], scrollable=True, size_subsample_height=2)
layout = [[sg.Text('My Window')],
          [sg.Text('Click to add a row inside the Frame'), sg.B('+', key='-ADD FRAME-')],
          [sg.Text('Click to add a row inside the Column'), sg.B('+', key='-ADD COL-')],
          [sg.Text('Click to add a row inside the Window'), sg.B('+', key='-ADD WIN-')],
          [sg.Frame('Frame', [[sg.T('Frame')]], key='-FRAME-')],
          [sg.Col([[sg.T('Column')], [col2]], scrollable=True, key='-COL-', s=(400, 400))],
          [sg.Input(key='-IN-'), sg.Text(size=(12, 1), key='-OUT-')],
          [sg.Button('Button'), sg.Button('Exit')]]

window = sg.Window('Window Title', layout)

i = 0

while True:  # Event Loop
    event, values = window.read()
    print(event, values)
    if event in (sg.WIN_CLOSED, 'Exit'):
        break
    if event == '-ADD FRAME-':
        window.extend_layout(window['-FRAME-'], [[sg.T('A New Input Line'), sg.I(key=f'-IN-{i}-')]])
        i += 1
    elif event == '-ADD COL-':
        window.extend_layout(window['-COL-'], [[sg.T('A New Input Line'), sg.I(key=f'-IN-{i}-')]])
        window.visibility_changed()
        window['-COL-'].contents_changed()
        i += 1
    elif event == '-ADD WIN-':
        window.extend_layout(window, [[sg.T('A New Input Line'), sg.I(key=f'-IN-{i}-')]])
        i += 1
window.close()

Nested Elements

As you can see, there is a little struggling going on to get the mouse scrollwheel to function correctly in every case.

PySimpleGUI commented 2 years ago

The above code is 4.59.0.45 that's on GitHub.

I would like to make this the 4.60.0 release if at all possible.

@jason990420 do you have an opinion on this one? Are we in "Good Enough" territory? As I said, it's a fear producing set of changes, but this 4.60.0 ship needs to sail and soon.

jason990420 commented 2 years ago

I don't have exact conclusion for it, but it looks something strange, not yet do all the tests. Tell the truth, not sure how many items or what items to do the test.

For example:

python_ewOnO9Lh5l

PySimpleGUI commented 2 years ago

It is meant to be not scrollable at first because the Column isn't "full"... it doesn't have enough things in it to make a scrollable area. Only after the input elements are added that it should scroll.

I do see what you mean by scrollable using the scrollbar even though it doesn't with the wheel.

There are so many weird edge cases... this is why I'm asking for an opinion. It'll drive us CRAZY to try to get all of the edge cases at this point I think. I dunno, maybe I'm wrong about this and being lazy, but I get a sense these have always been there.

PySimpleGUI commented 2 years ago

This was released in 4.60.0. There may be some edge cases such as those that Jason pointed out, but I think for the most part it should function really well.