Search code examples
pythonkivyscrollview

Color changing issue with Kivy Scrollview


I created some simple lines in between the buttons within my scrollview but the brightness of the lines seem to fluctuate when you drag the scroll bar up and down in various places.

This issue occurs when you set the HEIGHT of the scrollview object between a range of 501 to 999 pixels. However, when you change the height of the scrollview object to say, exactly 500 or 1000 pixels, the issue stops and the colours stay consistent. I need the red colour lines to be consistent throughout all rows, no matter what the height of the scrollview is.

Does anyone know what is causing this issue and how to fix it?

Edit: I edited this post with updated code and description on 7/22/2019 with a better demonstration of the apparent bug. Please see code and screenshots below.

Here is an image of the lines starting out dark:

enter image description here

Here is an image of the lines changing to a brighter color after scroll bar is dragged:

enter image description here

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.graphics import Line, InstructionGroup, Canvas, CanvasBase, Color, Rectangle

Builder.load_string("""
<ButtonsApp>:
    ScrollView:
        id: sv
        size_hint: None, None
        pos: 205, 0
        size: 900, 700 #If you change the height to 700 pixels, the line colors will darken and brighten as you drag the scroll bar up and down... 
        #Alternatively, if you change the height to 500 pixels, the line colors stay consistent as you drag the scroll bar..
        scroll_type: ['bars']
        scroll_wheel_distance: 20
        bar_width: 8
        bar_inactive_color: .55, .55, .55, 1 
        bar_color: .663, .663, .663, 1 
        canvas.before:
            Color:
                rgba: 0, .5, 1, 1
                group: 'b'
            Rectangle:
                size: 0, 0
                group: 'b'
        GridLayout:
            id: container
            cols: 6
            height: self.minimum_height
            size_hint: None, None
            do_scroll_x: False


""")

class ButtonsApp(App, FloatLayout):

    def build(self):
        y = 1 #we need to use this variable for dynamic ID creation
        start_pixel = 0
        for i in range(0, 200):
            L1 = Button(text="row = " + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=60, background_color=[0, 0, 0, 1],
            id=str(y), color=[.92, .92, .92, 1])
            L2 = Button(text="", font_size=12, halign='left', valign='middle', size_hint=[None, None], width=63, height=40, background_color=[0, 0, 0, 1],
            id=str(y), color=[.92, .92, .92, 1])
            L3 = Button(text="22" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=330, background_color=[0, 0, 0, 1],
            id=str(y), color=[.92, .92, .92, 1])
            L4 = Button(text="33" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=118, background_color=[0, 0, 0, 1],
            id=str(y), color=[.92, .92, .92, 1])
            L5 = Button(text="Test Description" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=122, background_color=[0, 0, 0, 1],
            id=str(y), color=[.92, .92, .92, 1])
            L6 = Button(text="Test Description" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=118, background_color=[0, 0, 0, 1],
            id=str(y), color=[.92, .92, .92, 1])
            with self.ids.container.canvas.after:
                Color(1, 0, 0, 1)
                Line(points=(L1.pos[0], L1.pos[1] + start_pixel, L1.pos[0] + 900, L1.pos[1] + start_pixel), width=1)
            #bind text_size to size so that halign and valign work properly on button created above
            L1.bind(size=L1.setter('text_size'))  
            L2.bind(size=L2.setter('text_size')) 
            L3.bind(size=L3.setter('text_size')) 
            L4.bind(size=L3.setter('text_size')) 
            L5.bind(size=L3.setter('text_size')) 
            L6.bind(size=L3.setter('text_size'))
            #add the button to grid layout
            self.ids.container.add_widget(L1)
            self.ids.container.add_widget(L2)
            self.ids.container.add_widget(L3)
            self.ids.container.add_widget(L4)
            self.ids.container.add_widget(L5)
            self.ids.container.add_widget(L6)
            y = y + 1   
            start_pixel = start_pixel + 40
        return self

if __name__ == "__main__":
    ButtonsApp().run()

