ListView可编辑,支持GTK4、C和VFL

问题描述 投票:0回答:1

GTK4 关于 TreeView 的新可能性并不容易实现。因此,最好有一个介绍性示例。

几个小时后,在这个论坛的宝贵建议的帮助下,我成功地为 ListView 的实现创建了一个小测试示例。也许对其他人来说也会很有趣。

c listview gtk4
1个回答
0
投票

重要通知:

该程序的唯一目的是测试使用 GTK4、C 和 VFL 的 ListView 的一些方法。它可能包含错误,并且并不声称被视为“最佳实践”。

  /*
   * The sole purpose of this program is to test some approaches to using 
   * ListView with GTK4, C, and VFL.It may contain errors and does not 
   * claim to be considered "best practice".
   */

#include <gtk/gtk.h>

static GListModel* create_model()
{
    GListStore *store;
    store = g_list_store_new(GTK_TYPE_STRING_OBJECT);
    g_list_store_append(store, gtk_string_object_new("Washington,D.C."));
    g_list_store_append(store, gtk_string_object_new("London"));
    g_list_store_append(store, gtk_string_object_new("Paris"));
    g_list_store_append(store, gtk_string_object_new("Berlin"));
    g_list_store_append(store, gtk_string_object_new("Rom"));

    return G_LIST_MODEL (store);
}

/*
 * Create a class derived from Widget that contains the controls 
 * and implements the Layout Manager.
 */

#define LISTVFL_TYPE_LAYOUT (listvfl_layout_get_type())

G_DECLARE_FINAL_TYPE (ListvflLayout, listvfl_layout, LISTVFL, LAYOUT, 
GtkWidget)

struct _ListvflLayout
{
    GtkWidget parent_instance;
 
    GtkWidget *scrolledwindow;  
    GtkWidget *listview;
    GtkWidget *label;
    GtkWidget *btndelete;
    GtkWidget *btnaz;
    GtkWidget *btnza;
    GtkWidget *btnadd;
    GtkWidget *entry;
    GtkSingleSelection *selection;
    guint position;
  };

G_DEFINE_TYPE (ListvflLayout, listvfl_layout, GTK_TYPE_WIDGET)

static void
setup_list_item_cb (GtkListItemFactory *factory, GtkListItem *list_item)
{
    GtkWidget*label = gtk_label_new (NULL);
    gtk_list_item_set_child (GTK_LIST_ITEM(list_item), label);
}

static void
bind_list_item_cb (GtkListItemFactory *factory, GtkListItem *list_item, 
gpointer listvfllayout)
{
    GtkWidget *label = gtk_list_item_get_child(list_item);
    GtkStringObject *str = gtk_list_item_get_item(list_item);
    const char *string = gtk_string_object_get_string(str);
    gtk_label_set_text(GTK_LABEL(label), string);

    if (gtk_list_item_get_selected(list_item))
    {
        ListvflLayout  *widget = (ListvflLayout*)listvfllayout;
        GtkWidget *label1 = GTK_WIDGET(widget->label);
        gchar *format = "<span foreground='blue' 
background='yellow'size='x-large'>\%s </span>";
        gchar *markup;
        markup = g_markup_printf_escaped (format,string);
        gtk_label_set_markup (GTK_LABEL(label1),markup);        
        g_free (markup);
        widget->position = gtk_list_item_get_position(list_item);
    }
}

// not in use !!
static void
selection_changed(GObject *object, GParamSpec *pspec, GtkWidget 
*listvfllayout)
{
//  GtkListItem *list_item 
=gtk_single_selection_get_selected_item(GTK_SINGLE_SELECTION(object));
//  pos = gtk_single_selection_get_selected(GTK_SINGLE_SELECTION(object));
//  const char *string = 
gtk_string_object_get_string(GTK_STRING_OBJECT(list_item));
//  ListvflLayout  *widget = (ListvflLayout*)listvfllayout;
//  gtk_label_set_label(GTK_LABEL(widget->label),string);
}

gint sort_dec(gconstpointer *a, gconstpointer *b, gpointer un_used)
{
    const char *string1 = 
gtk_string_object_get_string(GTK_STRING_OBJECT(a));
    const char *string2 = 
gtk_string_object_get_string(GTK_STRING_OBJECT(b));
    return g_strcmp0 (string1, string2);
}

