2012-12-25 145 views
2

我想用GridLayout來使用自定義小部件,但結果總是一個角落中的一個非常小的網格,而不是在整個窗口中擴展的網格。爲什麼根窗口小部件不具有相同的窗口大小?

示例代碼:

import kivy 
kivy.require('1.5.1') 

from kivy.app import App 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.widget import Widget 
from kivy.uix.gridlayout import GridLayout 



class MyWidget(Widget): 
    def __init__(self): 
     super(MyWidget, self).__init__() 

     grid_layout = GridLayout(cols=3) 
     grid_layout.add_widget(Button(text='A')) 
     grid_layout.add_widget(Button(text='B')) 
     grid_layout.add_widget(Label(text='text')) 
     grid_layout.add_widget(Label(text='other')) 
     grid_layout.add_widget(Button(text='text')) 
     self.add_widget(grid_layout) 


class MyApp(App): 
    def build(self): 
     float = 
     return MyWidget() 


MyApp().run() 

由於Widget的默認size_hint(1,1)應該在整個窗口中展開,而GridLayout也。爲什麼這不會發生? 我如何獲得我想要的結果?

回答

4
`class MyWidget(Widget):` 

你根插件是MyWidget其從佈局中的一個的Widget,而不是繼承,因此不控制它的孩子的尺寸如前所述here「的size_hint是通過使用的值的元組佈局來管理他們的孩子的大小「。

您的根部件佔用了整個窗口的空間。您可以通過添加一個Rectangle的MyWidget畫布像這樣測試這個::

with self.canvas.before: 
    Color(1,0,0,1) 
    Rectangle(pos=self.pos, size=self.size) 

你應該熟悉的畫布,canvas.before and canvas.after。他們基本上是一組指令,之前的組是在小組件的畫布指令之前和組之後繪製的。

在Kivy不同的是,雖然Widget的尺寸/佈局推遲到下一幀,所以如果你只需要添加上面的代碼到你的代碼,像這樣::

from kivy.app import App 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.widget import Widget 
from kivy.uix.gridlayout import GridLayout 
from kivy.graphics import * 


class MyWidget(Widget): 

    def __init__(self, **kwargs): 
     # I'd make sure to pass of kwargs through to the super 
     # as there are widgets's that process their initial 
     # arguments through. 
     super(MyWidget, self).__init__(**kwargs) 

     grid_layout = GridLayout(cols=3) 
     grid_layout.add_widget(Button(text='A')) 
     grid_layout.add_widget(Button(text='B')) 
     grid_layout.add_widget(Label(text='text')) 
     grid_layout.add_widget(Label(text='other')) 
     grid_layout.add_widget(Button(text='text')) 
     self.add_widget(grid_layout) 
     with self.canvas.before: 
      Color(1,0,0,1) 
      Rectangle(pos=self.pos, size=self.size) 


class MyApp(App): 
    def build(self): 
     return MyWidget() 

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

這將只顯示一個關鍵的事情紅色的矩形在你的小部件的初始位置和大小,當時它的默認位置和大小分別爲(0,0)和(100,100)。

爲了使紅色矩形堅持小部件的大小,我們應該bind它的大小到小部件的大小,像這樣::

... 
     grid_layout.add_widget(Button(text='text')) 
     self.add_widget(grid_layout) 
     with self.canvas.before: 
      Color(1,0,0,1) 
      self.rect = Rectangle(pos=self.pos, size=self.size) 
     self.bind(size=self.update_rect) 

    def update_rect(self, instance, value): 
     self.rect.pos = self.pos 
     self.rect.size = self.size 

class MyApp(App): 
    def build(self): 
... 

將上述代碼的輸出上面會顯示,你的小部件佔用了整個窗口的大小。但是,這不能解決您的問題,並且子版面仍然保留在其原始尺寸的原始位置&。這是因爲小部件無法控制上述兒童的大小。

你有兩個選擇,或者更新你的小部件的孩子/孩子的位置,比如更新矩形(很快會讓多個孩子變得複雜),或者使用其中一個佈局作爲根部件。

這也可以在千伏做像這樣::

from kivy.app import App 
from kivy.uix.widget import Widget 
from kivy.lang import Builder 

Builder.load_string(''' 
# this is the rule for MyWidget that defines 
# what MyWidget looks like i.e.drawing 
# instructions and widgets etc 
<MyWidget>: 
    canvas.before: 
     Color: 
      rgba: 1, 0, 0, 1 
     Rectangle: 
      # this implicitly binds the size of the 
      # rect to the size of the widget 
      size: self.size 
      # self here still refers to the widget as Rectangle is only a 
      # graphics instruction and not a widget 
      pos: self.pos 
    GridLayout: 
     cols: 3 
     # root here refers to the `MyWidget`, bind the size of the 
     # GridLayout to the size of your root widget 
     size: root.size 
     Button: 
      text: 'A' 
     Button: 
      text: 'B' 
     Label: 
      text: 'text' 
     Label: 
      text: 'other' 
     Button: 
      text: 'text'   
''') 


class MyWidget(Widget): 
    pass 


class MyApp(App): 
    def build(self): 
     return MyWidget() 

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

上面的例子結合孩子的大小,它的大小是父控件。我仍然建議使用佈局作爲根部件,並且不要猶豫嵌套佈局。

+0

我還是不明白,爲什麼他們決定做這樣的事情。無論如何,我解決了在你的例子中添加一個'update_layout'方法並像'Rectangle'一樣綁定它。我所有的小部件只有一個孩子:一個佈局,因此這個解決方案是完美的。我討厭使用語言/設計師編寫用戶界面,因此目前我對您的第二個解決方案不感興趣。 – Bakuriu

+0

好吧,無論你想要什麼,但你應該在未來嘗試使用kvlang,它會讓所有的事情變得更簡單,並且更簡單。 – Tshirtman

0

我更喜歡讓您的主類繼承GridLayout而不是Widget的解決方案。事實上,回想起來這似乎很明顯,我不知道爲什麼這些教程完全使用Widget方法。以前的答案建議這種技術,但我想我會提供一些代碼。

import kivy 
kivy.require('1.5.1') 

from kivy.app import App 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.gridlayout import GridLayout 

class MyWidget(GridLayout): 
    def __init__(self): 
     super(MyWidget, self).__init__(cols=3) 

     self.add_widget(Button(text='A')) 
     self.add_widget(Button(text='B')) 
     self.add_widget(Label(text='text')) 
     self.add_widget(Label(text='other')) 
     self.add_widget(Button(text='text')) 

class MyApp(App): 
    def build(self): 
     return MyWidget() 


MyApp().run() 

或使用kvlang:

import kivy 
kivy.require('1.5.1') 

from kivy.app import App 
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.uix.gridlayout import GridLayout 
from kivy.lang import Builder 

Builder.load_string(''' 
<MyWidget>: 
    cols:3 
    Button: 
     text:'A' 
    Button: 
     text:'B' 
    Label: 
     text:'text' 
    Label: 
     text:'other' 
    Button: 
     text:'text' 
''') 

class MyWidget(GridLayout): 
    pass 
class MyApp(App): 
    def build(self): 
     return MyWidget() 

if __name__ == "__main__": 
    MyApp().run() 
相關問題