Solution

  • I found a less than ideal solution to fix this issue by drawing the red lines with a width of 1.0001 and a black line underneath with a width of 1. For some reason, the colors change when the scrollview is dragged when the red color lines are set to a width of 1 (or the lines are very thin). This solution is going to hurt performance slightly since you have to draw twice as many lines, but it does fix the colors changing issue.

    Here is the code:

    from kivy.app import App
    from kivy.uix.floatlayout import FloatLayout
    from kivy.lang import Builder
    from kivy.uix.button import Button
    from kivy.graphics import Line, InstructionGroup, Canvas, CanvasBase, Color, Rectangle
    
    Builder.load_string("""
    <ButtonsApp>:
        ScrollView:
            id: sv
            size_hint: None, None
            pos: 205, 0
            size: 900, 700 #If you change the height to 700 pixels, the line colors will darken and brighten as you drag the scroll bar up and down... 
            #Alternatively, if you change the height to 500 pixels, the line colors stay consistent as you drag the scroll bar..
            scroll_type: ['bars']
            scroll_wheel_distance: 20
            bar_width: 8
            bar_inactive_color: .55, .55, .55, 1 
            bar_color: .663, .663, .663, 1 
            canvas.before:
                Color:
                    rgba: 0, .5, 1, 1
                    group: 'b'
                Rectangle:
                    size: 0, 0
                    group: 'b'
            GridLayout:
                id: container
                cols: 6
                height: self.minimum_height
                size_hint: None, None
                do_scroll_x: False
    
    
    """)
    
    class ButtonsApp(App, FloatLayout):
    
        def build(self):
            y = 1 #we need to use this variable for dynamic ID creation
            start_pixel = 0
            for i in range(0, 200):
                L1 = Button(text="row = " + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=60, background_color=[0, 0, 0, 1],
                id=str(y), color=[.92, .92, .92, 1])
                L2 = Button(text="", font_size=12, halign='left', valign='middle', size_hint=[None, None], width=63, height=40, background_color=[0, 0, 0, 1],
                id=str(y), color=[.92, .92, .92, 1])
                L3 = Button(text="22" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=330, background_color=[0, 0, 0, 1],
                id=str(y), color=[.92, .92, .92, 1])
                L4 = Button(text="33" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=118, background_color=[0, 0, 0, 1],
                id=str(y), color=[.92, .92, .92, 1])
                L5 = Button(text="Test Description" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=122, background_color=[0, 0, 0, 1],
                id=str(y), color=[.92, .92, .92, 1])
                L6 = Button(text="Test Description" + str(y), font_size=12, halign='left', valign='middle', size_hint_x=None, width=118, background_color=[0, 0, 0, 1],
                id=str(y), color=[.92, .92, .92, 1])
                with self.ids.container.canvas.after: #draw the red line with a width of 1.0001
                    Color(1, 0, 0, 1)
                    Line(points=(L1.pos[0], L1.pos[1] + start_pixel, L1.pos[0] + 900, L1.pos[1] + start_pixel), width=1.0001)
                with self.ids.container.canvas.after: #draw a black line with a width of 1
                    Color(0, 0, 0, 1)
                    Line(points=(L1.pos[0], (L1.pos[1] + start_pixel) - 1, L1.pos[0] + 900, (L1.pos[1] + start_pixel) - 1), width=1)
                #bind text_size to size so that halign and valign work properly on button created above
                L1.bind(size=L1.setter('text_size'))  
                L2.bind(size=L2.setter('text_size')) 
                L3.bind(size=L3.setter('text_size')) 
                L4.bind(size=L3.setter('text_size')) 
                L5.bind(size=L3.setter('text_size')) 
                L6.bind(size=L3.setter('text_size'))
                #add the button to grid layout
                self.ids.container.add_widget(L1)
                self.ids.container.add_widget(L2)
                self.ids.container.add_widget(L3)
                self.ids.container.add_widget(L4)
                self.ids.container.add_widget(L5)
                self.ids.container.add_widget(L6)
                y = y + 1   
                start_pixel = start_pixel + 40
            return self
    
    if __name__ == "__main__":
        ButtonsApp().run()