Диалог выбора файла
Заметьте, что это модуль dialogs.rs
GTK Rust API не используют преимущества типажа Drop в Rust, поэтому при появлении диалога, он будет всегда находится на вашем экране. К счастью, мы можем решить эту проблему самостоятельно, создав тип для GtkFileChooserDialogs и реализовать типаж Drop, чтобы разрушить внутренний диалог после сброса типа.
Создание OpenDialog
Начнём с создания простой кортёжной структуры.
# #![allow(unused_variables)] #fn main() { pub struct OpenDialog(FileChooserDialog); #}
Реализуем простой метод new() для этой структуры и создадим внутренний FileChooserDialog.
# #![allow(unused_variables)] #fn main() { impl OpenDialog { pub fn new(path: Option<PathBuf>) -> OpenDialog { // Создадим новый диалог выбора файлов, чтобы открыть их. let open_dialog = FileChooserDialog::new( Some("Open"), Some(&Window::new(WindowType::Popup)), FileChooserAction::Open, ); // Добавим кнопки отмены и открытия для этого диалога. open_dialog.add_button("Cancel", ResponseType::Cancel.into()); open_dialog.add_button("Open", ResponseType::Ok.into()); // Установим стандартный путь открытия файла. path.map(|p| open_dialog.set_current_folder(p)); OpenDialog(open_dialog) } } #}
Смысл FileChooserDialog состоит в том, чтобы дать имя диалогу и предоставить новое окно с типом Popup, а затем выбрать соответствующее FileChooserAction, который нужен вашим критериям при использовании. В этом случае, мы создадим диалог Open, чтобы открыть файл.
После создания установите label для двух кнопок внутри диалога и установите нужный ResponseTypes с этими кнопками. Очень важно знать, нажал ли пользователь Cancel или Ok.
Как только закончим, нам необходимо обернуть тип в нашем OpenDialog.
Создание SaveDialog
Диалог Save практически идентичен.
# #![allow(unused_variables)] #fn main() { pub struct SaveDialog(FileChooserDialog); impl SaveDialog { pub fn new(path: Option<PathBuf>) -> SaveDialog { // Инициализируем новый даилог встроенный в всплывающее окно. let save_dialog = FileChooserDialog::new( Some("Save As"), Some(&Window::new(WindowType::Popup)), FileChooserAction::Save, ); // Добавим кнопки cancel и save к диалогу. save_dialog.add_button("Cancel", ResponseType::Cancel.into()); save_dialog.add_button("Save", ResponseType::Ok.into()); // Установим стандартный путь открытия файла. path.map(|p| save_dialog.set_current_folder(p)); SaveDialog(save_dialog) } } #}
Реализация типажа Drop
Объекты в GTK разрушаются с помощью метода destroy(). Если вы хотите разрушить наш диалог после того, как мы сбросили их обращение (handles), мы можем сделать это автоматически реализуя типаж Drop на обоих типах.
# #![allow(unused_variables)] #fn main() { impl Drop for OpenDialog { fn drop(&mut self) { self.0.destroy(); } } impl Drop for SaveDialog { fn drop(&mut self) { self.0.destroy(); } } #}
Глупо, но просто. Мы вызываем метод destroy() для внутреннего значения наших новых типов.
Реализация полезного метода
Следующий метод может быть добавлен в блок impl для обоих типов и они упрощают запуск и получают данные на выходе, которые мы хотим.
# #![allow(unused_variables)] #fn main() { pub fn run(&self) -> Option<PathBuf> { if self.0.run() == ResponseType::Ok.into() { self.0.get_filename() } else { None } } #}
В основном мы показываем/запускаем диалог и проверяем вывод, чтобы определить, получили ли мы ответ Ok. Если ответ Ok, мы просто пытаемся вернуть имя файла, которое существует или не существует.
Весь код
# #![allow(unused_variables)] #fn main() { use gtk::*; use std::path::PathBuf; /// Обёрнутый FileChooserDialog автоматически разрушающийся при сбрасывании. pub struct OpenDialog(FileChooserDialog); /// Обёрнутый FileChooserDialog автоматически разрушающийся при сбрасывании. pub struct SaveDialog(FileChooserDialog); impl OpenDialog { pub fn new() -> OpenDialog { // Создадим новый диалог выбора файлов, чтобы открыть их. let open_dialog = FileChooserDialog::new( Some("Open"), Some(&Window::new(WindowType::Popup)), FileChooserAction::Open, ); // Добавим кнопки cancel и open для этого диалога. open_dialog.add_button("Cancel", ResponseType::Cancel.into()); open_dialog.add_button("Open", ResponseType::Ok.into()); OpenDialog(open_dialog) } pub fn run(&self) -> Option<PathBuf> { if self.0.run() == ResponseType::Ok.into() { self.0.get_filename() } else { None } } } impl SaveDialog { pub fn new() -> SaveDialog { // Инициализируем новый диалог, встроенный в всплывающее окно. let save_dialog = FileChooserDialog::new( Some("Save As"), Some(&Window::new(WindowType::Popup)), FileChooserAction::Save, ); // Добавим кнопки cancel и save к диалогу. save_dialog.add_button("Cancel", ResponseType::Cancel.into()); save_dialog.add_button("Save", ResponseType::Ok.into()); SaveDialog(save_dialog) } pub fn run(&self) -> Option<PathBuf> { if self.0.run() == ResponseType::Ok.into() { self.0.get_filename() } else { None } } } impl Drop for OpenDialog { fn drop(&mut self) { self.0.destroy(); } } impl Drop for SaveDialog { fn drop(&mut self) { self.0.destroy(); } } #}