kivy:我的函数在使用时钟计划时指向其他/新小部件

时间:2014-11-07 08:15:49

标签: python widget kivy

我已将代码设置为最初添加几个按钮小部件。

第一个按钮会产生一个矩形框。这写为addfunction()

第二个按钮必须执行hookupfull(),这会做两件事 - gethooks()hookfunc()

首先它会抓取我pos的子项的widthheightMainWindowWidget,并将其列入每个列表的列表中,然后删除额外的按钮中的条目(我的按钮是当前MainWindowWidget的子项,但我只想要这些框的属性)。这写为gethooks()

其次,它从列表中计算花式坐标并绘制一条线。这写为hookfunc()

因此,如果我按下第一个按钮两次,第二个按钮按一次,它将创建两个框,然后画一条线将它们连接在一起。这很好用。我的议程上的下一步是安排像canvas.clear()这样的东西,并每1/60秒重绘一行等。然后我创建了第三个按钮小部件来设置一个标志以启动update循环运行。

但是,如果我尝试将hookupfull()Clock.schedule_interval()一起安排,那么它无法正常工作 - 不确定如何解释或发生了什么,但预定的代码没有似乎“走”到我想要的MainWindowWidget。它似乎产生了大量其他MainWindowWidget s。

我认为这是我指的是小部件或带参数的东西(我认为是代码的(self, *args)部分)或我声明方法/函数的方式(我还不确定方法和功能之间的区别,对不起)

所以,我尝试通过在多个地方添加print self等内容来调试它,看看self是什么。

我的代码:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.graphics import Color, Line
from kivy.clock import Clock

boxscale = 1
global startenable
global debug_1
startenable = False
debug_1 = True

class Scatterer(Scatter):
    pass

class Drawer(FloatLayout):
    pass

class MainWindowWidget(FloatLayout):
    def addfunction(self, *args):
        s = Scatterer()
        d = Drawer()
        s.size = 60 * boxscale , 111 * boxscale
        # default size * scale
        d.size = s.size
        self.add_widget(s)
        s.add_widget(d)
        print "button is pressed"

    def startfunc(obj):
        global startenable
        if startenable == False:
            startenable = True
        else:
            startenable = False
        print'startenable set to',startenable


    def gethooks(self, *args):
        # get hook locations
        self.p = [] 
        for child in self.children:
            self.p.append(child.pos)
        del self.p[(len(self.p)-3):(len(self.p))]

        self.w = [] 
        for child in self.children:
            self.w.append(child.width)
        del self.w[(len(self.w)-3):(len(self.w))]

        self.h = []
        for child in self.children:
            self.h.append(child.height)
        del self.h[(len(self.h)-3):(len(self.h))]

        if debug_1 == True:
            print 'getting hook location........'
            print 'self.p:',self.p # list of positions
            print 'length of self.p:',len(self.p)
            print 'widths:',self.w # list of widths
            print 'heights:',self.h# list of heights
        print self

    def hookfunc(self, *args): 
        # draw line based on hooks' position
        self.h_01_x = \
        self.p[0][0]

        self.h_01_y = \
        self.p[0][1] + (self.h[0]/2)

        self.h_02_x = \
        self.p[1][0] + self.w[1]

        self.h_02_y = \
        self.p[1][1] + (self.h[1]/2)
        with self.canvas:
            Line(bezier=(
                self.h_01_x, self.h_01_y,
                self.h_01_x - 20, self.h_01_y,
                self.h_02_x + 20, self.h_02_y,
                self.h_02_x, self.h_02_y,
                ), width=2)

        print self

    def hookupfull(self, *args):
        self.gethooks()
        self.hookfunc()

    def update(self, *args):
        global debug_1
        if startenable == True:
            mww= MainWindowWidget()
            print mww

            mww.hookupfull()

        else: # if startenable is false
            pass

class Test2App(App):
    def build(self):

        Clock.schedule_interval(MainWindowWidget.update, \
                5.0/60.0)
        return MainWindowWidget()

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

kv文件:

#:kivy 1.0.9

