Kivy: 在我的应用中添加工具栏
我正在尝试实现一个简单的工具栏。目前我在基础部分遇到了困难。
我现在的目标:
制作一个位于应用侧边的工具栏,让用户可以往主界面添加小部件。
我目前的进展:
我已经有了一个白色的矩形,位置也对了。还有一些按钮可以添加正确的小部件。不过,我需要把这些按钮放在正确的位置。
看起来我理想中想用某种布局(比如Box)。但是我不知道怎么把这个布局只嵌入到这个矩形里。
我也不明白为什么到目前为止我做的这些不管用。
当前代码:
我会附上一个能运行的代码片段,但按钮的位置不对。如果需要,我也可以提供更简洁的代码(只要问我就行 :))。
Python代码:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import Property, NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.graphics import Color, Ellipse, Line
from kivy.clock import Clock
import math
class GraphToolBar(Widget):
def add_buttons(self, game):
createNodeButton = Button(text = 'CreateNode', pos = (self.x,game.height))
createEdgeButton = Button(text = 'CreateEdge', pos = (self.x,0.8*game.height))
self.add_widget(createNodeButton)
self.add_widget(createEdgeButton)
def createNode(instance):
newNode = GraphNode()
game.add_widget(newNode)
print "Node Created"
def createEdge(instance):
newEdge = GraphEdge()
game.add_widget(newEdge)
print "Edge Created"
createNodeButton.bind(on_press=createNode)
createEdgeButton.bind(on_press=createEdge)
pass
class GraphInterface(Widget):
node = ObjectProperty(None)
toolbar = ObjectProperty(None)
def update(self, dt):
for widget in self.children:
if isinstance(widget, GraphEdge) and widget.collide_widget(self):
widget.check_connection()
def construct_toolbar(self):
self.toolbar.add_buttons(self)
class GraphNode(Widget):
r = NumericProperty(1.0)
def __init__(self, **kwargs):
self.size= [50,50]
self.pos = [175,125]
self.r = 1.0
super(GraphNode, self).__init__(**kwargs)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
if touch.grab_current == None:
self.r = 0.6
touch.grab(self)
return True
return super(GraphNode, self).on_touch_down(touch)
def on_touch_move(self, touch):
if touch.grab_current is self:
self.pos=[touch.x-25,touch.y-25]
for widget in self.parent.children:
if isinstance(widget, GraphEdge) and widget.collide_widget(self):
widget.snap_to_node(self)
def on_touch_up(self, touch):
if touch.grab_current is self:
touch.ungrab(self)
self.r = 1.0
# and finish up here
pass
class GraphEdge(Widget):
r = NumericProperty(1.0)
connected_point_0 = Property(False)
connected_point_1 = Property(False)
connected_node_0 = Widget()
connected_node_1 = Widget()
def __init__(self, **kwargs):
super(GraphEdge, self).__init__(**kwargs)
with self.canvas:
Color(self.r, 1, 1, 1)
self.line = Line(points=[100, 200, 200, 200], width = 2.0, close = True)
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
def snap_to_node(self, node):
if self.collide_widget(node):
distance_from_0 = [math.sqrt(((self.line.points[0]-node.center[0])**2 + (self.line.points[1]-node.center[1])**2))]*2
distance_from_1 = [math.sqrt(((self.line.points[2]-node.center[0])**2 + (self.line.points[3]-node.center[1])**2))]*2
if distance_from_0 < distance_from_1:
if (self.connected_point_0 is False):
print "collision"
if node is not self.connected_node_1:
self.connected_point_0 = True
self.connected_node_0 = node
self.line.points = node.center + self.line.points[2:]
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
return True
elif distance_from_1 < distance_from_0:
if (self.connected_point_1 is False):
print "collision"
if node is not self.connected_node_0:
self.connected_point_1 = True
self.connected_node_1 = node
self.line.points = self.line.points[:-2] + node.center
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
return True
pass
def check_connection(self):
if self.connected_point_0:
self.line.points = self.connected_node_0.center + self.line.points[2:]
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
self.r = self.connected_node_1.r
if self.connected_point_1:
self.line.points = self.line.points[:2] + self.connected_node_1.center
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
self.r = self.connected_node_1.r
class GraphApp(App):
def build(self):
game = GraphInterface()
game.construct_toolbar()
Clock.schedule_interval(game.update, 1.0/20.0)
return game
if __name__ == '__main__':
GraphApp().run()
.kv 文件:
#:kivy 1.0.9
<GraphInterface>:
node: graph_node
toolbar: graph_toolbar
GraphNode:
id: graph_node
center: self.parent.center
GraphToolBar:
id: graph_toolbar
size: root.width * 2/10, root.height
x: root.width * 8/10
y: 0
<GraphToolBar>:
size: 10,100
canvas:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
<GraphNode>:
size: 50, 50
canvas:
Color:
rgba: (root.r,1,1,1)
Ellipse:
pos: self.pos
size: self.size
<GraphEdge>:
size: self.size
center: self.center
canvas:
Color:
rgba: (root.r,1,1,1)
Line:
width: 2.0
close: True
谢谢你的耐心!
1 个回答
1
如果我理解得没错的话,你只是想把那些按钮放到白色的矩形上。这可以很简单地通过使用 BoxLayout
来实现,正如你提到的。只需要把这一行
class GraphToolBar(Widget):
改成这一行
class GraphToolBar(BoxLayout):