Как я могу запустить обновление сетки из обработчика событий в OrbTK? - PullRequest
0 голосов
/ 06 ноября 2019

Я начал изучать Rust и хотел бы создать очень простого тральщика. Я думаю, что я закончил с игровой логикой, и я работаю над GUI. У меня проблема с обработкой клика по полям. Когда пользователь нажимает на одно из полей, он вызывает две вещи:

  1. Обновление игрового состояния (в настоящее время только открытие соответствующего поля)
  2. Запуск перестроения сетки, визуализирующей фактическоесостояние игры. Эта сетка содержит виджет, который обрабатывает событие нажатия.

Я удалил обработку логики игры, так как она не сильно связана с возникшей проблемой:

Мой Cargo.toml:

[package]
name = "orbtk_grid_event_handler"
version = "0.1.0"
edition = "2018"

[dependencies]
orbtk = "0.2.29"
orbimage = "0.1.17"
orbclient = "0.3.17"

Мой main.rs:

use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;

extern crate orbimage;
extern crate orbtk;

use orbtk::traits::Click;
use orbtk::{Color, Grid, Image, Place, Rect, Window};

struct MainWindowInner {
    grid: Arc<Grid>,
}

impl MainWindowInner {
    fn new() -> Self {
        MainWindowInner { grid: Grid::new() }
    }
}

pub struct MainWindow {
    inner: Rc<RefCell<MainWindowInner>>,
}

impl MainWindow {
    pub fn new() -> Self {
        MainWindow {
            inner: Rc::new(RefCell::new(MainWindowInner::new())),
        }
    }

    pub fn show(&self) {
        let mut window = Window::new(Rect::new(100, 100, 420, 768), "Minesweeper");

        {
            let inner = self.inner.borrow();
            inner.grid.position(0, 0).spacing(1, 1);
            window.add(&inner.grid);
            Self::update_grid(self.inner.clone());
        }
        window.exec();
    }

    fn update_grid(inner_param: Rc<RefCell<MainWindowInner>>) {
        let inner = inner_param.borrow();
        let grid = inner.grid.clone();

        grid.insert(0, 0, &Self::create_cell(inner_param.clone()));//
    }

    fn create_cell(inner_param: Rc<RefCell<MainWindowInner>>) -> Arc<Image> {
        let cell = Image::from_color(16, 16, Color::rgb(0, 0, 255));

        cell.on_click(move |_cell, _point| {
            MainWindow::update_grid(inner_param.clone()); // Panic happens inside this call
        });
        return cell;
    }
}

fn main() {
    MainWindow::new().show();
}

И обратная трассировка стека выглядит следующим образом:

thread 'main' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:1165:5
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.37/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.37/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:61
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1028
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1412
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:65
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:50
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:189
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:206
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:469
  11: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:376
  12: rust_begin_unwind
             at src/libstd/panicking.rs:303
  13: core::panicking::panic_fmt
             at src/libcore/panicking.rs:84
  14: core::result::unwrap_failed
             at src/libcore/result.rs:1165
  15: core::result::Result<T,E>::expect
             at /rustc/c23a7aa778b0dfeffbf83b099bdf971242c1e1ac/src/libcore/result.rs:960
  16: core::cell::RefCell<T>::borrow_mut
             at /rustc/c23a7aa778b0dfeffbf83b099bdf971242c1e1ac/src/libcore/cell.rs:869
  17: orbtk::layouts::grid::Grid::insert
             at /home/kovi/.cargo/registry/src/github.com-1ecc6299db9ec823/orbtk-0.2.29/src/layouts/grid.rs:67
  18: orbtk_grid_event_handler::MainWindow::update_grid
             at src/main.rs:48
  19: orbtk_grid_event_handler::MainWindow::create_cell::{{closure}}
             at src/main.rs:55
  20: <orbtk::primitives::image::Image as orbtk::traits::click::Click>::emit_click
             at /home/kovi/.cargo/registry/src/github.com-1ecc6299db9ec823/orbtk-0.2.29/src/primitives/image.rs:56
  21: <orbtk::primitives::image::Image as orbtk::widgets::Widget>::event
             at /home/kovi/.cargo/registry/src/github.com-1ecc6299db9ec823/orbtk-0.2.29/src/primitives/image.rs:106
  22: <orbtk::layouts::grid::Grid as orbtk::widgets::Widget>::event
             at /home/kovi/.cargo/registry/src/github.com-1ecc6299db9ec823/orbtk-0.2.29/src/layouts/grid.rs:197
  23: orbtk::window::Window::drain_events
             at /home/kovi/.cargo/registry/src/github.com-1ecc6299db9ec823/orbtk-0.2.29/src/window.rs:230
  24: orbtk::window::Window::exec
             at /home/kovi/.cargo/registry/src/github.com-1ecc6299db9ec823/orbtk-0.2.29/src/window.rs:302
  25: orbtk_grid_event_handler::MainWindow::show
             at src/main.rs:41
  26: orbtk_grid_event_handler::main
             at src/main.rs:62
  27: std::rt::lang_start::{{closure}}
             at /rustc/c23a7aa778b0dfeffbf83b099bdf971242c1e1ac/src/libstd/rt.rs:61
  28: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:48
  29: std::panicking::try::do_call
             at src/libstd/panicking.rs:288
  30: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:80
  31: std::panicking::try
             at src/libstd/panicking.rs:267
  32: std::panic::catch_unwind
             at src/libstd/panic.rs:396
  33: std::rt::lang_start_internal
             at src/libstd/rt.rs:47
  34: std::rt::lang_start
             at /rustc/c23a7aa778b0dfeffbf83b099bdf971242c1e1ac/src/libstd/rt.rs:61
  35: main
  36: __libc_start_main
  37: _start
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Когда я нажимаю на поле, вызывается закрытие обработчика событияВ этом закрытии я обрабатываю состояние игры и после этого пытаюсь обновить графический интерфейс. Паника возникает из функции grid.insert в функции update_grid: я добавил два комментария, чтобы быть более конкретным.

Паника, вызванная внутренней структурой данных сетки: поле entries заимствовано во времяобработка событий, поэтому его нельзя изменить из обработчика событий (функция insert определенно изменяет его).

Как я могу решить эту проблему? Хорошим решением было бы как-то извлечь обновление GUI из обработчика событий, но я не могу найти, как это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...