在 Rust 中使用 GTK+ 框架開發桌面應用程式,需要熟悉 GTK+ 的元件和訊號機制。本文將示範如何建立一個包含滾動視窗、列表框和按鈕的應用程式,並講解如何處理使用者輸入和更新介面。透過逐步的程式碼範例,讀者可以學習如何使用 GTK+ 構建具有互動功能的使用者介面。此外,文章還提供圖表說明,以更清晰地展現元件之間的關係和資料流程,幫助讀者更容易理解 GTK+ 框架的運作方式。
簡介
在這個範例中,我們將建立一個簡單的 GTK 應用程式,展示如何使用 GTK 建立一個帶有滾動視窗、列表框和按鈕的圖形使用者介面。
建立滾動視窗和列表框
首先,我們需要建立一個滾動視窗和列表框。滾動視窗將用於容納列表框,列表框將用於顯示專案。
let scrolled_window = gtk::ScrolledWindow::new(gtk::Adjustment::NONE, gtk::Adjustment::NONE);
let listbox = gtk::ListBox::new();
scrolled_window.add(&listbox);
建立按鈕
接下來,我們需要建立兩個按鈕:新增按鈕和刪除按鈕。新增按鈕將用於新增新專案到列表框中,刪除按鈕將用於刪除選中的專案。
let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 5);
let add_button = gtk::Button::with_label("Add");
let delete_button = gtk::Button::with_label("Delete");
hbox.add(&add_button);
hbox.add(&delete_button);
新增按鈕的功能
當新增按鈕被點選時,我們需要彈出一個對話方塊,讓使用者輸入新專案的名稱和數量。然後,我們將這個新專案新增到列表框中。
add_button.connect_clicked(move |_| {
let dialog = gtk::Dialog::with_buttons(Some("Add Item"), Some(&window), gtk::DialogFlags::MODAL, &[("Ok", ResponseType::Ok), ("Cancel", ResponseType::Cancel)]);
dialog.set_default_response(ResponseType::Ok);
let content_area = dialog.content_area();
let entry = gtk::Entry::new();
content_area.add(&entry);
let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0);
content_area.add(&spin_button);
dialog.connect_response(move |dialog, resp| {
if resp == ResponseType::Ok {
let text = entry.text();
if !text.is_empty() {
model.append(&RowData::new(&text, spin_button.value() as u32));
}
}
dialog.close();
});
dialog.show_all();
});
刪除按鈕的功能
當刪除按鈕被點選時,我們需要刪除選中的專案。
delete_button.connect_clicked(move |_| {
let selected = listbox.selected_row();
if let Some(selected) = selected {
let idx = selected.index();
model.remove(idx as u32);
}
});
組裝介面
最後,我們需要組裝介面,將滾動視窗、列表框、新增按鈕和刪除按鈕新增到主視窗中。
vbox.pack_start(&hbox, false, false, 0);
vbox.pack_start(&scrolled_window, true, true, 0);
window.add(&vbox);
window.show_all();
圖表翻譯:
graph LR A[主視窗] --> B[滾動視窗] B --> C[列表框] A --> D[新增按鈕] A --> E[刪除按鈕] D --> F[對話方塊] F --> G[輸入框] F --> H[旋轉按鈕] E --> I[刪除選中的專案]
GTK 框架的 Rust 實作:打造桌面應用
簡介
GTK 是一個廣泛使用的 GUI 框架,尤其是在 Linux 平臺上。雖然 GTK 的檔案和資源相對較少,但仍然可以使用 Rust 來開發桌面應用。在本章中,我們將探討如何使用 GTK 框架在 Rust 中建立一個基本的桌面應用。
建立 GTK 應用
首先,需要新增 gtk
依賴到 Cargo.toml
中:
[dependencies]
gtk = { version = "0.16.0", features = ["v3_22"] }
然後,建立一個新的 Rust 專案,並新增必要的 import:
use gtk::glib;
use gtk::prelude::*;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
建立主介面
建立一個 build_ui
函式來構建主介面:
fn build_ui(application: >k::Application) {
// 建立主視窗
let window = gtk::Window::new(gtk::WindowType::Toplevel);
window.set_title("Grocery List App");
window.set_default_size(350, 70);
// 建立垂直盒子
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
// 新增垂直盒子到主視窗
window.add(&vbox);
// 顯示所有元件
window.show_all();
}
執行應用
建立一個 main
函式來執行應用:
fn main() {
// 建立一個新的 GTK 應用
let application = gtk::Application::new(
Some("com.grocery_list"),
Default::default(),
);
// 連線 UI 和應用
application.connect_activate(build_ui);
// 執行應用
application.run(Default::default());
}
測試應用
執行 cargo run
命令來測試應用。應該會顯示一個類似於圖 7.2 的視窗。
新增專案對話方塊
建立一個 add_item_dialog
函式來新增專案對話方塊:
fn add_item_dialog(window: >k::Window) {
// 建立對話方塊
let dialog = gtk::Dialog::new(
Some("Add Item"),
Some(window),
gtk::DialogFlags::Modal,
&[
("_OK", gtk::ResponseType::Ok),
("_Cancel", gtk::ResponseType::Cancel),
],
);
// 新增對話方塊內容
let entry = gtk::Entry::new();
dialog.get_content_area().add(&entry);
// 顯示對話方塊
dialog.show_all();
}
編輯專案對話方塊
建立一個 edit_item_dialog
函式來編輯專案對話方塊:
fn edit_item_dialog(window: >k::Window) {
// 建立對話方塊
let dialog = gtk::Dialog::new(
Some("Edit Item"),
Some(window),
gtk::DialogFlags::Modal,
&[
("_OK", gtk::ResponseType::Ok),
("_Cancel", gtk::ResponseType::Cancel),
],
);
// 新增對話方塊內容
let entry = gtk::Entry::new();
dialog.get_content_area().add(&entry);
// 顯示對話方塊
dialog.show_all();
}
刪除專案
建立一個 delete_item
函式來刪除專案:
fn delete_item(window: >k::Window) {
// 刪除專案邏輯
}
重點事項
- GTK 是一個廣泛使用的 GUI 框架,尤其是在 Linux 平臺上。
- 可以使用 Rust 來開發桌面應用。
- 建立 GTK 應用需要新增
gtk
依賴到Cargo.toml
中。 - 建立主介面需要使用
build_ui
函式。 - 執行應用需要使用
main
函式。
練習
- 建立一個可以建立多個視窗的應用。
- 建立一個具有進度條的應用,並在按下開始按鈕時啟動進度條。
答案
- 建立一個新專案,並新增必要的 import。然後,建立一個
build_ui
函式來構建主介面,並新增多個視窗。 - 建立一個新專案,並新增必要的 import。然後,建立一個
build_ui
函式來構建主介面,並新增進度條和開始按鈕。
建立多視窗應用程式的使用者介面
首先,我們需要建立一個主視窗,然後在其中新增按鈕和其他元件。以下是建立主視窗的步驟:
建立主視窗
fn create_main_window(application: >k::Application) -> gtk::ApplicationWindow {
let window = gtk::ApplicationWindow::new(application);
window.set_title("多視窗應用程式");
window.set_default_size(400, 320);
window.set_position(gtk::WindowPosition::Center);
window.show_all();
window
}
建立子視窗
fn create_sub_window(
application: >k::Application,
title: &str,
main_window_entry: >k::Entry,
id: usize,
windows: &Rc<RefCell<HashMap<usize, glib::WeakRef<gtk::Window>>>,
) {
let window = gtk::Window::new(gtk::WindowType::Toplevel);
application.add_window(&window);
window.set_title(title);
window.set_default_size(400, 320);
// 當子視窗關閉時,移除其對應的專案
glib::clone!(@weak windows => @default-return Inhibit(false), move |_, _| {
windows.borrow_mut().remove(&id);
Inhibit(false)
});
// 建立按鈕,當按鈕被點選時,通知主視窗
let button = gtk::Button::with_label(&format!("通知主視窗 ID {}", id));
button.connect_clicked(move |_| {
main_window_entry.buffer().set_text(&format!("子視窗 {} 被點選", id));
});
window.add(&button);
window.show_all();
// 將子視窗新增到雜湊表中
windows.borrow_mut().insert(id, window.downgrade());
}
建立使用者介面
fn build_ui(application: >k::Application) {
// 建立主視窗
let main_window = create_main_window(application);
// 建立子視窗
let mut id = 0;
let windows = Rc::new(RefCell::new(HashMap::new()));
let main_window_entry = gtk::Entry::new();
main_window.add(&main_window_entry);
// 建立按鈕,當按鈕被點選時,建立新的子視窗
let button = gtk::Button::with_label("建立新視窗");
button.connect_clicked(move |_| {
let title = format!("子視窗 {}", id);
create_sub_window(application, &title, &main_window_entry, id, &windows);
id += 1;
});
main_window.add(&button);
main_window.show_all();
}
以上程式碼建立了一個多視窗應用程式,當按鈕被點選時,會建立新的子視窗,並在主視窗中顯示通知。每個子視窗都有一個按鈕,當按鈕被點選時,會通知主視窗。
建立多視窗應用程式
首先,我們需要初始化一個集合來儲存子視窗,使用 HashMap
來儲存子視窗的 ID 和對應的 gtk::Window
參照。這個 HashMap
將被包裹在 Rc
和 RefCell
中,以便於分享和修改。
let windows: Rc<RefCell<HashMap<usize, glib::WeakRef<gtk::Window>>>> =
Rc::new(RefCell::new(HashMap::new()));
接下來,我們需要建立一個主視窗,並將其儲存在 window
變數中。這個主視窗將被用來顯示通知。
let window = create_main_window(application);
為了方便地更新所有子視窗的標題,我們需要建立一個輸入欄位,允許使用者輸入新的標題。這個輸入欄位將被新增到主視窗中。
let windows_title_entry = gtk::Entry::new();
windows_title_entry.set_placeholder_text(Some("Update all sub-window's titles"));
當輸入欄位的內容發生變化時,我們需要更新所有子視窗的標題。為此,我們需要連線輸入欄位的 changed
訊號,並使用 glib::clone!
宏來捕捉 windows
和 windows_title_entry
的弱參照。
windows_title_entry.connect_changed(move |_| {
let text = windows_title_entry.buffer().text();
for window in windows.borrow().values() {
if let Some(w) = window.upgrade() {
w.set_title(&text);
}
}
});
為了顯示通知,我們需要建立一個新的輸入欄位,並將其新增到主視窗中。
let entry = gtk::Entry::new();
entry.set_editable(false);
entry.set_placeholder_text(Some("Event notifications will be sent here"));
現在,我們需要建立一個按鈕來建立新的子視窗。當按鈕被點選時,我們需要建立一個新的子視窗,並將其新增到 windows
中。
let button = gtk::Button::with_label("Create a new window");
glib::clone!(@weak windows_title_entry, @weak entry, @weak application => move |_| {
let id = generate_new_id(&windows.borrow());
create_sub_window(&application, &windows_title_entry.buffer().text(), &entry, id, &windows);
});
最後,我們需要將所有的部件新增到主視窗中,並顯示主視窗。
let layout = gtk::Box::new(gtk::Orientation::Vertical, 5);
layout.add(&windows_title_entry);
layout.add(&button);
layout.add(&entry);
window.add(&layout);
window.show_all();
這樣,我們就完成了多視窗應用程式的建立。當使用者點選建立新視窗按鈕時,將會建立一個新的子視窗,並將其新增到 windows
中。當子視窗被點選時,將會顯示通知在主視窗中。
GTK+ 進階教程:建立進度條應用
介紹
在這個教程中,我們將學習如何使用 GTK+ 建立一個簡單的進度條應用。這個應用將包括一個主視窗、一個進度條和一個開始按鈕。當使用者按下開始按鈕時,進度條將開始執行,並在完成時顯示一個完成視窗。
建立專案
首先,讓我們建立一個新的 GTK+ 專案。開啟終端,執行以下命令:
cargo new progress_tracker
cd progress_tracker
cargo add gtk
定義結構體
在 src/main.rs
中,新增以下程式碼:
use gtk::prelude::*;
use gtk::{gio, glib};
use std::cell::{RefCell, Cell};
use std::rc::Rc;
use std::thread;
use std::time::Duration;
pub struct Application {
pub widgets: Rc<Widgets>,
}
pub struct Widgets {
pub window: gtk::ApplicationWindow,
pub header: Header,
pub view_stack: gtk::Stack,
pub main_view: MainView,
pub complete_view: CompleteView,
}
pub struct Header {
container: gtk::HeaderBar,
}
pub struct MainView {
pub container: gtk::Grid,
pub progress: gtk::ProgressBar,
pub button: gtk::Button,
}
pub struct CompleteView {
pub container: gtk::Grid,
}
實作 CompleteView
讓我們從 CompleteView
開始。這個視窗將顯示一個標籤,指示任務已完成。
impl CompleteView {
pub fn new() -> Self {
let label = gtk::Label::new(None);
label.set_markup("Task complete");
label.set_halign(gtk::Align::Center);
label.set_valign(gtk::Align::Center);
label.set_vexpand(true);
label.set_hexpand(true);
let container = gtk::Grid::new();
container.set_vexpand(true);
container.set_hexpand(true);
container.add(&label);
Self { container }
}
}
實作 MainView
現在,讓我們實作 MainView
。這個視窗將包含一個進度條和一個開始按鈕。
impl MainView {
pub fn new() -> Self {
let progress = gtk::ProgressBar::new();
progress.set_text(Some("Progress Bar"));
progress.set_show_text(true);
progress.set_hexpand(true);
let button = gtk::Button::new();
button.set_label("start");
button.set_halign(gtk::Align::Center);
let container = gtk::Grid::new();
container.attach(&progress, 0, 0, 1, 1);
container.attach(&button, 0, 1, 1, 1);
Self {
container,
progress,
button,
}
}
}
建立主視窗
現在,讓我們建立主視窗。
fn main() {
// 建立 GTK+ 應用
let application = gtk::Application::new(
Some("com.example.progress-tracker"),
Default::default(),
);
// 建立主視窗
let window = gtk::ApplicationWindow::new(application, Default::default());
window.set_title("Progress Tracker");
window.set_default_size(300, 200);
// 建立 Header
let header = Header {
container: gtk::HeaderBar::new(),
};
// 建立 MainView 和 CompleteView
let main_view = MainView::new();
let complete_view = CompleteView::new();
// 建立 view_stack
let view_stack = gtk::Stack::new();
view_stack.add(&main_view.container);
view_stack.add(&complete_view.container);
// 建立 Widgets
let widgets = Widgets {
window: window.clone(),
header,
view_stack,
main_view,
complete_view,
};
// 建立 Application
let application = Application {
widgets: Rc::new(widgets),
};
// 顯示主視窗
window.show_all();
}
執行應用
現在,讓我們執行應用。
cargo run
這將啟動主視窗,顯示進度條和開始按鈕。當你按下開始按鈕時,進度條將開始執行,並在完成時顯示完成視窗。
圖表翻譯:
graph LR A[主視窗] --> B[進度條] B --> C[開始按鈕] C --> D[完成視窗]
這個圖表顯示了主視窗、進度條、開始按鈕和完成視窗之間的關係。
內容解密:
這個應用使用 GTK+ 建立了一個簡單的進度條介面。當使用者按下開始按鈕時,進度條將開始執行,並在完成時顯示完成視窗。這個應用使用了 GTK+ 的 gtk::ProgressBar
和 gtk::Button
類別來建立進度條和開始按鈕。
GTK+ 應用程式開發:進度條和視窗管理
在本節中,我們將深入探討如何使用 GTK+ 建立一個具有進度條和視窗管理的應用程式。首先,我們需要建立一個 MainView
來管理我們的應用程式的主視窗。
從使用者經驗視角來看,使用 Rust 與 GTK+ 框架構建桌面應用程式,雖然能提供高度客製化的介面設計和效能最佳化,但開發過程仍面臨一些挑戰。本文深入剖析了 GTK+ 框架在 Rust 中的應用,涵蓋了滾動視窗、列表框、按鈕、多視窗管理以及進度條等核心元件的建立與整合。透過程式碼範例與圖表,逐步闡明瞭 UI 構建的流程與邏輯。
分析 GTK+ 的 Rust 生態可以發現,雖然社群持續發展,但相關教學資源和檔案仍相對匱乏,開發者需要花費更多時間探索和解決問題。此外,GTK+ 的訊號與回呼機制雖然強大,但也增加了程式碼的複雜度,尤其在處理多視窗和非同步操作時,需要更謹慎地管理狀態和資源,避免潛在的記憶體洩漏或效能瓶頸。對於習慣物件導向程式設計的開發者而言,適應 Rust 的所有權和借用系統也需要一定的學習曲線。
展望未來,隨著 Rust 語言的普及和 GTK+ 框架的持續演進,預期會有更多工具和函式函式庫出現,簡化 GTK+ 應用程式的開發流程。跨平臺支援和更完善的開發者工具將是未來發展的重點。而結合 Rust 的安全性與 GTK+ 的跨平臺特性,可望在桌面應用程式開發領域開創新的局面。
對於有意使用 Rust 和 GTK+ 開發桌面應用程式的團隊,玄貓建議優先關注核心功能的實作,並逐步探索 GTK+ 的進階特性。同時,積極參與社群討論和貢獻程式碼,將有助於加速 GTK+ 在 Rust 生態的成熟,並提升整體開發體驗。