Киви: Рисование в виджет - PullRequest
0 голосов
/ 27 марта 2020

Я собираю опыт работы с kivy, и у меня проблема с использованием центра виджетов. Моя проблема показывает следующий сценарий:

from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from functools import partial
from kivy.graphics import Color, Ellipse

class CanvasApp(App):

    def draw(self,wid, color):
         with wid.canvas:
            Color(color[0], color[1], color[2])
            Ellipse(size= (100, 100), pos=(wid.center_x, wid.center_y))
         return

    def painter(self, wid, *largs):
        self.draw(wid, (0,  1, 0))
        return

    def build(self):
        wid = Widget()

        btn_painter = Button(text='Painter',
                            on_press=partial(self.painter, wid))

        ctrl =  BoxLayout(size_hint=(1, None), height=50)
        ctrl.add_widget(btn_painter)
        root = BoxLayout(orientation='vertical')
        root.add_widget(wid)
        root.add_widget(ctrl)

        self.draw(wid, (1, 0, 0))
        return root

if __name__ == '__main__':
    CanvasApp().run()

Я хочу нарисовать круг в центре виджета (черный прямоугольник), не используя кнопку художника. Я не могу получить координаты центра. Без использования кнопки доступны только стандартные координаты центра. Как нормально процесс? Спасибо за ответы.

Ответы [ 2 ]

1 голос
/ 27 марта 2020

Проблема в том, что размер и позиция wid еще не установлены внутри метода build(). Поэтому вам нужно немного задержать вызов draw(). Попробуйте заменить вызов на draw() на:

    Clock.schedule_once(partial(self.draw, wid, (1,0,0)))

Вам также потребуется немного изменить метод draw(), чтобы обработать добавляемый аргумент dt:

def draw(self,wid, color, *args):
0 голосов
/ 01 апреля 2020

Я нашел решение своей проблемы. Все объясняет следующий сценарий:

from kivy.app import App
from kivy.graphics import Color, Rectangle, Ellipse
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class DrawArea(FloatLayout):

    def __init__(self, **kwargs):
        # make sure we aren't overriding any important functionality
        super(DrawArea, self).__init__(**kwargs)
        self.rect1 = None
        self.li_item = []
        return

    def clear_area(self):                
        for item in self.li_item:
            self.canvas.remove(item)
        self.li_item.clear()

    def draw_rect(self):
        with self.canvas:

            Color(0, 1, 0, 1)  # green; colors range from 0-1 not 0-255
            self.rect1 = Rectangle(size=self.size, pos=self.pos)

            Color(1, 0, 0, 1)  # green; colors range from 0-1 not 0-255
            width  = self.width/2
            height = self.height/2 
            pos_x = self.center_x -width/2
            pos_y = self.center_y - height/2
            self.rect2 = Rectangle(size=(width, height), pos=(pos_x, pos_y))
            self.li_item.append(self.rect1)
            self.li_item.append(self.rect2)

        return

    def draw_circle(self):
        Color(1, 0, 0)
        d = 120
        with self.canvas:
            Color(0, 1, 0)
            self.circle1 = Ellipse(size = (d,d), pos = (self.center_x-d/2, self.center_y-d/2))
            Color(0, 0, 1)
            self.circle2 = Ellipse(size = (d/2,d/2), pos = (self.center_x - self.size[0]/2, self.center_y - self.size[1]/2))
            self.li_item.append(self.circle1)
            self.li_item.append(self.circle2)
        return

class MainApp(App):

    def build(self):
        self.task = 'circle'


        root = BoxLayout(orientation = 'vertical')
        self.dra = DrawArea()
        button = Button(text = 'painter',size_hint=(1, None), height=50, on_press = self.but_paint)

        root.add_widget(self.dra)
        root.add_widget(button)

        if self.task == 'circle':
            self.dra.bind(pos = self._update_circ, size = self._update_circ)
            self.dra.draw_circle()
        else:
            self.dra.bind(size=self._update_rect, pos=self._update_rect)
            self.dra.draw_rect()

        return root

    def but_paint(self, instance):
        #self.dra.clear_area()

        if self.task == 'circle':
            self.task = 'rectangle'
        else:
            self.task = 'circle'

        if self.task == 'circle':
            self.dra.bind(pos = self._update_circ, size = self._update_circ)
            self.dra.draw_circle()
        else:
            self.dra.bind(size=self._update_rect, pos=self._update_rect)
            self.dra.draw_rect()

        return

    def _update_circ(self, instance, value):
        d = 120
        pos1_x = instance.center[0] -d/2
        pos1_y = instance.center[1] -d/2

        self.dra.circle1.pos = (pos1_x, pos1_y)

        pos2_x = instance.center[0] - instance.size[0]/2
        pos2_y = instance.center[1] - instance.size[1]/2

        self.dra.circle2.pos = (pos2_x, pos2_y)

        return

    def _update_rect(self, instance, value):
        if self.dra.rect1 != None:
            self.dra.rect1.pos = instance.pos
            self.dra.rect1.size = instance.size

        width  = instance.size[0]/2
        height = instance.size[1]/2 
        pos_x = instance.center[0] -width/2
        pos_y = instance.center[1] - height/2

        self.dra.rect2.pos = (pos_x, pos_y)
        self.dra.rect2.size = (width, height)


    def draw_rect(self):
        with self.dra.canvas.before:
            Color(0, 1, 0, 1)  # green; colors range from 0-1 not 0-255
            self.rect1 = Rectangle(size=self.dra.size, pos=self.dra.pos)

            Color(1, 0, 0, 1)  # green; colors range from 0-1 not 0-255
            width  = self.width/2
            height = self.height/2 
            self.rect2 = Rectangle(size=(width, height), pos=(self.center_x -width/2, self.center_y - height/2))

        return

if __name__ == '__main__':
    MainApp().run()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...