Есть ли способ предотвратить перекрытие canva и textinput в kivy? - PullRequest
0 голосов
/ 29 февраля 2020

Я сделал код, где вы можете рисовать линии с помощью киви канвы, и я хотел добавить Textinput. Но проблема в том, что когда я нажимаю на Textinput ie, kivy хочет нарисовать линию и выдает ошибку:

" File "/myfolders/test.py", line 45, in on_touch_up
     touch.ud['line'].points += [touch.x, touch.y]
 KeyError: 'line' "

Вот мой код:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse, Line, Rectangle
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.uix.textinput import TextInput
from time import sleep
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scatter import Scatter
from kivy.uix.boxlayout import BoxLayout 
from math import *
isLine=False
length=0


class MyBackground(Widget):

     def __init__(self, **kwargs):

        super(MyBackground, self).__init__(**kwargs)
        with self.canvas:
            self.bg = Rectangle(source='chouettes3.jpg', pos=self.pos, size=self.size)

        self.bind(pos=self.update_bg)
        self.bind(size=self.update_bg)
     def update_bg(self, *args):
         self.bg.pos = self.pos
         self.bg.size = self.size


class MyPaintWidget(Widget):

    def on_touch_down(self, touch):
        #if self.collide_point(*touch.pos): 
             with self.canvas:
                 self.canvas.clear()
                 d=15
                 Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
                 touch.ud['line'] = Line(points=(touch.x, touch.y), width=3)



    def on_touch_up(self, touch):
        #if self.collide_point(*touch.pos): 
             touch.ud['line'].points += [touch.x, touch.y]
             points=touch.ud['line'].points
             length=sqrt(((points[0]-points[2])**2)+((points[1]-points[3])**2))
             print (length)
             with self.canvas:
                 d=15
                 Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))



class MyPaintApp(App):
    def build(self):
        f = FloatLayout()
        s = Scatter()
        b = BoxLayout(orientation='vertical')
        parent = MyBackground()
        painter = MyPaintWidget(pos_hint={'x': 100, 'center_y': 100}, size_hint=(None, None))
        textinput = TextInput(text='Hello world')
        parent.add_widget(painter)
        parent.add_widget(textinput)
        f.add_widget(parent)
        sleep(0.1)
        return f




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

Я попробовал метод self.collide_point, где что-то работает, только когда вы щелкаете по виджету, о котором идет речь, но это больше не рисует линию.

Заранее спасибо за ваши ответы!

1 Ответ

0 голосов
/ 01 марта 2020

Одной из проблем является использование класса Widget в качестве контейнера для других Widgets. Вы должны использовать класс Layout, чтобы содержать другие Widgets, в противном случае такие вещи, как pos_hint, не будут иметь никакого эффекта. Поэтому я изменил ваш код, чтобы MyBackground продлил FloatLayout. Также, использование collide_point() - хорошая идея, но обычно, когда вы переопределяете метод класса, вы также должны вызывать переопределенный метод, используя super(). Имея это в виду, вот ваш измененный код, который, я думаю, будет работать так, как вы и предполагали:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line, Rectangle
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from math import *
isLine=False
length=0


class MyBackground(FloatLayout):
     def __init__(self, **kwargs):
        super(MyBackground, self).__init__(**kwargs)
        with self.canvas:
            self.bg = Rectangle(source='chouettes3.jpg', pos=self.pos, size=self.size)

        self.bind(pos=self.update_bg)
        self.bind(size=self.update_bg)

     def update_bg(self, *args):
         self.bg.pos = self.pos
         self.bg.size = self.size


class MyPaintWidget(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
             with self.canvas:
                 self.canvas.clear()
                 d=15
                 Color(1, 0, 0, 1)
                 Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
                 touch.ud['line'] = Line(points=(touch.x, touch.y), width=3)
        return super(MyPaintWidget, self).on_touch_down(touch)


    def on_touch_up(self, touch):
         if 'line' not in touch.ud:
             return super(MyPaintWidget, self).on_touch_up(touch)
         if self.collide_point(*touch.pos):
             touch.ud['line'].points += [touch.x, touch.y]
             points=touch.ud['line'].points
             length=sqrt(((points[0]-points[2])**2)+((points[1]-points[3])**2))
             print (length)
             with self.canvas:
                 d=15
                 Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
         return super(MyPaintWidget, self).on_touch_up(touch)


class MyPaintApp(App):
    def build(self):
        parent = MyBackground()
        painter = MyPaintWidget(pos_hint={'x':0., 'center_y':0.5}, size_hint=(1, 1))
        self.textinput = TextInput(text='Hello world', pos=(0,0), size_hint=(0.1,0.1))
        parent.add_widget(painter)
        parent.add_widget(self.textinput)
        return parent


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

Я также удалил неиспользуемый код в методе build().

Как код остается, щелкнув по TextInput, вы не начнете новую строку, но вы можете закончить строку за TextInput. Если вы не хотите, чтобы это происходило, вы можете добавить проверку столкновения в методе on_touch_up(), чтобы обработать его, как показано ниже:

def on_touch_up(self, touch):
     if 'line' not in touch.ud:
         return super(MyPaintWidget, self).on_touch_up(touch)
     ti = App.get_running_app().textinput
     if self.collide_point(*touch.pos) and not ti.collide_point(*touch.pos):
         touch.ud['line'].points += [touch.x, touch.y]
         points=touch.ud['line'].points
         length=sqrt(((points[0]-points[2])**2)+((points[1]-points[3])**2))
         print (length)
         with self.canvas:
             d=15
             Rectangle(pos=(touch.x-d/2,touch.y-d/2),size=(d,d))
     else:
         self.canvas.clear()
     return super(MyPaintWidget, self).on_touch_up(touch)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...