gint sort_asc(gconstpointer *a, gconstpointer *b, gpointer un_used)
{
    const char *string1 = gtk_string_object_get_string(GTK_STRING_OBJECT(a));
    const char *string2 = 
gtk_string_object_get_string(GTK_STRING_OBJECT(b));
    return g_strcmp0 (string2, string1);
}

static void sort_az(GtkWidget * btnaz, gpointer listvfllayout)
{
    ListvflLayout *widget = LISTVFL_LAYOUT(listvfllayout);
    GListModel *model = gtk_single_selection_get_model(widget->selection);
    GListStore *store = G_LIST_STORE(model);
    g_list_store_sort(store,(GCompareDataFunc)sort_dec,NULL);
}

static void sort_za(GtkWidget *btnza, gpointer listvfllayout)
{
    ListvflLayout *widget = LISTVFL_LAYOUT(listvfllayout);
    GListModel *model = gtk_single_selection_get_model(widget->selection);
    GListStore *store = G_LIST_STORE(model);
    g_list_store_sort(store,(GCompareDataFunc)sort_asc,NULL);
}

static void delete(GtkWidget *btndelete, gpointer listvfllayout)
{
    ListvflLayout *widget = LISTVFL_LAYOUT(listvfllayout);
    GListModel *store = gtk_single_selection_get_model(widget->selection);
    if (widget->position == 0) gtk_label_set_label(GTK_LABEL(widget- 
   >label),"-empty-");
    if(g_list_model_get_n_items(store)) 
g_list_store_remove(G_LIST_STORE(store), widget->position);
}

static void add(GtkWidget *btnadd, gpointer listvfllayout)
{
    ListvflLayout *widget = LISTVFL_LAYOUT(listvfllayout);
    GtkEntryBuffer *buffer;
    const char *text;
    buffer = gtk_entry_get_buffer(GTK_ENTRY(widget->entry));
    text = gtk_entry_buffer_get_text(buffer);
    if (strlen(text) > 0)
    {
        GListModel *store = gtk_single_selection_get_model(widget- 
   >selection);
        g_list_store_append(G_LIST_STORE(store), 
gtk_string_object_new(text));
    }
    gtk_entry_buffer_delete_text(buffer,0,-1);
}

static void
listvfl_layout_dispose (GObject *object)
{
    ListvflLayout *self = LISTVFL_LAYOUT (object);
    g_clear_pointer (&self->scrolledwindow, gtk_widget_unparent);  
    g_clear_pointer (&self->label, gtk_widget_unparent);
    g_clear_pointer (&self->btndelete, gtk_widget_unparent);
    g_clear_pointer (&self->btnaz, gtk_widget_unparent);
    g_clear_pointer (&self->btnza, gtk_widget_unparent);
    g_clear_pointer (&self->btnadd, gtk_widget_unparent);
    g_clear_pointer (&self->entry, gtk_widget_unparent);
    G_OBJECT_CLASS (listvfl_layout_parent_class)->dispose (object);
}

static void
listvfl_layout_class_init (ListvflLayoutClass *class)
{
    GObjectClass *object_class = G_OBJECT_CLASS(class);
    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
    object_class->dispose = listvfl_layout_dispose;
    // Layout manager
    gtk_widget_class_set_layout_manager_type 
(widget_class,GTK_TYPE_CONSTRAINT_LAYOUT);
}

// Creating the Conistraints for the Layout
static void
build_constraints (ListvflLayout *self, GtkConstraintLayout *manager)
{
    const char *const vfl[] = {
        "H:|-20-[label(110)]-60-[btndelete(110)]-(<=0)-|",
        "H:|-20-[scrolledwindow(110)]-60-[btnaz(50)]-10-[btnza(50)]-(<=0)-|",
        "H:|-20-[scrolledwindow(110)]-60-[entry(110)]-(<=0)-|",
        "H:|-20-[scrolledwindow(110)]-60-[btnadd(110)]-(<=0)-|",
        "V:|-20-[label(30)]-20-[scrolledwindow(250)]-(<=0)-|",
        "V:|-20-[btndelete(30)]-10-[btnaz(20)]-10-[entry(30)]-10-[btnadd(30)]-(<=0)-|",
        "V:|-20-[btndelete(30)]-10-[btnza(20)]-(<=0)-|",
        
    };

GError *error = NULL;

gtk_constraint_layout_add_constraints_from_description (manager, vfl, G_N_ELEMENTS (vfl),
            0,0,
            &error,
            "label", self->label,
            "btndelete", self->btndelete,
            "scrolledwindow", self->scrolledwindow, 
            "listview", self->listview,
            "btnaz", self->btnaz,
            "btnza", self->btnza,
            "entry", self->entry,
            "btnadd", self->btnadd,
            NULL);
   if (error != NULL)
   {
    g_printerr("VFL parsing Error: %s\n", error->message);
    g_error_free(error);
   }
}

