GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Mon Sep 01, 2014 9:07 pm

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: treeview like MS-Excel/OO-calc sheet
PostPosted: Tue Apr 14, 2009 5:54 pm 
Offline

Joined: Tue Apr 14, 2009 4:47 pm
Posts: 2
Location: Germany
Hi all,
after reading many topics here, which have given me plenty of inspirations how to write software in C using GTK+ for GUI, I've started to write a demo for an excel/calc like sheet, that I need for a bigger application.

What I need is a sheet with row- and col-headers, where users can type in numerical data just by selecting a cell with mouse button or cursor keys and then typing in data without a need of some extra buttons or keys (blank, return, etc.). Just select a cell, type in a number (float), press return and selection goes automatically to the next "logical" cell (after last cell in row, cursor should jump to first "editable" cell in next row)

Please find attached the code of my demo, which isn't quite finished (cell navigation and highlight with cursor keys works, but with mouse button I've got a problem getting the right col number; data validation (float) also missing), but hopefully explains a little more, what I've in mind.

But Jesus - isn't there an easier way to achieve what I want?

Code:
#include <gtk/gtk.h>

enum {
   COL_CHARS, COL_MIN, COL_NOM, COL_MAX,
   NUMCOLS
};

/* define some row and column headers */
static char *ColHeader[] = {
   "Characteristic", "min", "nom", "max"
};

#define NaN "******.***"
#define NUMROWHEADER 7
static char *RowHeader[] = {
   "Voltage", "Current", "Power", "Resistance", "Length", "Width", "Lifetime"
};


/* treeview's cursor_changed event */
void view_cursor_changed_cb (GtkTreeView *view, GtkListStore *model)
{
   static gint col = -1;
   static GtkTreeIter iter;
   GtkTreePath *path;
   GtkTreeViewColumn *column;
   GList *renderers;
   
   if (col > -1)
      gtk_list_store_set(model, &iter, col + NUMCOLS, FALSE, -1);
   
   gtk_tree_view_get_cursor(view, &path, &column);
   if (column) {
      renderers = gtk_tree_view_column_get_cell_renderers(column);
      col = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(renderers->data), "column"));
      gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
      gtk_list_store_set(model, &iter, col + NUMCOLS, TRUE, -1);
   }
}


/* treeview's key_pressed event */
gboolean view_key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
   GtkTreePath *path;
   GtkTreeViewColumn *column;
   // check if keyval = numkey, comma, plus, minus, etc. from keyboard or keypad (should use GDK_KeySyms instead)
   if ((event->keyval >= 0x02b && event->keyval <= 0x039) || (event->keyval >= 0xffac && event->keyval <= 0xffb9)) {
      // get cell coordinates, set cursor to cell, start editing and put keyval via event queue into cell
      gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, &column);
      gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), path, column, TRUE);
      gdk_event_put((GdkEvent *) event);
   }
   // keyval = return or enter
   else if (event->keyval == 0xff0d || event->keyval == 0xff8d) {
      // TODO: skip edit instead jump to next logical cell
      ;
   }
      
   return FALSE;
}

/* treeview's button_pressed event */
gboolean view_button_pressed_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
   GtkTreePath *path;
   GtkTreeViewColumn *column;
   gint x, y;
   gint *cell_x = NULL, *cell_y = NULL;
   
   path = gtk_tree_path_new();
   column = gtk_tree_view_column_new();
   x = event->x;
   y = event->y;
   gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), x, y, &path, &column, cell_x, cell_y);
   gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), path, column, FALSE);
   return TRUE;
}

/* get logical next cell */
void next_cell (GtkTreeModel *model, GtkTreeView *view, GtkTreeIter iter, gint colno)
{
   GtkTreePath *path;
   GtkTreeViewColumn *column;
   
   if (colno < NUMCOLS - 1)
      column = gtk_tree_view_get_column(view, ++colno);
   else {
      column = gtk_tree_view_get_column(view, COL_MIN);
      if (!gtk_tree_model_iter_next(model, &iter))
         gtk_tree_model_get_iter_first(model, &iter);
   }
   path = gtk_tree_model_get_path(model, &iter);
   gtk_tree_view_set_cursor(view, path, column, FALSE);
   view_cursor_changed_cb(view, GTK_LIST_STORE(model));
}

