如何解决“必须首先将控件添加到页面”的问题。在 flet 中使用 GestureDetector 时出错?

问题描述 投票:0回答:1

我正在尝试使用 flet 制作 janggi(国际象棋变体)游戏。我想对片段使用拖放操作,因此我按照 flet 文档中的 Solitaire 教程进行操作。当我尝试执行“move_on_top”部分时出现问题。在添加 move_on_top 代码之前,一切都按预期完美运行。我可以自由地移动这些碎片。但是,在我添加 move_on_top 函数后,它有时会起作用,但它也会随机导致 AssertionError,并且拖动不再起作用。

Future exception was never retrieved
future: <Future finished exception=AssertionError('Control must be added to the page first.')>
Traceback (most recent call last):
  File "C:\Users\andyp\AppData\Local\Programs\Python\Python312\Lib\concurrent\futures\thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\andyp\AppData\Local\Programs\Python\Python312\Lib\site-packages\flet_core\page.py", line 950, in wrapper
    handler(*args)
  File "c:\limbaksa\janggi-v2\janggiBoard.py", line 22, in drag
    e.control.update()
  File "C:\Users\andyp\AppData\Local\Programs\Python\Python312\Lib\site-packages\flet_core\control.py", line 314, in update
    assert self.__page, "Control must be added to the page first."
           ^^^^^^^^^^^
AssertionError: Control must be added to the page first.

我认为这与 move_on_top 函数有关。我认为当我在函数删除并将该片段重新附加到控件后尝试更新它们时,就会发生错误。但我不明白为什么会发生这种情况,因为该函数在删除它后将其添加回控件中。我的代码在这里,我尽可能地简化了它。有90个隐形槽位,棋子根据棋盘放置在槽位上。 janggibase.Board 包含有关棋盘的信息,例如棋盘上的棋子列表。 janggibase.Piece 包含有关该片段的信息,例如它的位置。我还将完整代码上传到[我的github](github.com/limbaksa/janggi-v2/)

import flet as ft
import janggibase

def move_on_top(piece,controls):
    controls.remove(piece)
    controls.append(piece)
    piece.board.update()

def start_drag(e:ft.DragStartEvent):
    move_on_top(e.control,e.control.board.controls)
    e.control.board.move_start_top=e.control.top
    e.control.board.move_start_left=e.control.left

def bounce_back(board,piece):
    piece.top=board.move_start_top
    piece.left=board.move_start_left
    board.update()

def drag(e: ft.DragUpdateEvent):
   e.control.top = max(0, e.control.top + e.delta_y)
   e.control.left = max(0, e.control.left + e.delta_x)
   e.control.update()

def drop(e:ft.DragEndEvent):
    for slot in e.control.board.slots:
        if (
            abs(e.control.top - slot.top) < 20
            and abs(e.control.left - slot.left) < 20
        ):
            place(e.control, slot)
            break
    else:
        bounce_back(e.control.board,e.control)
    e.control.update()

def place(piece,slot):
        piece.top=slot.top
        piece.left=slot.left
        piece.board.update()


class janggiPiece(ft.GestureDetector):
    def __init__(self, piece: janggibase.Piece, board: "janggiBoard"):
        super().__init__()
        self.piece=piece
        self.board=board
        self.mouse_cursor=ft.MouseCursor.MOVE
        self.drag_interval=5
        self.on_pan_start=start_drag
        self.on_pan_update=drag
        self.on_pan_end=drop
        self.left = 60 * (piece.location // 10)
        self.top = 60 * (9 - piece.location % 10)
        self.content=ft.Container(
            width=60,
            height=60,
            border_radius=ft.border_radius.all(5),
            content=ft.Image(f"img/{str(piece).upper()}{piece.color}.png"),
        )
    



class Slot(ft.Container):
    def __init__(self, top, left):
        super().__init__()
        self.ontop = None
        self.width = 60
        self.height = 60
        self.left = left
        self.top = top


class janggiBoard(ft.Stack):
    def __init__(self, board: janggibase.Board):
        super().__init__()
        self.board = board
        self.slots = []
        self.controls = []
        self.width = 540
        self.height = 600
        for i in range(90):
            self.slots.append(Slot(60 * (9 - i % 10), 60 * (i // 10)))
        self.controls.extend(self.slots)
        self.piecelist = []
        for color in range(2):
            for piece in self.board.pieces[color]:
                self.piecelist.append(janggiPiece(piece, self))
        self.controls.extend(self.piecelist)
        self.move_start_top=None
        self.move_start_left=None


if __name__ == "__main__":
    def main(page):
        page.add(janggiBoard(janggibase.Board(15)))

    ft.app(target=main)

我还尝试如下切换 move_on_top 函数,以便该片段永远不会从控件中移除,但我仍然遇到相同的错误。

def move_on_top(piece,controls:list):
    i=controls.index(piece)
    controls[i],controls[-1]=controls[-1],controls[i]
    piece.board.update()
python python-3.x flet
1个回答
0
投票

我在链接的存储库中查看了您的代码。 主要问题是,在您的辅助方法中,您更新

board
而不是更新
piece
。我对链接存储库中的代码进行了以下 2 项修改 (
janggiBoard.py
),它再次工作了:

    def bounce_back(board, piece):
        # ...
        piece.update()

    def place(piece, slot):
        # ...
        piece.update()
© www.soinside.com 2019 - 2024. All rights reserved.