Creating a GTK3 Window
It's finally time to gain some experience with GUI programming using GTK from the gtk-rs
wrapper project.
Setting the Use Statements
Like the command-line front-end, we are going to need to import article::Article
and homepage
for getting the homepage and collecting articles. However, now we are going to also import gtk
for creating GUI windows and widgets, gtk::traits::*
to allow widgets to use all their traits, gdk::ffi::GdkRGBA
for creating colors to color our widgets and finally pango
for manipulating font styles.
use article::Article;
use homepage;
use gtk;
use gtk::traits::*;
use gdk::ffi::GdkRGBA;
use pango;
Initializing GTK
The absolute first step to take when setting up a GTK GUI is to first initialize GTK. The following function will attempt to initialize GTK, and if it fails, will panic with an error that it failed to initialize.
gtk::init().unwrap_or_else(|_| panic!("Failed to initialize GTK."));
After this step, you will then set up your GUI, but at the very end you must end your main()
function with gtk::main()
, which will actually start your GUI application.
pub fn launch() {
gtk::init().unwrap_or_else(|_| panic!("Failed to initialize GTK."));
gtk::main();
}
Creating the Main Window
Between the init()
and main()
functions, we will begin setting up all of our GTK widgets and window. We will start by creating a Toplevel Window. The syntax for creating widgets is universally the same. Each widget provides a new()
method, only varying in the input variables that it accepts. the gtk::Window
type takes a WindowType
enum as input to tell the wrapper what type of window to create.
You can think of a Toplevel window as a main window to a program.
let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
Now we need to make some configurations to our newly-created gtk::Window
widget. The information that we want is the default_size()
, set_title()
and connect_delete_event()
. The first, default_size()
, will set the dimensions of the window upon launch. Then, set_title()
will set the title of the window. Finally, connect_delete_event()
will define the action to take when the window is closed.
window.set_title("Phoronix Reader");
let (width, height) = (600, 500);
window.default_size(width, height);
The hard part is understanding this next part: connect_delete_event()
. All of the connect
events take a function or closure as input, which is where the confusion lies in. This is how this event is generally configured:
window.connect_delete_event(|_,_| {
gtk::main_quit();
gtk::signal::Inhibit(true)
});
This signifies that it takes no variables as input into the closure, and simply executes gtk::main_quit()
and gtk::signal::Inhibit(true)
, which tells GTK not to interrupt this action.
We can combine all of this together into a new function specific for configuring the window. We will pass the window to the function by reference as that's simply the best practice when working with GTK widgets.
fn configure_window(window: >k::Window) {
window.set_title("Phoronix Reader");
let (width, height) = (600, 500);
window.set_default_size(width, height);
window.connect_delete_event(|_,_| {
gtk::main_quit();
gtk::signal::Inhibit(true)
});
}
Then we can call it in our launch function as such:
configure_window(&window);
To actually show the window after the program starts, you need to use the show_all()
method.
window.show_all();
phoronix_gui.rs
Review
use article::Article;
use homepage;
use gtk;
use gtk::traits::*;
use gdk::ffi::GdkRGBA;
use pango;
fn configure_window(window: >k::Window) {
window.set_title("Phoronix Reader");
let (width, height) = (600, 500);
window.set_default_size(width, height);
window.connect_delete_event(|_,_| {
gtk::main_quit();
gtk::signal::Inhibit(true)
});
}
pub fn launch() {
gtk::init().unwrap_or_else(|_| panic!("Failed to initialize GTK."));
let window = gtk::Window::new(gtk::WindowType::Toplevel).unwrap();
configure_window(&window);
window.show_all();
gtk::main();
}