如何在 Kivy 上的屏幕之间导航?

时间:2021-02-25 21:23:43

标签: python kivy screen kivy-language

我正在制作一个游戏,您必须将图像拖放到某个位置,当您设法将所有图像都正确时,它会跳转到下一个屏幕。

Game screen

我创建了一个计数器,将点击次数相加,当它达到一定的点击次数时,它会转到下一个屏幕,但显然有些事情我做得不对。当它完成测试时,它会停留在同一个屏幕上,不会跳到下一个。

可能是什么问题?

arrastrar.kv

#:kivy 1.9.0
#:import FadeTransition kivy.uix.screenmanager.FadeTransition

<RelScreenManager>:
    transition: FadeTransition()
    Relaciona3x2:
    Relaciona4x2:
    Relaciona5x2:

<Relaciona3x2>:
    name: 'Rel3x2'
    id: Rel3x2
    canvas.before:
        Rectangle:
            pos: self.pos
            size: self.size
            source: 'data/img/fondobosque.jpg'
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            id: from_box
            
            Widget:
            
            DragableButton:
                canvas:
                    Rectangle:
                        pos: self.pos
                        size: self.size
                        source: 'data/img/letra_i/iglu.png'
                bound_zone_objects: [from_box, to_box ]
                droppable_zone_objects: [to_box, ]
                drop_func: app.greet
                
            Widget:
                
            DragableButton:
                canvas:
                    Rectangle:
                        pos: self.pos
                        size: self.size
                        source: 'data/img/letra_i/indio.png'
                bound_zone_objects: [from_box, to_box, ]
                droppable_zone_objects: [to_box, ]
                drop_func: app.greet

            Widget:
                
            DragableButton:
                canvas:
                    Rectangle:
                        pos: self.pos
                        size: self.size
                        source: 'data/img/letra_m/moto.png'
                bound_zone_objects: [from_box, to_box, ]
                #droppable_zone_objects: [to_box, ]
                drop_func: app.greet
                
            Widget:
        
        BoxLayout:
            id: from_box
            
            Widget:
            
            DragableButton:
                canvas:
                    Rectangle:
                        pos: self.pos
                        size: self.size
                        source: 'data/img/letra_u/una.png'
                bound_zone_objects: [from_box, to_box, ]
                #droppable_zone_objects: [to_box, ]
                drop_func: app.greet
                
            Widget:
            
            DragableButton:
                canvas:
                    Rectangle:
                        pos: self.pos
                        size: self.size
                        source: 'data/img/letra_i/iman_1.png'
                bound_zone_objects: [from_box, to_box, ]
                droppable_zone_objects: [to_box, ]
                drop_func: app.greet
                
            Widget:
            
            DragableButton:
                canvas:
                    Rectangle:
                        pos: self.pos
                        size: self.size
                        source: 'data/img/letra_u/urraca.png'
                bound_zone_objects: [from_box, to_box, ]
                #droppable_zone_objects: [to_box, ]
                drop_func: app.greet

            Widget:
            
        Image:
            id: to_box
            source: "data/img/caldero.png"
            
<Relaciona4x2>:
    name: 'Rel4x2'
    id: Rel4x2
    AnchorLayout:
        Image:
            source: "data/img/fondobosque.jpg"
            allow_stretch: True
            keep_ratio: False
            
<Relaciona5x2>:
    name: 'Rel5x2'
    id: Rel5x2
    AnchorLayout:
        Image:
            source: "data/img/fondobosque.jpg"
            allow_stretch: True
            keep_ratio: False

arrastrar.py

from kivy.uix.boxlayout import BoxLayout
__all__ = ('Relaciona3x2', 'Relaciona4x2', 'Relaciona5x2')

import kivy
kivy.require('1.0.6')

from DragableButton import DragableButton
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.widget import Widget

Builder.load_file('arrastrar.kv')

