Kivy:基于Scatter底层更新标记中心位置

时间:2016-09-30 09:56:39

标签: python kivy

我在更新先前固定位置的位置时遇到问题(实现为从BellyButton继承的自定义圆形按钮标记),使得按钮的中心始终位于同一位置,无论比例或位置如何有潜在的Scatter。我是这样做的,这样按钮大小就不会随着分散而缩放。

以下代码是我与数据库一起使用的简化版本 - 这就是为什么它有这么多方法等等。我需要belly_posbelly_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()

0 个答案:

没有答案