Вопрос или проблема
В начале программы я создаю случайный список узлов и линий между ними, чтобы представить граф:
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)
Объяснение изменений:
-
Изменение функции
swap_clicked
: Теперь вы используетеrandom.sample
для выбора двух уникальных индексов, которые будут обменяны. Это предотвращает случайную замену одного и того же узла. -
Обновление канваса: После обновления координат узлов и связей, вы должны обновить
Canvas
, чтобы отобразить новые данные. Мы обновляемpoints
дляedges
иa
в зависимости от служебных элементов канваса. -
Текст поля: Мы преобразуем значение
totalDistance2
в строку, чтобы оно корректно отображалось в текстовом элементе.
Теперь при нажатии на кнопку "Swap" граф будет перерисовываться с новыми координатами узлов и пересчитанной общей длиной.