class Contador(object):
    def __init__(self, inicial=0):
        self.numero = inicial
    
    def next(self):
        self.numero += 1
        return self.numero
    
class RelScreenManager(ScreenManager):
    def __init__(self):
        super(RelScreenManager, self).__init__()
        
        self.cuenta = Contador()
        if self.cuenta.numero == 3:
            self.screen_manager.current = "Rel4x2"
        
class Relaciona3x2(Screen):
    pass

class Relaciona4x2(Screen):
    pass

class Relaciona5x2(Screen):
    pass

class ArrastraApp(App):
    def build(self):
        #Window.fullscreen = 'auto'
        
        return RelScreenManager()        
    
    def greet(self):
        #cuenta = Contador()
        print('Draggin done!')
        #print(self.cuenta.next())
        
if __name__ == "__main__":
    ArrastraApp().run()

DragableButton.py

from DragNDropWidget import DragNDropWidget
from kivy.uix.button import Button


class DragableButton(Button, DragNDropWidget):
    '''
    classdocs
    '''
    def __init__(self, **kw):
        '''
        Constructor
        '''
        #Button.__init__(self, **kw)
        super(DragableButton, self).__init__(**kw)
        self.size_hint = (None, None)

    def __deepcopy__(self, dumb):
        return DragableButton(text=self.text,
                              droppable_zone_objects=self.droppable_zone_objects,
                              bound_zone_objects=self.bound_zone_objects,
                              drag_opacity=self.drag_opacity,
                              drop_func=self.drop_func,
                              remove_on_drag=self.remove_on_drag)

拖动NDropWidget.py

from kivy.core.window import Window
from kivy.animation import Animation
import copy
from kivy.uix.widget import Widget
from kivy.properties import (
    ListProperty, NumericProperty, BooleanProperty, ObjectProperty)


