Kivy:为什么我的一些按钮会遮盖我在它们上面绘制的矩形?

时间:2014-07-19 22:03:38

标签: kivy

我想要一个3x3按钮的GridLayout,每个Button都用彩色矩形装饰。出于某种原因,一些按钮是“在它们的矩形之上”,遮挡它们,而其他按钮则低于它们应该是的。见截图。我查看了add -widget中的z-index和index参数,但我看不到索引首先出错。

#!/usr/bin/env kivy

'''Why are some of the rectangles obscured by the buttons?'''

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
from kivy.graphics import Color, Rectangle
from random import random as r

class ImageButton(Button):
    def __init__(self, *args, **kwargs):
        super(ImageButton, self).__init__(*args, **kwargs)
        side = 80 # smaller than button, to make it easy to see what's happening
        print self.x
        with self.canvas:
            Color(r(), r(), r())
            Rectangle(pos=self.convert_coords(0, 0), size=(side, side))

    def convert_coords(self, x, y):
        """Convert relative [0-1] widget coords to absolute (pixel-valued)
        window coords. FIXME this should be handled by
        self.to_parent."""
        w = int(Config.get('graphics', 'width'))
        h = int(Config.get('graphics', 'height'))
        phx = self.pos_hint['x']
        phy = self.pos_hint['y']
        shx = self.size_hint[0]
        shy = self.size_hint[1]
        i = w * (phx + x * shx)
        j = h * (phy + y * shy)
        return i, j

    def hello(self, i, j, *largs):
        print i, j

class Cells(GridLayout):
    def __init__(self, *args, **kwargs):
        super(Cells, self).__init__(*args, **kwargs)
        for i in range(self.cols):
            for j in range(self.rows):
                cell = ImageButton(size_hint=(1./self.cols, 1./self.rows),
                                   pos_hint={'x':i/float(self.cols), 'y':j/float(self.rows)})
                cell.bind(on_release=lambda *x: cell.hello(i, j))
                self.add_widget(cell)

class Main(App):
    def build(self):
        return Cells(cols=3, rows=3)

if __name__ == '__main__':
    Config.set('graphics', 'width',  '300')
    Config.set('graphics', 'height', '300')
    Main().run()

Screenshot

我在OSX上使用Kivy 1.8.0。

编辑:当前的工作版本如下。

#!/usr/bin/env kivy

'''Using kvlang and GridLayout correctly simplifies and avoids the error'''

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
from kivy.graphics import Color, Rectangle

kv_string = """
#:import r random.random

<ImageButton>:
    canvas:
        Color:
            rgba: r(), r(), r(), 1
        Rectangle:
            pos: self.pos
            size: self.size
"""

class ImageButton(Button):
    pass

class Cells(GridLayout):
    def __init__(self, *args, **kwargs):
        super(Cells, self).__init__(*args, **kwargs)
        for i in range(self.cols):
            for j in range(self.rows):
                self.add_widget(ImageButton())

class Main(App):
    def __init__(self, cols, rows, *args, **kwargs):
        super(Main, self).__init__(*args, **kwargs)
        self.cols = cols
        self.rows = rows
    def build(self):
        return Cells(cols=self.cols, rows=self.rows)

if __name__ == '__main__':
    cols = 3
    rows = 3
    Config.set('graphics', 'width',  str(cols * 100))
    Config.set('graphics', 'height', str(rows * 100))
    Builder.load_string(kv_string)
    Main(cols, rows).run()

1 个答案:

答案 0 :(得分:1)

  

为什么我的某些按钮会遮盖我在其上绘制的矩形?

直接的答案是他们没有 - 他们模糊了不同按钮的矩形。您的问题是您的convert_coords函数不会将矩形放在与其按钮相同的位置; GridLayout 忽略 pos_hint并从左上角填充按钮,而您的代码假设按钮从左下角填充。

也就是说,左下方的矩形是第一个绘制的矩形(通过第一个按钮),但该按钮实际上位于右上角。左下角的按钮实际上是第七个绘制的,因此它显示在矩形的顶部。

你可以通过修正你的坐标数学来解决这个问题,但实际上你的整个过程并不好 - 你正在与kivy战斗而不是使用它。布局已经在内部执行定位数学,使按钮处于正确的位置,并且更容易简单地利用它。

class ImageButton(Button):
    def __init__(self, *args, **kwargs):
        super(ImageButton, self).__init__(*args, **kwargs)
        side = 80 # smaller than button, to make it easy to see what's happening
        print self.x
        with self.canvas:
            Color(r(), r(), r())
            self.rect = Rectangle(pos=self.pos, size=self.size)
        self.bind(pos=self.update_rect, size=self.update_rect)

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

这简单地让布局完成工作;当按钮定位时,它的大小和pos属性可能会改变,如果发生这种情况,会自动调用update_rect方法,该方法适当地重新定位矩形。如果您的窗口没有预设的确切尺寸,这还有一个额外的好处就是它会继续工作。

如果你使用kv语言(我推荐!),这就更容易了:

class ImageButton(Button):
    pass  # You don't need to do *anything* in python!

...和kv代码:

#:import r random.random

<ImageButton>:
    canvas:
        Color:
            rgba: r(), r(), r(), 1
        Rectangle:
            pos: self.pos
            size: self.size

这更短更清晰,矩形位置和大小将自动更新以匹配按钮位置和大小,因为kv会自动创建正确的装订。