1

Тема: gtk4 помилка при використанні метода структрури для запуску програми

Під час використання connect_startup і connect_activate
з методом структури з'являється помилка:
application.connect_startup(main_window.build_main_window());
    |                 --------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn(&gtk4::Application)` closure, found `()`
    |                 |
    |                 required by a bound introduced by this call
    |
    = help: the trait `for<'a> Fn<(&'a gtk4::Application,)>` is not implemented for `()`
main.rs

mod main_window;
pub use crate::main_window::MainWindow;
use gtk::{gio, prelude::*};

const APP_ID: &str = "org.gtk_rs.Movar";

fn main() {
    // Створення нового екземпляра додатка
    let application = gtk::Application::builder()
        .application_id(APP_ID)
        .build();
    let new_settings = gio::Settings::new(APP_ID);
    let main_window = MainWindow{
        settings: new_settings,
        app: application,
    };

    application.connect_startup(main_window.build_main_window());
    application.connect_activate(main_window.activate_main_window());
    application.run();
}

Методи main_window:

pub fn build_main_window(&self)  {
        //Побудова віджетів головного вікна

        self.create_actions_entries();
        self.create_accelerators();
        let menubar = self.create_menubar();
        self.app.set_menubar(Some(&menubar));

    }

pub fn activate_main_window(&self) {
        //Створення головного вікна програми та його відображення
        let main_window = gtk::ApplicationWindow::builder()
            .application(&self.app)
            .title("Movar")
            .default_width(800)
            .default_height(600)
            .show_menubar(true)
            .build();

        main_window.present();
    }

Коли я використовував ці методі як просто окремі функції,
усе працювало без помилок.
Чому використання структури дає таку помилку?
Як це виправити?

2

Re: gtk4 помилка при використанні метода структрури для запуску програми

Ну вам же пише: expected ... closure, found `()`.
Очікувалося замикання.
Мабуть, треба

application.connect_startup(||main_window.build_main_window())

робити

3

Re: gtk4 помилка при використанні метода структрури для запуску програми

koala написав:

Ну вам же пише: expected ... closure, found `()`.
Очікувалося замикання.
Мабуть, треба

application.connect_startup(||main_window.build_main_window())

робити

Якщо так робити, то починаються жахи позичання кінця краю яким немає,
бо спочатку він вимагає змінну, а тоді вже і move.

4

Re: gtk4 помилка при використанні метода структрури для запуску програми

Teg Miles написав:

починаються жахи позичання

Вітаю у Rust.
Так, думаємо. Вам треба побудувати об'єкт основного вікна по сигналу startup, і в загальному випадку це може статися в невідомо якому потоці. Де саме цей об'єкт буде розміщуватися в пам'яті? Так, як ви написали - його буде Drop-нуто при виході з функції activate_main_window. Не певен, що вам це треба... а радше певен, що вам не це треба. Глянемо...

fn connect_startup<F>(&self, f: F) -> SignalHandlerId
where
    F: Fn(&Self) + 'static,

Колбек у connect_startup приймає один аргумент - &Self, тобто Application. І якщо вам треба, щоб щось лишалося після виходу з колбеку, то ви маєте покласти його в цей Application (не бачу такої можливості), або використати щось глобальне, що не є добре.
Гм. Але якщо подивитися документацію уважно, то

While Application works fine with plain Windows, it is recommended to use it together with ApplicationWindow.
...
ApplicationWindow is a Window subclass that integrates with Application.
Notably, ApplicationWindow can handle an application menubar.

І схоже, що там робиться саме те, що намагаєтеся зробити ви.

5

Re: gtk4 помилка при використанні метода структрури для запуску програми

koala написав:
Teg Miles написав:

починаються жахи позичання

Вітаю у Rust.
Так, думаємо. Вам треба побудувати об'єкт основного вікна по сигналу startup, і в загальному випадку це може статися в невідомо якому потоці. Де саме цей об'єкт буде розміщуватися в пам'яті? Так, як ви написали - його буде Drop-нуто при виході з функції activate_main_window. Не певен, що вам це треба... а радше певен, що вам не це треба. Глянемо...

fn connect_startup<F>(&self, f: F) -> SignalHandlerId
where
    F: Fn(&Self) + 'static,

Колбек у connect_startup приймає один аргумент - &Self, тобто Application. І якщо вам треба, щоб щось лишалося після виходу з колбеку, то ви маєте покласти його в цей Application (не бачу такої можливості), або використати щось глобальне, що не є добре.
Гм. Але якщо подивитися документацію уважно, то

While Application works fine with plain Windows, it is recommended to use it together with ApplicationWindow.
...
ApplicationWindow is a Window subclass that integrates with Application.
Notably, ApplicationWindow can handle an application menubar.

І схоже, що там робиться саме те, що намагаєтеся зробити ви.

Так, я створюю Application як екземпляр програми, а тоді прив'язую до нього ApplicationWindow,
що є головним вікном. Проблема в тому, що коли я запхнув ApplicationWindow і його побудову
до структури (потрібні спільні змінні, що будуть доступні всім віджетам, наприклад, налаштування),
то з'явилися нові обмеження пов'язані зі створенням екземпляра структури.
Доведеться, мабуть, Rc використати.

6

Re: gtk4 помилка при використанні метода структрури для запуску програми

Знайшов рішення. Переніс функцію активації вікна в main.
У цій функції створюю вікно та екземпляр структури MainWindow,
передаю туди всі потрібні мені параметри, роблю вікно видимим,
а тоді все це активую в основній програмі через connect_activate.
Не можна функцію активації заганяти в структуру, бо в gtk4 там свої вимоги до неї.
main.rs

mod main_window;
pub use crate::main_window::MainWindow;
use gtk::{gio, prelude::*};

const APP_ID: &str = "org.gtk_rs.Movar";

fn main() {
    // Створення нового екземпляра додатка
    let application = gtk::Application::builder()
        .application_id(APP_ID)
        .build();

    application.connect_activate(activate_main_window);
    application.run();
}

fn activate_main_window(app: &gtk::Application) {
    // Створення головного вікна програми та його відображення
    let app_window = gtk::ApplicationWindow::builder()
        .application(app)
        .title("Movar")
        .default_width(800)
        .default_height(600)
        .show_menubar(true)
        .build();

    let new_settings = gio::Settings::new(APP_ID);
    let main_window = MainWindow{
        settings: new_settings,
        app: app.clone(),
        window: app_window,
    };
    // Тут будуються складові вікна
    main_window.build_main_window();
    // Відображення вікна
    main_window.window.present();
}

Мене лише бентежить використання clone() для gtk::Application.
Воно не забагато пам'яті зжере? Чи можливо замінити на щось інше?