kivy Resize vindow trouble

44 views
Skip to first unread message

Bonny

unread,
Sep 9, 2022, 6:35:10 AM9/9/22
to Kivy users support
Hello...

I have app that have Carousel view, and on each page have menu line on top and rest is scroll view. All works ok until I resize main window. I did try many things but fail.
Here is stripped app just for testing. No kv files, and pages are created dinamicaly on full app.

So how to proper manage resize?

#!/usr/bin/env python3

import kivy
from kivy.app import App
from kivy.uix.pagelayout import PageLayout
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView


class EpSolarApp(App):
    menuH=65
    itemH=35

    def build(self):
        CarouselView = Carousel(loop=True)

        #Iterate pages
        for i in range (4):
            PageView    = BoxLayout(orientation='vertical', spacing=3,size_hint=(1,None) )
            ScrolView   = ScrollView(size_hint=(1, None), size=(Window.size[0], Window.size[1]-self.menuH))
            Pagelay     = BoxLayout(orientation='vertical', spacing=3,size_hint=(1,None))
            ScrolView.add_widget(Pagelay)
            Pagelay.bind(minimum_size=Pagelay.setter('size'))

            #each page have menu line on top
            MenuLine=BoxLayout(orientation='horizontal', spacing=3, size_hint_y=None)
            MenuLine.add_widget(Button(text="This is info line for Page %i" % i, size_hint=(1, None), height=self.menuH))
            PageView.add_widget(MenuLine)
            PageView.add_widget(ScrolView)
            CarouselView.add_widget(PageView)

            #Iterate for each item on page
            buttons=[100,5,200,10][i]
            for n in range(buttons):
                but=Button(text="Buton %d of %d on page %d"%(n+1,buttons,i), size_hint=(1,None), height=self.itemH)
                Pagelay.add_widget(but)

        return (CarouselView)

if __name__ == '__main__':
    EpSolarApp().run()





Elliot Garbus

unread,
Sep 9, 2022, 5:07:31 PM9/9/22
to kivy-...@googlegroups.com

You can integrate KV with dynamic code.   In the example below, I created a class for PageView, and defined the structure in kv.  This fixes the scaling issues with the Window.  There are a number of small issue with your original code.  They are fixed here.

 

 

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout


kv =
"""
<PageView>:
    orientation:'vertical'
    spacing:3
    BoxLayout:  # Menuline   This BoxLayout is not required, you could just put the button here.
        orientation:'horizontal'
        spacing:3
        size_hint_y: None
        height: app.menuH
        Button:
            text: root.info_line
    ScrollView:
        BoxLayout:
            id: pagelay
            orientation:'vertical'
            spacing:3
            size_hint_y: None
            height: self.minimum_height

Carousel:
    loop: True
"""


class PageView(BoxLayout):
    info_line = StringProperty()


class EpSolarApp(App):
    menuH=
65
   
itemH=35

   
def build(self
):
       
return Builder.load_string(kv)

   
def on_start(self):
       
for i in range(4):
            w = PageView(
info_line=f'This is info line for Page {i}')
           
self.root.add_widget(w)
            buttons=[
100,5,200,10][i]
           
for n in range(buttons):
                but=Button(
text=f"Button {n+1} of {buttons} on page {i}", size_hint=(1,None), height=self.itemH)
                w.ids.pagelay.add_widget(but)


--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/d47bbed5-fbde-48c8-afe2-2cc686fae991n%40googlegroups.com.

 

Bonny

unread,
Sep 10, 2022, 12:10:46 PM9/10/22
to Kivy users support
I got it near working in my application.
I got into trouble where I need to have more buttons in menu line.
This is my old version example with added few lines to show what I mean.
(And this buttons should have different callbacks with parameter - not shown in example.)

            ########################################################################################
            ####### added line for different header line
            if i==0:
                MenuLine.add_widget(Button(text="Option1", size_hint=(1, None), height=self.menuH))
            if i==1:
                MenuLine.add_widget(Button(text="Option2", size_hint=(1, None), height=self.menuH))
            ########
            ########################################################################################

Elliot Garbus

unread,
Sep 10, 2022, 8:23:10 PM9/10/22
to kivy-...@googlegroups.com

Can you be more specific?  You want to add 2 buttons to the MenuLine, each with a separate callback.  Is it a separate callback for each instance of the button? 

Assuming you want a different callback per button with the page as a parameter you could do the following:

 

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty, StringProperty
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout


kv =
"""

<PageView>:
    orientation:'vertical'
    spacing:3
    BoxLayout:  # Menuline
        orientation:'horizontal'
        spacing:3
        size_hint_y: None
        height: app.menuH
        Button:
            text: root.info_line
        Button:
            text: 'Option 1'
            on_release: print(f'Option 1 callback from page {root.page_number}')
        Button:
            text: 'Option 2'
            on_release: print(f'Option 2 callback from page {root.page_number}')

    ScrollView:
        BoxLayout:
            id: pagelay
            orientation:'vertical'
            spacing:3
            size_hint_y: None
            height: self.minimum_height

Carousel:
    loop: True
"""


class PageView(BoxLayout):
    info_line = StringProperty()
    page_number = NumericProperty()


class EpSolarApp(App):
    menuH=
65
   
itemH=35

   
def build(self
):
       
return Builder.load_string(kv)

   
def on_start(self):
       
for i in range(4):
            w = PageView(
info_line=f'This is info line for Page {i}', page_number=i)
           
self.root.add_widget(w)
            buttons=[
100,5,200,10][i]
           
for n in range(buttons):
                but=Button(
text=f"Button {n+1} of {buttons} on page {i}", size_hint_y=None, height=self.itemH)
                w.ids.pagelay.add_widget(but)


Bonny

unread,
Sep 11, 2022, 1:50:58 AM9/11/22
to Kivy users support
Not ok. Additional buttons in menu line may be present or not.
Here is my example with additional buttons and callbacks that mimic what I want.

#!/usr/bin/env python3

import kivy
from kivy.app import App
from kivy.uix.pagelayout import PageLayout
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from functools import partial

class EpSolarApp(App):
    menuH=65
    itemH=35

    def doUpload(self, name, param, b):
        print ("Do Something with '%s(%s)' " % (name,param))


    def build(self):
        CarouselView = Carousel(loop=True)

        #Iterate pages
        for i in [('Info',0,5),('Data',1,20),('Settings',2,100)]:


            PageView    = BoxLayout(orientation='vertical', spacing=3,size_hint=(1,None) )
            ScrolView   = ScrollView(size_hint=(1, None), size=(Window.size[0], Window.size[1]-self.menuH))
            Pagelay     = BoxLayout(orientation='vertical', spacing=3,size_hint=(1,None))
            ScrolView.add_widget(Pagelay)
            Pagelay.bind(minimum_size=Pagelay.setter('size'))

            #each page have menu line on top
            MenuLine=BoxLayout(orientation='horizontal', spacing=3, size_hint_y=None)
            if i[1]==2:
                MenuLine.add_widget(Button(text="Upload", size_hint=(.5, None), height=self.menuH, on_press=partial(self.doUpload,i[0],'Upload')))
            MenuLine.add_widget(Button(text="This is info line for Page '%s'" % i[0], size_hint=(1, None), height=self.menuH))
            if i[1]!=0:
                MenuLine.add_widget(Button(text="Refresh", size_hint=(.5, None), height=self.menuH, on_press=partial(self.doUpload,i[0],'Refresh')))


            PageView.add_widget(MenuLine)
            PageView.add_widget(ScrolView)
            CarouselView.add_widget(PageView)

            #Iterate for each item on page
            for n in range(i[2]):
                but=Button(text="Buton %d of %d on page '%s'"%(n+1,i[2],i[0]), size_hint=(1,None), height=self.itemH)

                Pagelay.add_widget(but)

        return (CarouselView)

if __name__ == '__main__':
    EpSolarApp().run()



class EpSolarApp(App):
    menuH=
65
   