/* update cell in model and jump to next cell */
void cell_edited_cb (GtkCellRendererText *cell, gchar *pathtext, gchar *newtext, GtkTreeView *view)
{
   GtkTreeModel *model;
   GtkTreeIter iter;
   gint column;
   
   model = gtk_tree_view_get_model(view);
   gtk_tree_model_get_iter_from_string(model, &iter, pathtext);
   column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column"));
   gtk_list_store_set(GTK_LIST_STORE(model), &iter, column, newtext, -1);
   next_cell(model, view, iter, column);
}


GtkWidget *create_view(void)
{
   int idx;
   GtkWidget *view;
   GtkTreeSelection *selection;
   GtkListStore *model;
   GtkTreeIter iter;
   GtkCellRenderer *cell;
   
   model = gtk_list_store_new(NUMCOLS * 2,
      G_TYPE_STRING,  G_TYPE_STRING,  G_TYPE_STRING,  G_TYPE_STRING,
      G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
   view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
   gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view), FALSE);
   g_signal_connect(view, "key-press-event", G_CALLBACK(view_key_pressed_cb), NULL);
   g_signal_connect(view, "button-press-event", G_CALLBACK(view_button_pressed_cb), NULL);
   g_signal_connect(view, "cursor-changed", G_CALLBACK(view_cursor_changed_cb), (gpointer) model);
   g_object_unref(model);
   
   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
   gtk_tree_selection_set_mode(selection, GTK_SELECTION_NONE);
   
   for (idx = 0; idx < NUMCOLS; idx++) {
      cell = gtk_cell_renderer_text_new();
      g_object_set(cell, "background", "yellow", NULL);
      g_object_set_data(G_OBJECT(cell), "column", GINT_TO_POINTER(idx));
      if (idx > 0) {
         g_object_set(cell, "editable", TRUE, "xalign", 1.0, "align-set", TRUE, NULL);
         g_object_set_data(G_OBJECT(cell), "column", GINT_TO_POINTER(idx));
         g_signal_connect(cell, "edited", G_CALLBACK(cell_edited_cb), (gpointer) view);
      }
      gtk_tree_view_insert_column_with_attributes
         (GTK_TREE_VIEW(view), -1,
         ColHeader[idx], cell,
         "text", idx,
         "background-set", idx + NUMCOLS,
         NULL);
   }
   
   /* add some data */
   for (idx = 0; idx < NUMROWHEADER; idx++) {
      gtk_list_store_append(model, &iter);
      gtk_list_store_set(model, &iter, 0, RowHeader[idx], 1, NaN, 2, NaN, 3, NaN, -1);
   }
   
   return view;
}


gint main (gint argc, gchar **argv)
{
   GtkWidget *win;
   GtkWidget *view;
   
   gtk_init(&argc, &argv);
   
   win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   g_signal_connect(win, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
   
   view = create_view();
   gtk_container_add(GTK_CONTAINER(win), view);
   gtk_widget_show(view);
   
   gtk_widget_show(win);
   
   gtk_main();
   
   return 0;
}


I hope, someone could guide me to "simplify" my demo a little bit ;-)

greetings
Rufus


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 14, 2009 9:11 pm 
Offline
Never Seen the Sunlight

Joined: Wed Jul 23, 2008 10:31 am
Posts: 2406
Location: Slovenia
Hello and welcome to the Gtk+ forums.

I wouldn't recommend you to write grid widget using GtkTreeView, since this is highly inefficient.

There is a library called gtkextra that provides (among other widgets) GtkSheet. Check your distro's repos for gtkextra package. (Ubuntu interpid development package: http://packages.ubuntu.com/intrepid/libgtkextra-x11-2.0-dev)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 15, 2009 12:56 am 
Offline
GTK+ Guru

Joined: Thu Jun 21, 2007 1:52 pm
Posts: 198
Location: Wilkes Barre Pa
Gtk+ doesn't have a proper gridview type widget and gtkextra is very old and hasn't been updated since 2005 so your best bet would be to create something custom

This might not be exactly what your looking for but you might find some useful information. I am going to assume you want to build a gtk+ application like calc or excel.
.
They first thing you might want to do so you don't have to rewrite large amounts of code every time you need a gridview widget would be to learn how to create your own gtk+ widgets. They following tutorial focus on gtk+ and cairo. Use them to get a general idea how custom widgets are made.
[HTML] Part1: http://www.gnomejournal.org/article/34/ ... -and-gtk28
[HTML] Part2: http://www.gnomejournal.org/article/36/ ... k28-part-2

Next your going to want a canvas widget that can be used to create and interact with your gridview and can replace cairo in they above tutorials. For that we will want to use GooCanvas. Note: GooCanvas could also be used to create word processing & presentation type canvases.
GooCanvas is a canvas widget for GTK+ that uses the cairo 2D library for drawing.
http://library.gnome.org/devel/goocanvas/unstable/

Now that we have an idea on how to create a gridview you might want to create charts and graphs. GOffice will allow you to do that and alot more hence the name.
GOffice GOffice is a library of document-centric objects and utilities building on top of GLib and Gtk+ and used by software such as AbiWord, Gnumeric, GnuCash, and gchempaint.
http://freshmeat.net/projects/goffice/

Outlined here are some ideas for how things might work in producing nice graphs in GTK+.
http://live.gnome.org/KieranClancy/GtkGraphing

You might also want to save your spreadsheet data to file for later use. ODF was designed for just that below is a article on how to handle odf files in python. Use it to get a general idea on how its done so you could do the same in c.
http://www.linuxjournal.com/article/9347


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 15, 2009 8:57 am 
Offline
Never Seen the Sunlight

Joined: Wed Jul 23, 2008 10:31 am
Posts: 2406
Location: Slovenia
Hi.
caracal wrote:
Gtk+ doesn't have a proper gridview type widget and gtkextra is very old and hasn't been updated since 2005 so your best bet would be to create something custom
Just a small update: gtkextra2 is very old (this is what most distributions pack), but cvs version (gtkextra3) is only 6 months old and works pretty well.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 15, 2009 2:05 pm 
Offline
GTK+ Guru

Joined: Thu Jun 21, 2007 1:52 pm
Posts: 198
Location: Wilkes Barre Pa
Nice i didn't even know about gtkextra3 i am going to go check it out now.

Thanks tadeboro :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 15, 2009 4:45 pm 
Offline

Joined: Tue Apr 14, 2009 4:47 pm
Posts: 2
Location: Germany
Hi guys,
thanks for your comment and leading me to better directions :-)

@tadeboro: on your advise I've installed the gtk-extra package (debian lenny) and played a little bit with GtkSheet-Demo - very impressive! During rewriting my demo app, I've noticed a few problems like default sizing and behavior in GtkScrolledWindow with GTK_POLICY_AUTOMATIC (I would assume, that scrollbars disappear when whole grid fits into window ... but they don't), not quite the navigation behavior, that I want (seamless switch between cell navigation with cursor keys and cell editing, change default direction of <return> key) ... but perhaps I've to look a little bit deeper into manual ...

@caracal: I've also visited your links ... but I must admit, that I'm very new to coding in C under Linux - and so I find it very challenging to write such a complex widget like a Table/Grid with my current knowledge. But who knows, if I'm not getting satisfied with GtkSheet, perhaps I peek into the source and deviate my *first* own widget out of it ;-)

BTW - I've not in mind, writing "one more" office clone. I'll need this kind of Table/Grid/Sheet-Widget for a redesign of an application for quality control (selfwritten legacy app anno 1985 in FORTRAN - year!). This app consist of many editors (products, tests, characteristics to measure during tests, specifications, inspection plans, etc.), special apps to identify sample lots, create inspection lots, perform measurements, and so on. Backend is supposed to be a DBMS (e.g. MySQL). So we have many "tabulated" data at different locations within workflow, where it would be nice for users, if they can edit this data as easy as filling out a spreadsheet (like my example, which is a prototype of a "specification editor").

So, once again many thanks for your advices and I'll keep you informed of my progress rebuilding my demo with GtkSheet.

greeeting
Rufus


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group