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

PageLayout on_touch_down doesn't check for length of self.children. Can get IndexError: list index out of range. #8563

Closed
AJRepo opened this issue Jan 15, 2024 · 3 comments

Comments

@AJRepo
Copy link

AJRepo commented Jan 15, 2024

Software Versions

  • Python: Python 3.11.6
  • OS: Debian
  • Kivy: 2.2.1-2
  • Kivy installation method: dpkg and git

Describe the bug

Using PageLayout with on_touch_down() can generate an IndexError: list index out of range and crash the program using just standard user interactions.

Expected behavior
A clear and concise description of what you expected to happen.

No crash.

To Reproduce
A short, runnable example that reproduces the issue with latest kivy master.

  1. Create a simple PageLayout system
  2. Add the following code to your main.py
class MyPager(PageLayout):
    """See .kv file for details"""

    def on_touch_down(self, touch): 
        super().on_touch_down(touch)
        if touch.spos[0] > .95:
            if self.page == 1:
                self.page = 0
            else:
                self.page = 1
  1. instead of just clicking with a mouse, click-drag the mouse to drag out the page. The page will, instead of stopping a bit before the left side, continue and leave a blank on the right side.
  2. Mouse Click one more time
  3. Crash

Code and Logs and screenshots

Python File:

rom kivy.app import App
from kivy.lang import Builder
from kivy.uix.pagelayout import PageLayout
from kivy.uix.boxlayout import BoxLayout

KV = """
MyPager:

<MyPager>:
    border: '25dp'
    PageOne:
        Widget:
        Button:
            text: "page1"
        Widget:
    PageTwo:
        Widget:
        Button:
            text: "page2"
        Widget:
"""
class MyPager(PageLayout):
    """See .kv file for details"""

    def on_touch_down(self, touch):
        #Edit:  having this line below was a key part of the the problem. Updating ticket for future readers
        super().on_touch_down(touch)

        print("In main.py:", self)
        print("in main.py page=", self.page)
        print("In main.py: pos=",touch.pos)
        if touch.spos[0] > .95:
            if self.page == 1:
                self.page = 0
            elif self.page == 0:
                self.page = 1
            #Edit:  NOT return True was a key part of the the problem. Updating ticket for future readers
            return True

        #Edit:  NOT having this return was a key part of the the problem. Updating ticket for future readers
        return super().on_touch_down(touch)

class PageOne(BoxLayout):
    """See .kv file for details"""

class PageTwo(BoxLayout):
    """See .kv file for details"""

class TestMyPager(App): #pylint: disable=too-many-instance-attributes
    """docstring"""

    def build(self):
        """docstring"""
        return Builder.load_string(KV)

TestMyPager().run()

Additional context
Add any other context about the problem here.

I have fixed this out of range issue by adding a check on the list length and will submit a pull request shortly.

AJRepo added a commit to AJRepo/kivy that referenced this issue Jan 15, 2024
 PageLayout on_touch_down doesn't check for length of self.children.
Can get IndexError: list index out of range. kivy#8563
@AJRepo
Copy link
Author

AJRepo commented Jan 15, 2024

On Startup: the variable page=0, however with click_drag it changes to page=2 even though there are only two pages defined (0 and 1)

Looks like the root of the issue might be in on_touch_move which changes page , but independent of that issue - there should be a range check in on_touch_down which this PR fixes.

@ElliotGarbus
Copy link
Contributor

ElliotGarbus commented Jan 16, 2024

Edit: The on_touch_down() method needs to be changed to consume the touch when the touch_down is accepted.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.pagelayout import PageLayout


kv = """
MyPager:

<MyPager>:
    Button:
        text: "p1"
    Button:
        text: "p2"
"""


class MyPager(PageLayout):

    def on_touch_down(self, touch):
        print(f'on_touch_down: {self.page=} {touch.spos[0] > .95=}')
        if touch.spos[0] > .95:
            self.page = 0 if self.page == 1 else 1
            return True
        return super().on_touch_down(touch)


class AnalysisPageLayoutApp(App):
    def build(self):
        return Builder.load_string(kv)


AnalysisPageLayoutApp().run()

@AJRepo
Copy link
Author

AJRepo commented Jan 16, 2024

ok thanks - closing ticket as "not planned"

@AJRepo AJRepo closed this as completed Jan 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants