简体   繁体   English

Kivy:用户触摸和拖动以实现裁剪功能

[英]Kivy: user touch and drag for cropping function

I'm attempting to crop an image. 我正在尝试裁剪图像。 The basic idea is that the user will drag his mouse over the image to crop it. 基本思想是用户将鼠标拖动到图像上进行裁剪。 To that end, when you click "Crop", the user can select a lower left point, then drag the rectangle up to the top right. 为此,当您单击“裁剪”时,用户可以选择左下角的点,然后将矩形拖动到右上角。 The rectangle should shade the outside area not selected. 矩形应遮挡未选中的外部区域。

I've been researching Drag behavior and simpler methods such as this answer (attempted below), but with little results. 我一直在研究“拖动行为”和更简单的方法(例如此答案) (以下尝试),但收效甚微。 As a bonus, is it possible to limit the area the user can touch and drag? 另外,是否可以限制用户可以触摸和拖动的区域?

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics import Color
from kivy.graphics import Point
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen

Builder.load_string("""

<MyScreenManager>:
    ThirdScreen:
        id: third_screen

<ThirdScreen>:
    name: '_third_screen_'
    id: third_screen
    BoxLayout:
        orientation: "vertical"
        id: third_screen_boxlayout

        Label:
            id: main_title
            text: "Title"
            size_hint: (1, 0.1)
        BoxLayout:
            id: image_box_layout
            Image:
                id: main_image
                source: "C:/Users/OneDrive/0. T2/6. Kivy/4/claymore.jpg"
        BoxLayout:
            id: button_boxlayout
            orientation: "horizontal"
            padding: 10
            size_hint: (1, 0.15)
            Button:
                id: accept_button
                text: "Okay"
                size_hint: (0.33, 1)
                on_press: root.image_accepted_by_user(root.image_address)
            Button:
                id: crop_button
                text: "Crop"
                size_hint: (0.33, 1)
                on_press: root.enable_cropping()
            Button:
                id: cancel_button
                text: "Cancel"
                size_hint: (0.33, 1) 
                on_press: root.manager.current = '_first_screen_'
""")

class MyScreenManager(ScreenManager):
    pass

class ThirdScreen(Screen):
    def enable_cropping(self):
        print("\nThirdScreen:")
        print(self.ids.main_image.pos)
        print(self.ids.main_image.size)
        print("\tAbsolute size=", self.ids.main_image.norm_image_size)
        print("\tAbsolute pos_x=", self.ids.main_image.center_x - self.ids.main_image.norm_image_size[0] / 2.)
        print("\tAbsolute pos_y=", self.ids.main_image.center_y - self.ids.main_image.norm_image_size[1] / 2.)

        self.ids.image_box_layout.add_widget(DrawInput(size_hint=(0.00000000000001, 0.00000000000001)))

class DrawInput(Widget):
    # for cropping
    draw = True
    rect_box = ObjectProperty(None)
    t_x = NumericProperty(0.0)
    t_y = NumericProperty(0.0)
    x1 = y1 = x2 = y2 = 0.0

    def on_touch_down(self, touch):
        if self.draw:
            color = (1, 1, 1, 0.4) # red, 40% shaded
            win = self.get_parent_window()
            touch.ud['group'] = str(touch.uid)

            with self.canvas:
                # variable drag
                Color(*color, mode='hsv')
                self.x1 = touch.x
                self.y1 = touch.y
                self.t_x = touch.x
                self.t_y = touch.y

                self.rect_box = [Rectangle(pos=(0, self.y1),
                                           size=(win.width, -self.y1),
                                           group=touch.ud['group']),
                                  Rectangle(pos=(0, self.y1),
                                            size=(self.x1, win.height),
                                            group=touch.ud['group']),
                                  Point(points=(self.x1, self.y1),
                                        source='particle.png',
                                        group=touch.ud['group']),

                                  Rectangle(pos=(self.t_x, self.y1),
                                            size=(win.width - self.t_x, win.height - self.y1),
                                            group=touch.ud['group']),
                                  Rectangle(pos=(self.t_x, self.t_y),
                                            size=(self.x1 - self.t_x, win.height - touch.y),
                                            group=touch.ud['group']),
                                  Point(points=(self.t_x, self.t_y),
                                        source='particle.png',
                                        group=touch.ud['group'])]

                touch.grab(self)
                print(self.x1, self.y1)

    def on_touch_move(self, touch):
        if touch.grab_current is self:
            # not working
            self.t_x = touch.x
            self.t_y = touch.y
            print(self.t_x, self.t_y)

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            # only 1 draw
            self.draw = False
            # final position
            self.x2 = touch.x
            self.y2 = touch.y

            print(self.x2, self.y2)

