在Nannou中使用滑块值更新结构体字段



我正在尝试通过使用Nannou创建动画来学习Rust。动画由根据数学函数移动的圆圈组成,我想在GUI中添加一个滑块,通过以下代码来控制圆圈的数量

我已经创建了滑动条并添加了它,我可以看到滑动条的值在我移动它时发生了变化。然而,问题是,当我移动滑块时,fn model中的num_circles的值没有更新,并且我无法将其链接到滑块。

换句话说,我不能将num_circles连接到fn model上,但我可以将其连接到fn updatefn veiw函数。

TLDR我知道我的代码很长,但请不要担心。我在fn model函数内有一个for循环,它使用常量num_circles。我希望能够使用滑块更改此值,但到目前为止,我只能在fn updatefn view函数中更新它。是否有办法将fn model中的num_circles的值链接到滑块?

for i in 0..num_circles 
下面是我的代码:
use nannou::prelude::*;
use nannou_egui::{self, egui, Egui};
const num_circles: usize = 255;
fn main() {
nannou::app(model).update(update).run();
}
pub struct Model {
frequency: f32,
amplitude: f32,
phase: f32,
num_circles: usize,
num_points: usize,
circle_points: Vec<Vec<Point2>>,
settings: Settings,
egui: Egui,
}
pub struct Settings {
num_circles: usize,
}
fn model(app: &App) -> Model {
let window_id = app
.new_window()
.view(view)
.raw_event(raw_window_event)
.build()
.unwrap();
let window = app.window(window_id).unwrap();
let egui = Egui::from_window(&window);
let frequency = 125.0;
let amplitude = 1.4;
let phase = 1.0;
let num_points = 155;
let window_rect = app.window_rect();
let center = window_rect.xy();
let radius = window_rect.w().min(window_rect.h()) / 2.0;
let circle_radius = radius / (num_circles as f32);
let mut circle_points = Vec::with_capacity(num_circles);
for i in 0..num_circles {
let mut points = Vec::with_capacity(num_points);
for j in 0..num_points {
let angle = j as f32 * 4.0 * PI / (num_points as f32);
let x = center.x + angle.sin() * circle_radius * (i as f32 + 2.0);
let y = center.y + angle.cos() * circle_radius * (i as f32 + 2.0);
points.push(pt2(x, y));
}
circle_points.push(points);
}
Model {
frequency,
amplitude,
phase,
num_circles,
num_points,
circle_points,
egui,
settings: Settings { num_circles: 255 },
}
}
fn update(_app: &App, model: &mut Model, _update: Update) {
let egui = &mut model.egui;
let settings = &model.settings;
egui.set_elapsed_time(_update.since_start);
let ctx = egui.begin_frame();
egui::Window::new("Settings").show(&ctx, |ui| {
ui.label("Num Circles:");
ui.add(egui::Slider::new(&mut model.settings.num_circles, 1..=255));
});
for i in 0..model.num_circles {
for j in 0..model.num_points {
let x = model.circle_points[i][j].x
+ (-25.0 * PI * model.frequency * j as f32 / model.num_points as f32 + model.phase)
.sin()
* model.amplitude;
let y = model.circle_points[i][j].y
+ (25.0 * PI * model.frequency * j as f32 / model.num_points as f32 + model.phase)
.cos()
* model.amplitude;
model.circle_points[i][j] = pt2(x, y);
}
}
model.phase += 0.01;
}
fn raw_window_event(_app: &App, model: &mut Model, event: &nannou::winit::event::WindowEvent) {
model.egui.handle_raw_event(event);
}
fn view(app: &App, model: &Model, frame: Frame) {
let settings = &model.settings;
let draw = app.draw();
draw.background().color(WHITE);
for i in 0..settings.num_circles {
let hue = i as f32 / settings.num_circles as f32;
let color = hsla(hue, 1.0, 0.5, 1.0);
draw.polyline()
.weight(1.5)
.points(model.circle_points[i].clone())
.color(color);
}
draw.to_frame(app, &frame).unwrap();
model.egui.draw_to_frame(&frame).unwrap();
}

问题是fn model中的num_circles总是保持255并且不改变。我怎样才能让这里的值随着滑块改变呢?

我将感谢任何帮助如何正确更新"num_circles">

当我在model函数中使用model.settings.num_circles时,它会引发错误并且不工作。

model()函数的作用是创建初始的Model。它只在程序启动时调用一次。因此,在model()函数中更新num_circles是没有意义的,因为该函数不会被再次调用。

这段代码有一个方面令人困惑;您有三个名称为num_circles的不同绑定:

  1. const num_circles: usize = 255;。按照约定,Rust中的常量都是大写的。如果这是为了表示圆圈的初始数量,INITIAL_NUM_CIRCLES是一个好名字。

  2. Model->num_circles

  3. Model->settingsnum_circles

也许你只打算在你的模型中存储一个num_circles?

至于如何使用滑块值更新Modelnum_circles字段:您已经在这行上这样做了(至少,您正在更新一个)你的num_circles,因为正如我提到的,你的Model中有两个:

ui.add(egui::Slider::new(&mut model.settings.num_circles, 1..=255));

您正在为slider函数提供对num_circles的可变引用。它将负责将更新后的滑块值写入该引用。