简体   繁体   中英

Swapping Widgets / Replacing Layouts in Kivy With on_touch_down()

Okay, so I've got a program that, under certain conditions, needs to remove some options and present some other ones. I originally designed it so that certain buttons would occupy the same space. However, when the on_touch_down() is triggered, the intended switch I've coded doesn't swap layouts.

from kivy.uix.widget import Widget
from kivy.config import Config
from kivy import graphics
from kivy.uix.button import Button
from SpotChess import SCBoardWidget
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.relativelayout import RelativeLayout

promote_now = False

class Chessboard(Widget):
    def __init__(self, **kwargs):
        super(Chessboard, self).__init__(**kwargs)
        self.bind(pos=self.drawBoardandPieces)
        self.bind(size=self.drawBoardandPieces)
        self.drawBoardandPieces()

    def drawBoardandPieces(self, *args):
        with self.canvas:
            # Reset the canvas in case of redraws.
            self.canvas.clear()
            # Define the lengths of the edges of the squares.
            edge_len = min(self.height, self.width) // 8
            Config.set("graphics", "resizable", True)
            for column in range(0, 8):
                for row in range(0, 8):
                    if ((row + column) % 2) == 0:
                        graphics.Color(0, 0, 1)
                        self.dark_rect = graphics.Rectangle(pos=(column*edge_len, row*edge_len),
                                                            size=(edge_len, edge_len))
                    else:
                        graphics.Color(1, 1, 1)
                        self.light_rect = graphics.Rectangle(pos=(column*edge_len, row*edge_len),
                                                             size=(edge_len, edge_len))

    # This provides all of the user's mouse interaction with the board.
    def on_touch_down(self, touch):
        global promote_now
        if promote_now == False:
            promote_now = True
            Options().swapMenus()
        else:
            promote_now = False
            Options().swapMenus()

game_board = Chessboard()

class PromotionOptions(GridLayout):
    def __init__(self, **kwargs):
        super(PromotionOptions, self).__init__(**kwargs)
        self.cols = 4

        self.queen_btn = Button(text="Q/q")
        self.rook_btn = Button(text="R/r")
        self.bishop_btn = Button(text="B/b")
        self.knight_btn = Button(text="N/n")

        self.add_widget(self.queen_btn)
        self.add_widget(self.rook_btn)
        self.add_widget(self.bishop_btn)
        self.add_widget(self.knight_btn)

class Options(GridLayout):
    def __init__(self, **kwargs):
        super(Options, self).__init__(**kwargs)
        self.cols = 1
        self.swapMenus()

    def swapMenus(self):
        global promote_now
        self.clear_widgets()
        if promote_now == False:
            # Present the menu layout for normal play.
            self.normal_play_menu = GridLayout(cols=3)
            # It contains the button to flip the board.
            self.flip_board_btn = Button(text="Flip")
            self.normal_play_menu.add_widget(self.flip_board_btn)
            self.add_widget(self.normal_play_menu)
        else:
            # Present the menu layout for pawn promotions.
            self.promotion_menu = GridLayout(cols=1)
            self.promotion_menu.add_widget(widget=PromotionOptions())
            self.add_widget(self.promotion_menu)

class SCApp(App):
    def build(self):
        top_portion = BoxLayout(orientation="vertical")
        chessboard_portion = RelativeLayout()
        chessboard_portion.add_widget(widget=game_board)
        top_portion.add_widget(widget=chessboard_portion)
        bottom_portion = BoxLayout(orientation="vertical")
        bottom_portion.add_widget(widget=Options())
        app_layout = BoxLayout(orientation="vertical")
        app_layout.add_widget(top_portion)
        app_layout.add_widget(bottom_portion)
        return app_layout

SCApp().run()

I'm clearly calling the object to perform the replacement, but it's not completing either the self.clear_widgets() or the self.add_widget() , even though I've called the function. What am I missing?

In your on_touch_down() method the

Options().swapMenus()

lines are creating new instances of the Options class, and calling the swapMenus() method of that new instance. But that new instance of Options is not in your GUI, so it haas no effecet on your App. You need to get a reference to the Options instance that IS in your GUI, and call the swapMenus() method of that instance.

You can do that by saving a reference to the Options class in your App , by replacing this line in your build() method:

    bottom_portion.add_widget(widget=Options())

with:

    self.options = Options()
    bottom_portion.add_widget(widget=self.options)

Then in the on_touch_down() method:

def on_touch_down(self, touch):
    global promote_now
    
    # get the instance of Options that is in the App
    options = App.get_running_app().options
    
    if promote_now == False:
        promote_now = True
        options.swapMenus()
    else:
        promote_now = False
        options.swapMenus()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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