//Initializing the class
static void
listvfl_layout_init (ListvflLayout *self)
{
    GtkListItemFactory *factory;    
    GListModel *model;      
    self->position = 0;

    GtkWidget *widget = GTK_WIDGET (self);

    self->label = gtk_label_new(NULL);
    gtk_widget_set_parent(self->label,widget);

    self->btndelete = gtk_button_new_with_label("Delete");
    gtk_widget_add_css_class(self->btndelete, "destructive-action");
    gtk_widget_set_parent(self->btndelete,widget);
    g_signal_connect(self->btndelete,"clicked",G_CALLBACK(delete),self);

    self->listview = gtk_list_view_new(NULL,NULL);        
    model = create_model();
    self->selection = gtk_single_selection_new(G_LIST_MODEL(model));
    gtk_single_selection_set_autoselect(self->selection, TRUE);
    gtk_list_view_set_model(GTK_LIST_VIEW(self- 
   >listview),GTK_SELECTION_MODEL(self->selection));
    g_signal_connect (self->selection,"notify::selected", 
G_CALLBACK(selection_changed),self);

    factory = gtk_signal_list_item_factory_new();
    g_signal_connect (factory, "setup", G_CALLBACK (setup_list_item_cb), 
NULL);
    g_signal_connect (factory, "bind",G_CALLBACK (bind_list_item_cb),self);
    gtk_list_view_set_factory (GTK_LIST_VIEW (self->listview),factory);

    self->scrolledwindow = gtk_scrolled_window_new();     
    gtk_widget_set_parent(self->scrolledwindow,widget);  
    gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(self- 
   >scrolledwindow),self->listview);  

    self->btnaz = gtk_button_new_with_label("a-z");
    gtk_widget_set_parent(self->btnaz,widget);
    g_signal_connect(self->btnaz,"clicked",G_CALLBACK(sort_az),self);

    self->btnza = gtk_button_new_with_label("z-a");
    gtk_widget_set_parent(self->btnza,widget);
    g_signal_connect(self->btnza,"clicked",G_CALLBACK(sort_za),self);

    self->entry = gtk_entry_new();
    gtk_widget_set_parent(self->entry,widget);
    gtk_widget_set_focus_child(GTK_WIDGET(self),self->entry);
    g_signal_connect(self->entry,"activate",G_CALLBACK(add),self);

    self->btnadd = gtk_button_new_with_label("Add");
    gtk_widget_add_css_class(self->btnadd, "suggested-action");
    gtk_widget_set_parent(self->btnadd,widget);
    g_signal_connect(self->btnadd,"clicked",G_CALLBACK(add),self);

    //Import and initialize the widget's layout manager
    GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET 
(self));
    build_constraints(self, GTK_CONSTRAINT_LAYOUT (manager));
}

//From here, a applicationswindow is created  and the class is added via a 
box
static void
activate (GtkApplication *app, gpointer user_date)
{
    GtkWidget *window;
    GtkWidget *box, *listvfllayout;

    window = gtk_window_new();
    gtk_window_set_title (GTK_WINDOW (window), "ListView editable with 
VFL");
    gtk_widget_set_size_request (window, 200,400);
    g_object_add_weak_pointer (G_OBJECT (window),(gpointer *)&window);
    box = gtk_box_new(GTK_ORIENTATION_VERTICAL,12);
    gtk_window_set_child(GTK_WINDOW (window), box);
    listvfllayout = g_object_new(listvfl_layout_get_type(), NULL);
    gtk_widget_set_hexpand(listvfllayout, TRUE);
    gtk_widget_set_vexpand(listvfllayout, TRUE);
    gtk_box_append (GTK_BOX (box), listvfllayout);
    gtk_application_add_window(app, GTK_WINDOW(window));
    gtk_window_present (GTK_WINDOW(window));
}

int
main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new 
("holger.test.viewflf",G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}
© www.soinside.com 2019 - 2024. All rights reserved.