Как изменить переменную в главной функции в Flet?

Вопрос или проблема

В начале программы я создаю случайный список узлов и линий между ними, чтобы представить граф:

import flet as ft
import flet.canvas as cv
import random
import numpy as np

def generateNodes(n):
    a = []
    for _ in range(n):
        a.append(ft.Offset(random.randint(100, 400), random.randint(100, 400)))
    return a

def generateEdges(nodes):
    e = []
    sum = 0
    for i in range(len(nodes)):
        for j in range(i + 1, len(nodes)):
            e.extend([nodes[i], nodes[j]])
            d = np.sqrt((nodes[i].x - nodes[j].x) ** 2 + (nodes[i].y - nodes[j].y) ** 2)
            sum += d
    return (e, d)

В моей главной функции есть Canvas и Button. При нажатии кнопки я хочу поменять местами два случайных узла и снова отобразить граф.

def swap(a, i, j):
    a[i], a[j] = a[j], a[i]

def main(page: ft.Page):
    a = generateNodes(4)
    edges, totalDistance = generateEdges(a)

    page.title = "Пример приложения"
    page.window.width = 500
    page.window.height = 500
    page.window.resizable = False

    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    node_paint = ft.Paint(
        stroke_width=8, style=ft.PaintingStyle.STROKE, color=ft.colors.LIGHT_BLUE
    )
    edge_paint = ft.Paint(stroke_width=4, style=ft.PaintingStyle.STROKE)

    cvs = cv.Canvas(
        [
            cv.Points(edges, point_mode=cv.PointMode.LINES, paint=edge_paint),
            cv.Points(a, point_mode=cv.PointMode.POINTS, paint=node_paint),
        ],
        width=500,
        height=500,
        expand=True,
    )

    title_text = ft.Text(
        value=totalDistance, size=20, weight=ft.FontWeight.BOLD, text_align="CENTER"
    )

    def swap_clicked(e):
        swap(a, random.randint(0, 3), random.randint(0, 3))
        edges2, totalDistance2 = generateEdges(a)
        title_text.value = totalDistance2    
        page.update()

    page.add(cvs)
    page.add(title_text)
    page.add(ft.ElevatedButton(text="Поменять местами", on_click=swap_clicked))

ft.app(main)

Мне удалось изменить totalDistance после того, как я поменял местами узлы, но я не могу понять, как я могу заново нарисовать граф.

Не могли бы вы помочь? Заранее спасибо.

Ответ или решение

Конечно! Для того чтобы перерисовать граф после изменения положения узлов в вашем приложении Flet, вам необходимо обновить Canvas, добавив новые координаты для узлов и новые связи (edges). В вашей функции swap_clicked вы уже генерируете новые значения для edges и totalDistance, так что вам просто нужно обновить содержимое канваса.

Вот полный исправленный код с необходимыми изменениями:

import flet as ft
import flet.canvas as cv
import random
import numpy as np

def generateNodes(n):
    a = []
    for _ in range(n):
        a.append(ft.Offset(random.randint(100, 400), random.randint(100, 400)))
    return a

def generateEdges(nodes):
    e = []
    sum = 0
    for i in range(len(nodes)):
        for j in range(i + 1, len(nodes)):
            e.extend([nodes[i], nodes[j]])
            d = np.sqrt((nodes[i].x - nodes[j].x) ** 2 + (nodes[i].y - nodes[j].y) ** 2)
            sum += d
    return (e, sum)

def swap(a, i, j):
    a[i], a[j] = a[j], a[i]

def main(page: ft.Page):
    a = generateNodes(4)
    edges, totalDistance = generateEdges(a)

    page.title = "Example App"
    page.window.width = 500
    page.window.height = 500
    page.window.resizable = False

    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    node_paint = ft.Paint(
        stroke_width=8, style=ft.PaintingStyle.STROKE, color=ft.colors.LIGHT_BLUE
    )
    edge_paint = ft.Paint(stroke_width=4, style=ft.PaintingStyle.STROKE)

    cvs = cv.Canvas(
        [
            cv.Points(edges, point_mode=cv.PointMode.LINES, paint=edge_paint),
            cv.Points(a, point_mode=cv.PointMode.POINTS, paint=node_paint),
        ],
        width=500,
        height=500,
        expand=True,
    )

    title_text = ft.Text(
        value=str(totalDistance), size=20, weight=ft.FontWeight.BOLD, text_align="CENTER"
    )

    def swap_clicked(e):
        # Выбор двух случайных индексов для замены
        i, j = random.sample(range(len(a)), 2)
        swap(a, i, j)
        edges2, totalDistance2 = generateEdges(a)

        # Обновление значений в канвасе
        cvs.get_children()[0].points = edges2  # Обновляем линии
        cvs.get_children()[1].points = a       # Обновляем узлы
        title_text.value = str(totalDistance2)  # Обновляем текст с общей дистанцией
        page.update()

    page.add(cvs)
    page.add(title_text)
    page.add(ft.ElevatedButton(text="Swap", on_click=swap_clicked))

ft.app(main)

Объяснение изменений:

  1. Изменение функции swap_clicked: Теперь вы используете random.sample для выбора двух уникальных индексов, которые будут обменяны. Это предотвращает случайную замену одного и того же узла.

  2. Обновление канваса: После обновления координат узлов и связей, вы должны обновить Canvas, чтобы отобразить новые данные. Мы обновляем points для edges и a в зависимости от служебных элементов канваса.

  3. Текст поля: Мы преобразуем значение totalDistance2 в строку, чтобы оно корректно отображалось в текстовом элементе.

Теперь при нажатии на кнопку "Swap" граф будет перерисовываться с новыми координатами узлов и пересчитанной общей длиной.

Оцените материал
Добавить комментарий

Капча загружается...