Search code examples
pythonwindowskivykivy-languagegrid-layout

How can I center my GridLayout in the middle of the screen in Kivy?


I have a GridLayout with 8 cols, and I add 64 Buttons. (so 8x8). I want the Buttons to ALWAYS be quadratic, so I made that in my spot_init() function.

That all works great. When I make the Window smaller or bigger, the rest of my Screen gets black and the GridLayout stays in the Corner. But I wanted it to be centered.

For leftright that works perfectly fine but when i try applying that to updown as well, it does some weird things, I really cannot explain.

Some things I (maybe) found out:

  • When I do it exactly like right now, but in the code, the Y coord is 3 times as high as it should be for some reason.
  • When I then divide it by 3, it gets 7 times as high...
  • It doesn't change if I do it in .kv or in .py file
  • Moving GridLayout without RelativeLayout also doesn't work (almost the same thing happens)
  • Other askers seemed to have the same problem (or a similiar one) but their fixes didn't help me.

My .kv file:

RMainBoard:

<MainBoard>:
    cols:8
    # height: self.minimum_height
    # size_hint_y: None
    # size_hint_x: None

<RMainBoard@RelativeLayout>:
    pos:(self.width/2-min(self.width/8,self.height/8)*4,self.height/2-(min(self.width/8,self.height/8))*4)
    MainBoard:

My .py file:

#resize window (NEEDS TO BE AT VERY TOP)
from kivy.config import Config
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '600')

from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.metrics import dp
from kivy.properties import NumericProperty

class MainBoard(GridLayout):
    spots = []
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.spot_init()
        
    def on_size(self,*args):
        for spot in self.spots:
            spot_size = min(self.width/8,self.height/8)
            print(min(self.width/8,self.height/8))
            spot.height = spot_size
            spot.width = spot_size

    def spot_init(self):
        for i in range(0,64):
            self.spots.append(Button(size_hint=(None,None),height=self.height/8,width=self.width/8))
            self.add_widget(self.spots[i])

class TestApp(App):
    pass
TestApp().run()

Thanks a lot <3


Solution

  • Rather than writing your own code to position the GridLayout, you can use the kv language to accomplish that. Here is a modified version of your code that does this:

    # resize window (NEEDS TO BE AT VERY TOP)
    from kivy.config import Config
    from kivy.lang import Builder
    
    Config.set('graphics', 'width', '600')
    Config.set('graphics', 'height', '600')
    
    from kivy.app import App
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.button import Button
    
    kv = '''
    RMainBoard:
    
    <RMainBoard@RelativeLayout>:
        MainBoard:
            cols: 8
            size_hint: None, None
            
            # make MainBoard square
            width: min(root.width, root.height)
            height: self.width
            
            # position MainBoard in center of RMainBoard
            pos_hint: {'center_x': 0.5, 'center_y': 0.5}
        
    <SquareButton>:
        size_hint: None, None
        
        # make the Button square
        width: min(self.parent.width/8, self.parent.height/8) if self.parent else 100
        height: self.width
    '''
    
    
    class SquareButton(Button):
        pass
    
    
    class MainBoard(GridLayout):
        spots = []
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.spot_init()
    
        def spot_init(self):
            for i in range(0, 64):
                self.spots.append(SquareButton(text=str(i)))
                self.add_widget(self.spots[i])
    
    
    class TestApp(App):
        def build(self):
            return Builder.load_string(kv)
    
    
    TestApp().run()
    

    Note that I included the kv as a string in the python code. That was just for my own convenience, and it could just as well be in your kv file.

    I have defined a SquareButton class along with a <SquareButton> rule in the kv that keeps the SquareButton square. The Buttons created in the spot_init() method are now SquareButtons.