Kivy:基于基线更新标记中心位置

2024-06-26 17:03:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我在更新以前固定位置的位置(实现为从BellyButton继承的自定义圆形按钮标记)时遇到问题,因此按钮的中心总是在同一个位置,而不管哪个比例或位置具有基础散点。我是这样做的,这样按钮的大小就不会随着散射而缩放。你知道吗

下面的代码是我在数据库中使用的代码的简化版本-这就是为什么它有这么多方法等。我需要belly_posbelly_text将这些方法写入数据库。你知道吗

到目前为止,我发现在缩放和拖动散布时,Marker.pos对于maker实例保持在正确的位置,但我不知道为什么-因为我正在有效地更新belly_pos,而不是Marker.pos。我在画布上加了一些线条来更好地说明它。你知道吗

考虑以下代码(您需要将一些图片放置为'地图.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()

Tags: posimportselfmapnewsizedeflocation