我在更新先前固定位置的位置时遇到问题(实现为从BellyButton继承的自定义圆形按钮标记),使得按钮的中心始终位于同一位置,无论比例或位置如何有潜在的Scatter。我是这样做的,这样按钮大小就不会随着分散而缩放。
以下代码是我与数据库一起使用的简化版本 - 这就是为什么它有这么多方法等等。我需要belly_pos
和belly_text
来编写这些代码。到数据库。
到目前为止我所知道的是,在扩展和拖动Scatter时, Marker.pos
保留在制造商实例的正确位置,但我不知道为什么 - 因为我有效地更新了belly_pos
Marker.center
,而不是Marker.pos
。我在画布上添加了一些线条来更好地说明它。
考虑以下代码(您需要将一些图片作为' map.jpg' 放到同一个文件夹中):
from kivy.app import App
from kivy.lang import Builder
from kivy.logger import Logger as logging
import kivy.metrics as kvmetrics
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.behaviors.button import ButtonBehavior
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import StringProperty
from kivy.properties import ListProperty
from kivy.properties import NumericProperty
kivy_lang = '''
<ProjectMap>:
BoxLayout:
id: main_box
BellyButton:
id: add_new
belly_pos: (root.size[0]-self.size[0]/2,root.y+self.size[1]/2)
belly_text: "+"
on_press: root.add_marker()
<MapScatter>:
scatter_pos: imgscatter.pos
scatter_scale: imgscatter.scale
Scatter:
id: imgscatter
size_hint: None, None
size: img.size
auto_bring_to_front: False
do_rotation: False
Image:
id: img
source: root.map_path
# pos: imgscatter.pos
size: self.texture_size
canvas.before:
Color:
rgba: 1, 1, 1, 1
BorderImage:
border: (root.image_border,root.image_border,root.image_border,root.image_border)
size: (self.width+2*root.image_border,self.height+2*root.image_border)
pos: (-1*root.image_border,-1*root.image_border)
<BellyButton>:
size_hint: None, None
size: (belly_label.texture_size[1]*1.2, belly_label.texture_size[1]*1.2)
center: self.belly_pos
canvas.after:
Color:
rgba: 0,1,0,1
Line:
points: self.x, self.y, self.x+10, self.y+10
canvas:
Color:
rgba: self.belly_color
Ellipse:
pos: self.pos
size: self.size
Line:
points: self.x, self.y, self.center[0], self.center[1]
Label:
id: belly_label
size: self.texture_size
font_size: sp(app.gui_multiplier)
pos: [root.center_x-self.size[0]/2,root.center_y-self.size[1]/2]
text: root.belly_text
<Marker>:
'''
class BellyButton(ButtonBehavior, Widget):
belly_pos = ListProperty([0,0])
belly_text = StringProperty('#')
belly_color = ListProperty([1,0,0,1])
def __init__(self, *args, **kwargs):
super(BellyButton, self).__init__(*args,**kwargs)
class Marker(BellyButton):
location = [0,0]
def __init__(self, *args, **kwargs):
super(Marker, self).__init__(*args,**kwargs)
#self.center = self.location
def update_pos(self, offset, scale):
self.belly_pos = [offset[0] +self.size[0]/2 +(self.location[0]) * scale, offset[1]+ self.size[1]/2+(self.location[1]) * scale]
logging.info('''info: updated belly_pos context::
current scatter pos: {}
current scatter scale: {}
saved marker location: {}
calculated belly_pos: {}'''.format(offset,scale,self.location, self.belly_pos))
return self.belly_pos
def save_pos(self,offset,scale):
self.location = [(self.location[0] - offset[0])/scale, (self.location[1] - offset[1])/scale]
return self.location
class ProjectMap(FloatLayout):
def __init__(self,*args,**kwargs):
FloatLayout.__init__(self,**kwargs)
self.markers = []
self.load_map()
def load_map(self,**kwargs):
self.ids.main_box.clear_widgets()
self.ids.add_new.disabled = False
self.current_map = MapScatter('map.jpg')
self.current_map.bind(scatter_pos=self.transfer_pos)
self.current_map.bind(scatter_scale=self.transfer_pos)
for marker in self.markers:
self.current_map.add_widget(marker)
self.ids.main_box.add_widget(self.current_map)
img_bigger_dim = self.current_map.ids.img.texture_size.index(max(self.current_map.ids.img.texture_size))
self.current_map.ids.imgscatter.scale = 0.9 * Window.size[img_bigger_dim] / self.current_map.ids.imgscatter.size[0]
self.current_map.ids.imgscatter.scale_min = 0.5 * self.current_map.ids.imgscatter.scale
self.current_map.ids.imgscatter.center = (Window.size[0]/2,Window.size[1]/2)
def transfer_pos(self, *args, **kwargs):
for no in range(0,len(self.current_map.children)-1):
self.current_map.children[no].update_pos(self.current_map.scatter_pos,self.current_map.scatter_scale)
def add_marker(self,*args,**kwargs):
# self.new_marker.destroy()
self.new_marker = Marker()
self.place_marker_hint()
def place_marker_hint(self,*args,**kwargs):
self.marker_hint = BellyButton()
self.marker_hint.belly_color[3] = 0.5
self.marker_hint.belly_pos = self.center
self.marker_hint.bind(on_press=self.save_marker)
self.add_widget(self.marker_hint)
self.ids.add_new.disabled = True
def calc_new_marker_pos(self):
self.new_marker.location = self.center
self.new_marker.save_pos(self.current_map.scatter_pos,self.current_map.scatter_scale)
logging.info('''info: marker saved location context::
current window center: {}
current window scatterMap scatter_pos: {}
current window scatterMap scatter_scale: {}
current scatterMap scatter size: {}
current scatterMap img size: {}
marker size: {}
saved marker location: {}
calculated new Marker belly_pos(its center): {}
'''. format(self.center, self.current_map.scatter_pos, self.current_map.scatter_scale, self.current_map.ids.imgscatter.size, self.current_map.ids.img.size, self.new_marker.size, self.new_marker.location, self.new_marker.belly_pos ))
def save_marker(self, *args):
self.calc_new_marker_pos()
self.new_marker.belly_text = str(len(self.current_map.children)-1)
self.markers.append(self.new_marker)
self.current_map.clear_widgets()
self.remove_widget(self.marker_hint)
self.load_map()
class MapScatter(FloatLayout):
map_path = StringProperty('')
scatter_pos = ListProperty([0,0])
scatter_scale = NumericProperty(1.0)
image_border = NumericProperty(1.0)
def __init__(self, map_path,*args,**kwargs):
FloatLayout.__init__(self,*args,**kwargs)
self.map_path = map_path
self.image_border = kvmetrics.sp(app.gui_multiplier)*0.1
class MyApp(App):
gui_multiplier = NumericProperty(30)
def build(self):
Builder.load_string(kivy_lang)
return ProjectMap()
def on_pause(self):
return True
if __name__ == '__main__':
app = MyApp()
app.run()