rustgtkgtk-rs

How to right justify numeric data in list store / tree view using gtk-rs


enter image description here

I have been recently learning making simple GUIs with gtk-rs but have run into an issue where numeric data is left justified in the list store / tree view and I want to have it right justified.

The code below is a modification from here: https://github.com/gtk-rs/examples/blob/master/src/bin/list_store.rs

I have been able to get the column headers to justify to center (for date) and right (for population & area) by using ".set_alignment" but have been unable to change the alignment of the data itself.

String data is easy enough to manipulate (I embedded a tab in the date items and it lines up nicely. However, if I change the population & area data to be formatted strings, they will sort as such when their column header is clicked rather than as a numeric.

Any & all help is greatly appreciated!

extern crate gio;
extern crate gtk;

use gtk::prelude::*;
use std::rc::Rc;
use std::env::args;
use gio::prelude::*;

#[repr(i32)]
enum Columns {
    State,
    Population,
    Area,
    Date,
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("List Store");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(300, 500);

    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 8);
    window.add(&vbox);

    let label = gtk::Label::new(Some("US State Facts"));
    vbox.add(&label);

    let sw = gtk::ScrolledWindow::new(None::<&gtk::Adjustment>, None:: <&gtk::Adjustment>);
    sw.set_shadow_type(gtk::ShadowType::EtchedIn);
    sw.set_policy(gtk::PolicyType::Never, gtk::PolicyType::Automatic);
    vbox.add(&sw);

    let model = Rc::new(create_model());
    let treeview = gtk::TreeView::new_with_model(&*model);
    treeview.set_vexpand(true);

    sw.add(&treeview);

    add_columns(&treeview);

    window.show_all();
}

struct Data {
    state: String,
    population: u32,
    area: u32,
    date: String,
}

fn create_model() -> gtk::ListStore {

    let col_types: [gtk::Type; 4] = [
        gtk::Type::String,
        gtk::Type::U32,
        gtk::Type::U32,
        gtk::Type::String,
    ];

    let data: [Data; 14] = [
        Data {
            state: "Alabama".to_string(),
            population: 4887871,
            area: 125767,
            date: "\t1819.12.14".to_string(),
        },
        Data {
            state: "Alaska".to_string(),
            population: 737438,
            area: 1723337,
            date: "\t1959.01.03".to_string(),
        },
        Data {
            state: "Arkansas".to_string(),
            population: 3013825,
            area: 137732,
            date: "\t1836.06.15".to_string(),
        },
        Data {
            state: "Arizona".to_string(),
            population: 7171646,
            area: 295234,
            date: "\t1912.02.14".to_string(),
        },
        Data {
            state: "California".to_string(),
            population: 39557045,
            area: 423972,
            date: "\t1850.09.09".to_string(),
        },
        Data {
            state: "Colorado".to_string(),
            population: 5695564,
            area: 269601,
            date: "\t1876.08.01".to_string(),
        },
        Data {
            state: "Connecticut".to_string(),
            population: 3572665,
            area: 14357,
            date: "\t1788.01.09".to_string(),
        },
        Data {
            state: "Delaware".to_string(),
            population: 967171,
            area: 6446,
            date: "\t1787.12.07".to_string(),
        },
        Data {
            state: "Maine".to_string(),
            population: 1338404,
            area: 91633,
            date: "\t1820.03.15".to_string(),
        },
        Data {
            state: "Maryland".to_string(),
            population: 6042718,
            area: 32131,
            date: "\t1788.04.28".to_string(),
        },
        Data {
            state: "Massachusetts".to_string(),
            population: 6902149,
            area: 27336,
            date: "\t1788.02.06".to_string(),
        },
        Data {
            state: "Michigan".to_string(),
            population: 9998915,
            area: 250487,
            date: "\t1837.01.26".to_string(),
        },
        Data {
            state: "Missouri".to_string(),
            population: 6126452,
            area: 180540,
            date: "\t1821.08.10".to_string(),
        },
        Data {
            state: "Nebraska".to_string(),
            population: 1929268,
            area: 200330,
            date: "\t1867.03.01".to_string(),
        },
    ];

    let store = gtk::ListStore::new(&col_types);

    let col_indices: [u32; 4] = [0, 1, 2, 3];

    for (_, d) in data.iter().enumerate() {
        let values: [&dyn ToValue; 4] = [
            &d.state,
            &d.population,
            &d.area,
            &d.date,
        ];
        store.set(&store.append(), &col_indices, &values);
    }

    store
}

//fn add_columns(treeview: &gtk::TreeView) 
fn add_columns(treeview: &gtk::TreeView) {

    // Column for state name
    {
        let renderer = gtk::CellRendererText::new();
        let column = gtk::TreeViewColumn::new();
        column.pack_start(&renderer, true);
        column.set_title("State");
        column.add_attribute(&renderer, "text", Columns::State as i32);
        column.set_sort_column_id(Columns::State as i32);
        column.set_fixed_width(150);
        column.set_alignment(0.0);
        treeview.append_column(&column);
    }

    // Column for population
    {
        let renderer = gtk::CellRendererText::new();
        let column = gtk::TreeViewColumn::new();
        column.pack_start(&renderer, true);
        column.set_title("Population");
        column.add_attribute(&renderer, "text", Columns::Population as i32);
        column.set_sort_column_id(Columns::Population as i32);
        column.set_fixed_width(150);
        column.set_alignment(1.0);
        treeview.append_column(&column);
    } 

    // Column for area
    {
        let renderer = gtk::CellRendererText::new();
        let column = gtk::TreeViewColumn::new();
        column.pack_start(&renderer, true);
        column.set_title("Area");
        column.add_attribute(&renderer, "text", Columns::Area as i32);
        column.set_sort_column_id(Columns::Area as i32);
        column.set_fixed_width(150);
        column.set_alignment(1.0);
        treeview.append_column(&column);
    }

    // Column for date
    {
        let renderer = gtk::CellRendererText::new();
        let column = gtk::TreeViewColumn::new();
        column.pack_start(&renderer, true);
        column.set_title("Date");
        column.add_attribute(&renderer, "text", Columns::Date as i32);
        column.set_sort_column_id(Columns::Date as i32);
        column.set_fixed_width(150);
        column.set_alignment(0.5);
        treeview.append_column(&column);
    }
}


fn main() {
    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.list-store"),
        Default::default(),
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
         build_ui(app);
    });

    application.connect_activate(|_| {});

    application.run(&args().collect::<Vec<_>>());
}

Cargo.toml:

[package]
name = "testit"
version = "0.1.0"
authors = ["jerry"]
edition = "2018"

[dependencies]
gio = "0.7.0"
gtk = "0.7.0"   

The Fix: renderer.set_alignment(1.0, 1.0);

// Column for population
{
    let renderer = gtk::CellRendererText::new();
    renderer.set_alignment(1.0, 1.0);
    let column = gtk::TreeViewColumn::new();
    column.pack_start(&renderer, true);
    column.set_title("Population");
    column.add_attribute(&renderer, "text", Columns::Population as i32);
    column.set_sort_column_id(Columns::Population as i32);
    column.set_fixed_width(150);
    column.set_alignment(1.0);
    treeview.append_column(&column);
} 

Good result: enter image description here

Compiler Error: enter image description here


Solution

  • You are looking for the xalign property. As far as I can tell, this would result in:

    renderer.set_property("xalign", 1.00)