class DragNDropWidget(Widget):
    # let kivy take care of kwargs and get signals for free by using
    # properties
    droppable_zone_objects = ListProperty([])
    bound_zone_objects = ListProperty([])
    drag_opacity = NumericProperty(1.0)
    drop_func = ObjectProperty(None)
    drop_args = ListProperty([])
    remove_on_drag = BooleanProperty(True)

    def __init__(self, **kw):
        super(DragNDropWidget, self).__init__(**kw)

        self.register_event_type("on_drag_start")
        self.register_event_type("on_being_dragged")
        self.register_event_type("on_drag_finish")
        self.register_event_type("on_motion_over")
        self.register_event_type("on_motion_out")

        self._dragged = False
        self._dragable = True
        self._fired_already = False

    def set_dragable(self, value):
        self._dragable = value

    def set_remove_on_drag(self, value):
        """
        This function sets the property that determines whether the dragged widget is just copied from its parent or taken from its parent
        @param value: either True or False. If True then the widget will disappear from its parent on drag, else the widget will jsut get copied for dragging
        """
        self.remove_on_drag = value

    def set_bound_axis_positions(self):
        for obj in self.bound_zone_objects:
            try:
                if self.max_y < obj.y+obj.size[1]-self.size[1]:
                    self.max_y = obj.y+obj.size[1]-self.size[1]
            except AttributeError:
                self.max_y = obj.y+obj.size[1]-self.size[1]
            try:
                if self.max_x < obj.x+obj.size[0]-self.size[0]:
                    self.max_x = obj.x + obj.size[0]-self.size[0]
            except AttributeError:
                self.max_x = obj.x+obj.size[0]-self.size[0]
            try:
                if self.min_y > obj.y:
                    self.min_y = obj.y
            except AttributeError:
                self.min_y = obj.y
            try:
                if self.min_x > obj.x:
                    self.min_x = obj.x
            except AttributeError:
                self.min_x = obj.x

    def on_touch_down(self, touch):
        if self.collide_point(touch.x, touch.y) and self._dragable:
            # detect if the touch is short - has time and end (if not dispatch drag)
            if abs(touch.time_end - touch.time_start) > 0.2:
                self.dispatch("on_drag_start")


    def on_touch_up(self, touch):
        if self._dragable and self._dragged:
            self.short_touch = True
            self.dispatch("on_drag_finish")
            self.short_touch = False

    def on_touch_move(self, touch):
        if self._dragged and self._dragable:
            x = touch.x
            y = touch.y

            try:
                if touch.x < self.min_x:
                    x = self.min_x
                if touch.x > self.max_x:
                    x = self.max_x
                if touch.y < self.min_y:
                    y = self.min_y
                if touch.y > self.max_y:
                    y = self.max_y
            except AttributeError:
                pass
            self.pos = (x, y)

    def easy_access_dnd(self, function_to_do, function_to_do_out, arguments = [], bind_functions = []):
        """
        This function enables something that can be used instead of drag n drop
        @param function_to_do: function that is to be called when mouse_over event is fired on the widget
        @param bind_functions: what is really to be done - background function for GUI functionality
        """
        Window.bind(mouse_pos=self.on_motion)
        self.easy_access_dnd_function = function_to_do
        self.easy_access_dnd_function_out = function_to_do_out
        self.easy_access_dnd_function_aguments = arguments
        self.easy_access_dnd_function_binds = bind_functions

    def on_motion(self, etype, moutionevent):
        if self.collide_point(Window.mouse_pos[0], Window.mouse_pos[1]):
            if not self._fired_already:
                self.dispatch("on_motion_over")
        else:
            self.dispatch("on_motion_out")

    def on_motion_over(self):
        self.easy_access_dnd_function(
            self.easy_access_dnd_function_aguments,
            self.easy_access_dnd_function_binds)

        self._fired_already = True

    def on_motion_out(self):
        try:
            self.easy_access_dnd_function_out()
        except AttributeError:
            pass
        self._fired_already = False

    def on_drag_start(self):
        print ('drag start')
        self.opacity = self.drag_opacity
        self.set_bound_axis_positions()
        self._old_drag_pos = self.pos
        self._old_parent = self.parent
        self._old_index = self.parent.children.index(self)
        self._dragged = True
        if self.remove_on_drag:
            self.reparent(self)
        else:
            #create copy of object to drag
            self.reparent(self)
            # the final child class MUST implement __deepcopy__
            # IF self.remove_on_drag == False !!! In this case this is
            # met in DragableArhellModelImage class
            copy_of_self = copy.deepcopy(self)
            self._old_parent.add_widget(copy_of_self, index=self._old_index)

    def on_drag_finish(self):
        print ('drag finish')
        if self._dragged and self._dragable:
            self.opacity = 1.0
            dropped_ok = False
            for obj in self.droppable_zone_objects:
                if obj.collide_point(*self.pos):
                    dropped_ok = True
            if dropped_ok:
                self.drop_func(*self.drop_args)
                anim = Animation(opacity=0, duration=0.7, t="in_quad")
                anim.bind(on_complete=self.deparent)
                anim.start(self)
            else:
                anim = Animation(pos=self._old_drag_pos, duration=0.7, t="in_quad")
                if self.remove_on_drag:
                    anim.bind(on_complete = self.reborn)
                else:
                    anim.bind(on_complete = self.deparent)
                anim.start(self)
            self._dragged = False

    def deparent(self, widget="dumb", anim="dumb2"):
        self.get_root_window().remove_widget(self)

    def on_being_dragged(self):
        print ('being dragged')

    def reborn(self, widget, anim):
        self.deparent()
        self._old_parent.add_widget(self, index=self._old_index)

    def reparent(self, widget):
        parent = widget.parent
        orig_size = widget.size
        if parent:
            parent.remove_widget(widget)
            parent.get_root_window().add_widget(widget)
            widget.size_hint = (None, None)
            widget.size = orig_size

0 个答案:

没有答案