class MyApp(App):
    def build(self):
        return MyScreenManager()

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

The solution was to remove the DrawInput class and integrate the on_touch_down, on_touch_move and on_touch_up into the Screen. 解决方案是删除DrawInput类,并将on_touch_down,on_touch_move和on_touch_up集成到屏幕中。 NumericProperty() and ObjectProperty() allow the rectangle, wrote as a widget canvas into the kv file, to be manipulated. NumericProperty()和ObjectProperty()允许对作为小部件画布写入kv文件的矩形进行操作。

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics import Color
from kivy.graphics import Point
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen

Builder.load_string("""

<MyScreenManager>:
    ThirdScreen:
        id: third_screen

<ThirdScreen>:
    name: '_third_screen_'
    id: third_screen
    BoxLayout:
        orientation: "vertical"
        id: third_screen_boxlayout
        Label:
            id: main_title
            text: "Title"
            size_hint: (1, 0.1)
        BoxLayout:
            id: image_box_layout
            Image:
                id: main_image
                source: "C:/Users/Mark/OneDrive/0. T2/6. Kivy/4/claymore.jpg"
            Widget:
                id: image_canvas
                size_hint: (0.0000001, 0.0000001)
                canvas:
                    Rectangle:
                        id: root.rect_box
                        pos: (root.x1, root.y1)
                        size: (root.t_x, root.t_y)
        BoxLayout:
            id: button_boxlayout
            orientation: "horizontal"
            padding: 10
            size_hint: (1, 0.15)
            Button:
                id: accept_button
                text: "Okay"
                size_hint: (0.33, 1)
                on_press: root.image_accepted_by_user(root.image_address)
            Button:
                id: crop_button
                text: "Crop"
                size_hint: (0.33, 1)
                on_press: root.enable_cropping()
            Button:
                id: cancel_button
                text: "Cancel"
                size_hint: (0.33, 1) 
                on_press: root.manager.current = '_first_screen_'
""")

class MyScreenManager(ScreenManager):
    pass

class ThirdScreen(Screen):
    rect_box = ObjectProperty(None)
    t_x = NumericProperty(0.0)
    t_y = NumericProperty(0.0)
    x1 = y1 = x2 = y2 = NumericProperty(0.0)

    def enable_cropping(self):
        print("\nThirdScreen:")
        print(self.ids.main_image.pos)
        print(self.ids.main_image.size)
        print("\tAbsolute size=", self.ids.main_image.norm_image_size)
        print("\tAbsolute pos_x=", self.ids.main_image.center_x - self.ids.main_image.norm_image_size[0] / 2.)
        print("\tAbsolute pos_y=", self.ids.main_image.center_y - self.ids.main_image.norm_image_size[1] / 2.)

    def on_touch_down(self, touch):
        self.x1 = touch.x
        self.y1 = touch.y
        self.t_x = touch.x
        self.t_y = touch.y

        touch.grab(self)
        print(self.x1, self.y1)

    def on_touch_move(self, touch):
        if touch.grab_current is self:
            # not working
            self.t_x = touch.x
            self.t_y = touch.y

            print(self.t_x, self.t_y)

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            # final position
            self.x2 = touch.x
            self.y2 = touch.y

            print(self.x2, self.y2)

class MyApp(App):
    def build(self):
        return MyScreenManager()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM