3

我已经阅读了 Glade 的一些手册,并创建了一个 GUI,其中有一个我想通过代码填充的 TreeView。林间空地文件是:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <!-- interface-naming-policy toplevel-contextual -->
  <object class="GtkWindow" id="tree_window">
    <property name="can_focus">False</property>
    <property name="border_width">3</property>
    <property name="title" translatable="yes">Tree Viewer</property>
    <property name="default_width">400</property>
    <property name="default_height">600</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkTreeView" id="treeview1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <child>
              <object class="GtkTreeViewColumn" id="aColumn">
                <property name="title" translatable="yes">A</property>
              </object>
            </child>
            <child>
              <object class="GtkTreeViewColumn" id="bColumn">
                <property name="title" translatable="yes">B</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

所以这个想法是用我在下面的代码中定义的 GtkTreeStore 填充“treeview1”:

#include <gtk/gtk.h>
enum{
A_COL=0,
B_COL
};
GtkTreeModel * fill_gtk_tree_store_from_xml_file()
{
GtkTreeStore * t_model;
t_model=gtk_tree_store_new(2,G_TYPE_UINT,G_TYPE_UINT);
GtkTreeIter toplevel,childlevel;
gtk_tree_store_append(t_model,&toplevel,NULL);
gtk_tree_store_append(t_model,&toplevel,NULL);
gtk_tree_store_append(t_model,&toplevel,NULL);
gtk_tree_store_set(t_model,&toplevel,A_COL,(guint)12,B_COL,(guint)14,-1);
gtk_tree_store_append(t_model, &childlevel, &toplevel);
gtk_tree_store_set(t_model,&childlevel,0,(guint)20,
                1,(guint)22,-1);
    gtk_tree_store_append(t_model, &childlevel, &toplevel);
    return GTK_TREE_MODEL (t_model);
}

#include <gtk/gtk.h>
#include <stdlib.h>

int launchGUI(GtkBuilder *builder,GError *error=NULL)
{
    GtkWidget *ventanaPrincipal;

    if( ! gtk_builder_add_from_file( builder,"treeStore.glade", &error ) )
    {
        g_warning( "%s", error->message );
        g_free( error );
        return( 1 );
    }
    ventanaPrincipal = GTK_WIDGET(gtk_builder_get_object(builder, "tree_window"));
    GtkTreeModel *model;
    GtkWidget *view;
    model=fill_gtk_tree_store_from_xml_file();
    view=GTK_WIDGET(gtk_builder_get_object(builder, "treeview1"));
    gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);
    gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
        GTK_SELECTION_NONE);
    gtk_signal_connect(GTK_OBJECT(ventanaPrincipal), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);
    gtk_widget_show_all(ventanaPrincipal);
    gtk_main();
    return 0;
}

int main(int argc,char **argv)
{
GtkBuilder *gtkBuilder;
GError     *error = NULL;
gtk_init(&argc, &argv);
gtkBuilder= gtk_builder_new();
launchGUI(gtkBuilder,error);
return EXIT_SUCCESS;
}

我尝试了不同的方法,使用枚举,不使用枚举......空行显示为空(确定),但不应为空的行也显示为空。当我运行代码时,会发生这种情况: 图像

我不知道我做错了什么,有人可以帮助我吗?

4

1 回答 1

2

Your code has many construction sides. I will work down a list of those issues that attracted my particular attention.

Don't call it c++ if you stick with gtk+ and use plain c instead

You tagged your question with c++. However you don't use gtkmm but rather gtk+. Therefore you shouldn't intersperse c++ features that are not compatible with standard c.

Related to your code you shouldn't specify default function arguments. That feature is not part of the c programming language and will confuse fellow programmers who work on your code.

Declare variables where you need them and keep your function prototypes clean

Don't unnecessarily pass variables to functions that actually belongs only to the logical scope of the function itself.

For example the function

int launchGUI(GtkBuilder *builder,GError *error=NULL)

uses builder and error only locally so you shouldn't implement them as function arguments.

Furthermore you rarely need the GtkBuilder instance anywhere outside the function that initialize your user interface. So don't mess up functions with unnecessary definitions of local variables.

Check the reference manual not only for function descriptions but also for a conceptual understanding of library features

Don't apply g_free on a GError resource. Structures like GError aren't necessarily flat. Instead use a valid function. With respect to GError you should use g_error_free.

Study the conceptual overview of the GtkTreeModel widget and how to populate it. If you don't do this or study a similar description i see hard times will come upon you.

Don't use deprecated features

Check the code for deprecated features and replace them with the counterparts of the new version of the library.

For example don't use GTK_OBJECT in programs that depends on gtk+-3.0 (I conclude that from your ui definitions file). You can almost always replace gtk_object_ with g_object_ in your code.

Think about what should be defined in the ui definitions file and what should stay in the sources

GtkTreeView is one of the most complex widgets in gtk+ at least in my opinion. It is not enough to set the model of the widgets and create some columns.

At this point it is essential to pack the columns with cell renderers and link colums from your data store/model to specific properties of the particular renderers. Only this way content of the data store will be displayed directly or indirectly on the screen.

That being said you should consider what part of the tree view should be instantiated by methods of GtkBuilder and what should be defined in the code. With respect to your code you have to either get both columns or respectively get the treeview with gtk_builder_get_object or you implement the whole tree view in glade.

To show you a minimal working example of what i guess you want to achieve i decided to delete the columns in glade and just get the instantiated treeview widget in the code. Of course this example is not necessary the last word on the subject. However it displays the tree view with the content of the store on the screen.

I appended a screenshot of the working program and the code.


enter image description here

modfied source code:

#include <gtk/gtk.h>
#include <stdlib.h>

enum
{
    A_COL = 0,
    B_COL,
    COL_NUMBER
};

gchar *title[] = { "Column A", "Column B" };

void
fill_gtk_tree_store (GtkTreeView * view)
{
    GtkTreeStore *model;
    GtkTreeIter toplevel, childlevel;
    GtkTreeViewColumn *column;
    GtkTreeSelection *selection;
    GtkCellRenderer *renderer;
    guint i;

    model = gtk_tree_store_new (COL_NUMBER, G_TYPE_UINT, G_TYPE_UINT);

    gtk_tree_store_append (model, &toplevel, NULL);
    gtk_tree_store_append (model, &toplevel, NULL);
    gtk_tree_store_append (model, &toplevel, NULL);
    gtk_tree_store_set (model, &toplevel, A_COL, 12, B_COL, 14, -1);
    gtk_tree_store_append (model, &childlevel, &toplevel);
    gtk_tree_store_set (model, &childlevel, A_COL, 20, B_COL, 22, -1);
    gtk_tree_store_append (model, &childlevel, &toplevel);

    gtk_tree_view_set_model (view, GTK_TREE_MODEL (model));

    selection = gtk_tree_view_get_selection(view);

    gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);

    for (i = 0; i < COL_NUMBER; i++) {

        renderer = gtk_cell_renderer_text_new ();

        column =
            gtk_tree_view_column_new_with_attributes (title[i], renderer,
                                                      "text", i, NULL);

        gtk_tree_view_append_column (view, column);

    }
}

void
launchGUI ()
{
    GtkWidget *ventanaPrincipal;
    GtkBuilder *builder;
    GError *error = NULL;
    GtkTreeView *view;

    builder = gtk_builder_new ();
    gtk_builder_add_from_file (builder, "treeStoreMod.glade", &error);

    if (error != NULL) {
        g_warning ("%s", error->message);
        g_error_free (error);
        exit(1);
    }

    ventanaPrincipal =
        GTK_WIDGET (gtk_builder_get_object (builder, "tree_window"));

    view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview1"));

    g_object_unref(builder);

    fill_gtk_tree_store (view);

    g_signal_connect (G_OBJECT (ventanaPrincipal),
                      "destroy", G_CALLBACK (gtk_main_quit), NULL);

    gtk_widget_show_all (ventanaPrincipal);

    gtk_main ();
}

int
main (int argc, char **argv)
{
    gtk_init (&argc, &argv);
    launchGUI ();
    return 0;
}

modified ui definitions file treeStoreMod.glade:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkWindow" id="tree_window">
    <property name="can_focus">False</property>
    <property name="border_width">3</property>
    <property name="title" translatable="yes">Tree Viewer</property>
    <property name="default_width">400</property>
    <property name="default_height">600</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkTreeView" id="treeview1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <child internal-child="selection">
              <object class="GtkTreeSelection" id="treeview-selection1"/>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
于 2013-08-07T12:07:15.320 回答