<MainWindowWidget>

    NewButton:
        text: 'add'
        pos: 100, 0
        on_release: root.addfunction()

    NewButton:
        text: 'start'
        pos: 200, 0
        on_release: root.startfunc()

    NewButton:
        text: 'hook up full'
        pos: 400, 0
        on_release: root.hookupfull()

<NewButton@Button>:
    font_size: 15 
    size_hint: None, None
    size: 100, 100 

<Scatterer>:
    do_rotation: False
    size_hint: None, None
    size: self.size

<Drawer>:
    size: self.size
    canvas:
        Color:
            rgba: 0, 1, 0, 0.3
        Rectangle:
            pos: self.pos
            size: self.size

我发现的是,当我点击hookupfull()打印self的按钮时,无论多少次<__main__.MainWindowWidget object at 0x7f110fcef530>,它们总会返回相同的内容,例如hookupfull() self 1}}被称为。

但是,如果安排了相同的功能,Scatter将始终返回不同的小部件。

我想知道的其他一些问题:

  1. 有没有办法为动态创建的小部件分配id或引用?例如,在我的代码中,按第一个按钮将创建一个新的Scatter对象。有没有办法指向特定的FloatLayout对象?

  2. 如何引用小部件孙子?例如,在我的代码中,我将Scatter对象设置为MainWindowWidget对象的子对象,该对象是FloatLayout的子对象。由于Scatterpos对象的大小发生了变化,width就像一个控制器(据我所知,实际上并没有改变大小)。我想访问FloatLayout的{​​{1}}和(self, *args)等属性。

  3. 方法/函数声明的参数,例如{{1}} - 他们做了什么?

1 个答案:

答案 0 :(得分:0)

您在类中定义的每个函数都应该按照惯例将self作为第一个参数(静态方法除外)。调用函数时,它是类的实例对象。您还在某些函数中创建主窗口小部件的新实例:请参阅上面的inclement注释。这样做没有多大意义。请阅读手册:https://docs.python.org/2/tutorial/classes.html#class-objects

关于您的其他问题:

  
      
  1. 有没有办法为动态创建的id分配id或引用   小部件的数量
  2.   

您可以在实例化对象时使用指定的id参数直接分配和ID,例如散射体(ID = '本身份识别码')。您可以通过其ID来引用它,但我个人的偏好是使用列表跟踪对象(见下文)

  
      
  1. 我如何引用小部件孙子?
  2.   

简单地说,不要!直接在列表中跟踪它们并使用对其属性的引用,而不是创建维度的辅助列表:

def __init__(self, *args, **kwargs):
    self.box_list = [] # <---- set up list to track boxes
    super(MainWindowWidget, self).__init__(*args, **kwargs)
....
....
    if len(self.box_list) > 1:    
        box1 = self.box_list[-2] # grab the last two boxes added to the list
        box2 = self.box_list[-1]
        h_01_x = box1.x
        h_01_y = box1.y + (box1.height/2)
        h_02_x = box2.x + box2.width
        h_02_y = box2.y + (box2.height/2)
        with self.canvas:
            Line(bezier=(
                h_01_x, h_01_y,
                h_01_x - 20, h_01_y,
                h_02_x + 20, h_02_y,
                h_02_x, h_02_y,
            ), width=2)
  

我想访问诸如pos和width之类的属性   FloatLayout。

分散确实有大小和位置。更改对象时都会更新。如果你作为Scatterer的孩子直接在kivy中声明你的FloatLayout也会更好..没有必要单独创建它们

  
      
  1. 方法/函数声明的参数,例如(self,* args) - 它们做了什么?
  2.   

self是对已调用其函数的实例的引用。 * args是未命名参数列表的扩展。看看这个问题:*args and **kwargs?

作为最终评论,如果您按照说明中的说法调用canvas.clear,那么您也会删除按钮和框,因为您正在使用主窗口小部件的画布。创建另一个类来包含您的行并将其位置链接到框。当您在该对象上调用canvas.clear时,它将仅清除该行。如果在框位置/大小更改时更新线对象,则还可以将线的渲染移动到kivy文件中,并消除无关的时钟调度。