Тема: Рецепт створення простого меню з Checkbox і Radiobutton для gtk4
Вирішив оприлюднити цей рецепт тут, бо, як виявилося,
створити простеньке класичне меню в gtk4 ще той головняк.
Можливо, комусь буде корисне.
main.rs
mod main_window;
pub use crate::main_window::{activate_main_window, build_main_window};
use gtk::prelude::*;
fn main() {
// Створення нового екземпляра програми
let application = gtk::Application::builder()
.application_id("org.gtk-rs.Movar")
.build();
application.connect_startup(build_main_window);
application.connect_activate(activate_main_window);
application.run();
}
main_window.rs
use gtk::{gio, prelude::*};
pub fn build_main_window(app: >k::Application) {
//Побудова віджетів головного вікна
create_actions_entries(&app);
create_accelerators(&app);
let menubar = create_menubar();
app.set_menubar(Some(&menubar));
}
fn create_actions_entries(app: >k::Application){
//Створення дій, що будуть прив'язані до натискання кнопок
//Дія для кнопки Quit
let quit = gio::ActionEntry::builder("quit")
.activate(|app: >k::Application, _, _| {app.quit()})
.build();
//Дія для кнопки About
let about = gio::ActionEntry::builder("about")
.activate(|_, _, _| println!("About was pressed"))
.build();
//Дія для кнопки Manual
let manual = gio::ActionEntry::builder("manual")
.activate(|_, _, _| println!("Manual is pressed"))
.build();
//Дія для кнопки Website
let website = gio::ActionEntry::builder("website")
.activate(|_ ,_ ,_| println!("Website is pressed"))
.build();
//Дія для кнопки Dictionary settings
let dict_settings = gio::ActionEntry::builder("dict_settings")
.activate(|_ ,_, _| println!("Dictionary settings is pressed"))
.build();
//Дія для кнопки Clean search history
let clean_search_history = gio::ActionEntry::builder("clean_search_history")
.activate(|_, _, _| println!("Clean search history is pressed"))
.build();
//Дія для кнопки Show search history
let show_history_default_state: bool = true;
let show_search_history = gio::ActionEntry::builder("show_search_history")
//Створення стану(state) необхідне для того, щоб з'явилася галочка Checkbox
.state(show_history_default_state.to_variant())
//Дія прив'язується до змінної action, відстежується за її допомогою
//і перезаписується
.activate(|_, action, _| {
let state = action.state().unwrap();
let action_state: bool = state.get().unwrap();
let new_state = !action_state; // Натискання на Checkbox
action.set_state(&new_state.to_variant());
println!("Показати історію натиснуто")
})
.build();
//Комплексна дія для групи з трьома Radiobutton в розділі Interface language
let default_language_state: String = "Ukrainian".to_string();
let interface_languages = gio::ActionEntry::builder("interface_languages")
//Тип параметру треба вказати для подальшої його обробки
.parameter_type(Some(&String::static_variant_type()))
//Стан вказується по аналогії з Checkbox,
//Radiobutton є, по суті, групою зв'язаних між собою Checkbox
.state(default_language_state.to_variant())
//В активації відбувається відстежування зміни параметра
//та перезапис стану відповідного Radiobutton
.activate(move |_, action, parameter| {
// Get parameter
let parameter = parameter
.expect("Could not get parameter.")
.get::<String>()
.expect("The value needs to be of type `String`.");
let interface_language = match parameter.as_str() {
"Ukrainian" => "uk_Ua",
"English" => "en_Uk",
"Japanese" => "jp_Ja",
_ => unreachable!(),
};
//Обробка зміненого параметру та перезапис стану Radiobutton
println!("Натиснуто {}", interface_language);
action.set_state(¶meter.to_variant());
})
.build();
//Додавання дій до екземпляра програми,
//щоб вони були доступні в інших функціях
app.add_action_entries([
quit,
about,
manual,
website,
dict_settings,
clean_search_history,
show_search_history,
interface_languages,
]);
}
fn create_accelerators(app: >k::Application){
//Створення гарячих клавіш для певних елементів меню
app.set_accels_for_action("app.quit", &["<Ctrl>Q"] );
app.set_accels_for_action("app.manual", &["F1"] );
app.set_accels_for_action("app.dict_settings", &["F2"] );
}
fn create_menubar() -> gio::Menu {
//Основна функція побудови головного меню
let file_menu = create_file_menu();
let help_menu = create_help_menu();
let settings_menu = create_settings_menu();
let menubar = gio::Menu::new();
menubar.append_submenu(Some("File"), &file_menu);
menubar.append_submenu(Some("Settings"), &settings_menu );
menubar.append_submenu(Some("Help"), &help_menu);
menubar
}
fn create_file_menu() ->gio::Menu{
//Побудова підменю File
let quit_menu_item = gio::MenuItem::new(Some("Quit"), Some("app.quit"));
let file_menu = gio::Menu::new();
file_menu.append_item(&quit_menu_item);
file_menu
}
fn create_settings_menu() ->gio::Menu{
//Побудова підменю Settings
//Створення кнопки Dictionary settings
let settings_menu = gio::Menu::new();
let dict_settings_menu_item = gio::MenuItem::new(
Some("Dictionary settings"), Some("app.dict_settings") );
//Створення підменю Search history
let search_history_menu = gio::Menu::new();
let clean_search_history_menu_item = gio::MenuItem::new(
Some("Clean search history"), Some("app.clean_search_history") );
let show_search_history_menu_item = gio::MenuItem::new(
Some("Show search history"), Some("app.show_search_history") );
search_history_menu.append_item(&clean_search_history_menu_item);
search_history_menu.append_item(&show_search_history_menu_item);
//Створення підменю Interface language
let interface_language_menu = gio::Menu::new();
//Спочатку створюємо кнопку з назвою мови
let ukr_language_menu_item = gio::MenuItem::new(
Some("Ukrainian"), Some("app.interface_languages"));
let eng_language_menu_item = gio::MenuItem::new(
Some("English"), Some("app.interface_languages") );
let jap_language_menu_item = gio::MenuItem::new(
Some("Japanese"), Some("app.interface_languages") );
//Тепер прив'язуємо дію та параметр до відповідної кнопки з назвою мови
//Без цього буде лише неактивна кнопка з назвою
ukr_language_menu_item.set_action_and_target_value(
Some("app.interface_languages"), Some(&"Ukrainian".to_variant()));
eng_language_menu_item.set_action_and_target_value(
Some("app.interface_languages"), Some(&"English".to_variant()) );
jap_language_menu_item.set_action_and_target_value(
Some("app.interface_languages"), Some(&"Japanese".to_variant()));
//Додаємо відповідні кнопки до підменю вибору мов
interface_language_menu.append_item(&ukr_language_menu_item);
interface_language_menu.append_item(&eng_language_menu_item);
interface_language_menu.append_item(&jap_language_menu_item);
//Тепер додаємо усі створені кнопки й підменю до підменю вищого рівня
settings_menu.append_submenu(Some("Interface language"), &interface_language_menu);
settings_menu.append_item(&dict_settings_menu_item);
settings_menu.append_submenu(Some("Search history"), &search_history_menu );
settings_menu
}
fn create_help_menu() -> gio::Menu{
//Створення підменю Help
let about_menu_item = gio::MenuItem::new(Some("About"),Some("app.about"));
let manual_menu_item = gio::MenuItem::new(Some("Manual"), Some("app.manual") );
let website_menu_item = gio::MenuItem::new(Some("Website"), Some("app.website") );
let help_menu = gio::Menu::new();
help_menu.append_item(&about_menu_item);
help_menu.append_item(&manual_menu_item);
help_menu.append_item(&website_menu_item);
help_menu
}
pub fn activate_main_window(application: >k::Application) {
//Створення головного вікна програми та його відображення
let main_window = gtk::ApplicationWindow::builder()
.application(application)
.title("Movar")
.default_width(800)
.default_height(600)
.show_menubar(true)
.build();
main_window.present();
}