2016-04-02 86 views
3

我有几个小部件,并希望“拖动和选择”它们。我使用选择小部件作为矩形来显示选择大小,然后使用for child in root.children: selection.collide_widget(child)。这个效果很好,只要我从左下角拖到右上角,因为选择小部件的大小将是正面的。collide_widget负尺寸

预计负尺寸的小部件将无法与collide_widget一起使用吗?

我不应该使用小部件的负尺寸吗?

KV文件:

<SelectionBox>: 
    size: 0,0 
    size_hint: None, None 
    canvas: 
     Color: 
      rgba: 1, 1, 1, 0.1 
     Rectangle: 
      pos: root.pos 
      size: root.size 

<Selectable>: 
    size: 32, 32 
    size_hint: None, None 
    canvas: 
     Color: 
      rgba: 0, 1, 0, 1 
     Rectangle: 
      pos: root.pos 
      size: root.size 

代码:

class Selectable(Widget): 
    pass 

class Canvas(FloatLayout): 

    touch_down = False 

    def on_touch_down(self, touch): 
     self.selection = sel = SelectionBox() 
     sel.pos = touch.pos 
    self.touch_down = True 
     self.add_widget(sel) 

    def on_touch_move(self, touch): 
     if self.touch_down: 
#~~~~~~~~~~~~~~~~~~~~~~~~~ Interesting line here ~~~~~~~~~~~~~~~~~~~~~~~~~ 
      # size can get negative 
      self.selection.size = (touch.pos[0] - self.selection.pos[0] , touch.pos[1] - self.selection.pos[1]) 

    def on_touch_up(self, touch): 

     for widget in self.children: 
      if widget is self.selection: 
       print("Children is selection") 
      if self.selection.collide_widget(widget): 
      print("Widget collides: {}".format(widget)) 

     self.touch_down = False 
     self.remove_widget(self.selection) 

canvas = Canvas() 

class MyApp(App): 
    def build(self): 
     canvas = Canvas() 
    for i in range(0,11): 
     sel = Selectable() 
     sel.pos = random.random() * 1000, random.random() * 1000 
     self.add_widget(sel) 
     return canvas 

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

回答

1

事实上,这是正常现象。从kivy.uix.widget.Widget

def collide_widget(self, wid): 
    if self.right < wid.x: 
     return False 
    if self.x > wid.right: 
     return False 
    if self.top < wid.y: 
     return False 
    if self.y > wid.top: 
     return False 
    return True 

对于负大小,此逻辑将行不通,因为例如self.right < self.x。一个简单的解决办法是重新定义collide_widget这些类的其中负尺寸预期:

def collide_widget(self, wid):  
    if max(self.x, self.right) < min(wid.x, wid.right): 
     return False 
    if min(self.x, self.right) > max(wid.x, wid.right): 
     return False 
    if max(self.top, self.y) < min(wid.y, wid.top): 
     return False 
    if min(self.top, self.y) > max(wid.y, wid.top): 
     return False 
    return True 

这需要同时兼顾小窗口的具有正或负的大小(所述一个主叫collide_widget和所述一个被测试)。

但是,我不确定,如果其他地方的代码依赖于负值不会像预期的那样发生碰撞(所以请小心地将其贴到Widget上)。