我已将代码设置为最初添加几个按钮小部件。
第一个按钮会产生一个矩形框。这写为addfunction()
。
第二个按钮必须执行hookupfull()
,这会做两件事 - gethooks()
和hookfunc()
:
首先它会抓取我pos
的子项的width
,height
和MainWindowWidget
,并将其列入每个列表的列表中,然后删除额外的按钮中的条目(我的按钮是当前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
将始终返回不同的小部件。
我想知道的其他一些问题:
有没有办法为动态创建的小部件分配id或引用?例如,在我的代码中,按第一个按钮将创建一个新的Scatter
对象。有没有办法指向特定的FloatLayout
对象?
如何引用小部件孙子?例如,在我的代码中,我将Scatter
对象设置为MainWindowWidget
对象的子对象,该对象是FloatLayout
的子对象。由于Scatter
,pos
对象的大小发生了变化,width
就像一个控制器(据我所知,实际上并没有改变大小)。我想访问FloatLayout
的{{1}}和(self, *args)
等属性。
方法/函数声明的参数,例如{{1}} - 他们做了什么?
答案 0 :(得分:0)
您在类中定义的每个函数都应该按照惯例将self作为第一个参数(静态方法除外)。调用函数时,它是类的实例对象。您还在某些函数中创建主窗口小部件的新实例:请参阅上面的inclement注释。这样做没有多大意义。请阅读手册:https://docs.python.org/2/tutorial/classes.html#class-objects
关于您的其他问题:
- 有没有办法为动态创建的id分配id或引用 小部件的数量
醇>
您可以在实例化对象时使用指定的id参数直接分配和ID,例如散射体(ID = '本身份识别码')。您可以通过其ID来引用它,但我个人的偏好是使用列表跟踪对象(见下文)
- 我如何引用小部件孙子?
醇>
简单地说,不要!直接在列表中跟踪它们并使用对其属性的引用,而不是创建维度的辅助列表:
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也会更好..没有必要单独创建它们
- 方法/函数声明的参数,例如(self,* args) - 它们做了什么?
醇>
self是对已调用其函数的实例的引用。 * args是未命名参数列表的扩展。看看这个问题:*args and **kwargs?
作为最终评论,如果您按照说明中的说法调用canvas.clear,那么您也会删除按钮和框,因为您正在使用主窗口小部件的画布。创建另一个类来包含您的行并将其位置链接到框。当您在该对象上调用canvas.clear时,它将仅清除该行。如果在框位置/大小更改时更新线对象,则还可以将线的渲染移动到kivy文件中,并消除无关的时钟调度。