itemH=35

   
def build(self

Elliot Garbus

unread,
Sep 11, 2022, 3:58:28 PM9/11/22
to kivy-...@googlegroups.com

The code below adds and id that identifies the BoxLayout for MenuLine.  The enclosing BoxLayout sizes the buttons, so I removed the settings from the button defnitions.

Anytime you have a kivy rule (or root widget) that starts in the far left column, you get a new ids dictionary.  The ids dictionary associates the id, with the widget.

In the python code w is an instance of a PageView.  The code w.ids.menu_line refers the BoxLayout.

 

 

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty, StringProperty
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout

from functools import partial


kv =
"""

<PageView>:
    orientation:'vertical'
    spacing:3
    BoxLayout:  # Menuline
        id: menu_line

        orientation:'horizontal'
        spacing:3
        size_hint_y: None
        height: app.menuH
        Button:
            text: root.info_line
    ScrollView:
        BoxLayout:
            id: pagelay
            orientation:'vertical'
            spacing:3
            size_hint_y: None
            height: self.minimum_height

Carousel:
    loop: True
"""


class PageView(BoxLayout):
    info_line = StringProperty()
    page_number = NumericProperty()


class EpSolarApp(App):
    menuH=
65
   
itemH=35

   
def build(self):
       
return
Builder.load_string(kv)

   
def doUpload(self, name, param, b):
       
print("Do Something with '%s(%s)' " % (name, param))

   
def on_start(self):
       
for i in [('Info',0,5),('Data',1,20),('Settings',2,100)]:
            w = PageView(
info_line=f'{i[0]} Page', page_number=i[1])
           
if i[1] == 2:
               
# These buttons are sized by the enclosing layout
                
w.ids.menu_line.add_widget(Button(text="Upload", on_press=partial(self.doUpload,i[0],'Upload')))
                w.ids.menu_line.add_widget(Button(
text="This is info line for Page '%s'" % i[0]))
           
if i[1] != 0:
                w.ids.menu_line.add_widget(Button(
text="Refresh", on_press=partial(self.doUpload,i[0],'Refresh')))

           
self.root.add_widget(w)
           
for n in range(i[2]):
                but=Button(
text=f"Button {n+1} of {i[1]} on page {i[0]}", size_hint_y=None, height=self.itemH)
                w.ids.pagelay.add_widget(but)


Bonny

unread,
Sep 12, 2022, 1:58:07 AM9/12/22
to Kivy users support
So how I can set width of button on menuline now? Usually upload and refresh are small one and Info is big one.

Bonny

unread,
Sep 12, 2022, 2:24:21 AM9/12/22
to Kivy users support
At leas for now In Menu line I can have 3 buttons. Always present is let's call them 'NameOfPage'. Sometime the 'Upload' is present and/or sometime 'Refresh' is present.
In general the view of menu line can one of them:
NameOfPage

NameOfPage-Refresh

Upload-NameOfPage

Upload-NameOfPage-Refresh

I want Upload and Refresh to be separated as far as possible so misclick with fat fingers is reduced.
The Upload and Refresh buttons are smaller than NameOfPage. And I can't find a way to dynamic size leftmost element (NameOfPage or Upload)



Elliot Garbus

unread,
Sep 12, 2022, 9:17:08 AM9/12/22
to kivy-...@googlegroups.com

You can set the width of the MenuLine buttons, by setting the “size_hint_x” to a value or you can set “size_hint_x” to None and set a value for “width”. This is similar to the way you have set height using menuH.

The buttons appear in the order you add them to the BoxLayout.

Bonny

unread,
Sep 12, 2022, 11:50:23 AM9/12/22
to Kivy users support
That doesn't work as size is not same. But I solved in other way. I removed info_line button from kv, and added all buttons I neded  with w.ids.menu_line.add_widget.. Now works as I want.
Thanks for support.

Elliot Garbus

unread,
Sep 12, 2022, 12:00:10 PM9/12/22
to kivy-...@googlegroups.com

Happy to help.  I’m glad you got it figured out!

Bonny

unread,
Sep 12, 2022, 12:56:09 PM9/12/22
to Kivy users support
Actually I hit another problem as I wish to add rounded buttons and don't have idea how to do that as buttons aren't created in kv but in python. (i know how to do in kv but...)

Elliot Garbus

unread,
Sep 12, 2022, 1:12:47 PM9/12/22
to kivy-...@googlegroups.com

There are a number of options to create rounded buttons.

  1. Create a new class that is derived from Button, change the 4 bitmaps that define the look of the button.  Use png files with transparency.
    1. See: background_down, background_normal… https://kivy.org/doc/stable/api-kivy.uix.button.html?highlight=button#kivy.uix.button.Button.background_disabled_down
  2. You could combine and ButtonBehavior and an Image, again use a png.
  3. If you don’t mind a flat button (no depth), combine ButtonBehavior and a Label, use the canvas to draw a rounded rectange, and change the color when the button is pressed.

 

Give it a try, reach out if you have trouble.

Reply all
Reply to author
Forward
0 new messages