Could anyone please give me a hint on how to attach a "double clicked" signal
to the pixbuf that is in the GtkTreeView? GtkCellRendererPixbuf
doesn't have any signals?
I managed to set the GTK_CELL_RENDERER_MODE_ACTIVATABLE switch to the
renderer, but I don't know how to work.
I checked the header file and in fact there is the "activate" method; could you please
demonstrate how to use it?
renderer = gtk_cell_renderer_pixbuf_new();
g_object_set(renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
column = gtk_tree_view_column_new_with_attributes(NULL,
renderer,
"pixbuf",
0,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
OK I try this:
Tree view's 'row-activated' will send the path and column as arguments
to the callback. With 'cursor-changed' just need to call
gtk_gtk_treeview_get_cursor to find out the path and column. With
gtk Widget's 'button-press-event' I get the event as an argument for
the callback and just need to call gtk_treeview_get_path_at_pos with
event x and event y to get the path and column.
A cell renderer is only supposed to draw the contents of the data model over a portion of the widget. Interaction with the user is in most cases realized using the widget itself.
In other words, simply connect to the button-press-event of the tree view and handle the case when the type is GDK_2BUTTON_PRESS. You can get the row/column under the mouse using gtk_tree_view_get_path_at_pos, as you do in your other question.
Check this:
void on_treeview_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_tree_view_get_model( treeview );
if ( gtk_tree_model_get_iter(model, &iter, path) )
{
gtk_tree_model_get(model, &iter,
ITEM, &dhd_contaItem2,
CODIGO, &dhd_G_CodProduto2 ,
DESCRICAO, &dhd_G_NomeProduto2 ,
QTD, &dhd_quantidade2,
VALOR, &dhd_valorItem2,
-1);
g_print( "Current row: %s %s %s %s %s\n", dhd_contaItem2, dhd_G_CodProduto2, dhd_G_NomeProduto2, dhd_quantidade2, dhd_valorItem2 );
}
}
I use that in one of my codes to print in terminal the selected row from a TreeView (with ListStore) when double clicked or when you press enter on it. On the gtk_tree_model_get notice that I'm using my own columns and variables, as i do in g_print. And I attach this function with row-activated signal on the TreeView. I don't know if is that what you want exactly but I hope it helps you out. Sorry for my bad english.
Related
I have a GtkTreeView with two columns of type text (e.g. G_TYPE_STRING) and I am using GtkCellRendererText to render the column.
Is there any why that I can react when the mouse enters and leaves a certain cell and then hover or highlight the cell.
For example I would like to underline the text in the cell renderer, when the mouse enters it, in order to give a visual clue that the cell can be clicked to perform an action.
There are quite a few ways to accomplish the task. A few examples follow, separated by horizontal lines.
The simplest, and in some ways the best, option is to simply change the mouse cursor to a finger (same as the mouse cursor you see in a browser when pointing to a link) within the GtkTreeView.
Let's say GtkTreeView *view is the view we're interested in. After you have called gtk_widget_show_all(window);, you can call
GdkWindow *win = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(view));
GdkDisplay *disp = gdk_window_get_display(win);
gdk_window_set_cursor(win, gdk_cursor_new_from_name(disp, "pointer"));
With this, the mouse pointer will be a finger for all rows in the view, excluding the header row.
The set of cursor names you can use (instead of "pointer" above) is listed here in the GDK3 documentation.
The downside is that if you have empty rows in the tree view, or separator rows, the mouse pointer will still look like a finger for those.
You can override the hover color by applying an application-specific CSS hover color, say
GtkTreeView:hover {
color: #ff0000;
}
with e.g.
GtkCssProvider *css_provider;
css_provider = gtk_css_provider_new();
if (gtk_css_provider_load_from_data(css_provider,
"GtkTreeView:hover {\n"
" color: #ff0000;\n"
"}\n"
"", -1, NULL))
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(),
GTK_STYLE_PROVIDER(css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref(css_provider);
after creating your main window. (Of course, you can include all application-specific CSS overrides in the CSS snippet.)
However, on gtk+ 3.18.9 at least, the renderer does not seem to support text-decoration or font CSS attributes here. (The GtkCssProvider does not seem to support cursor attribute at all, in case you're wondering.)
Also, since this essentially overrides the user theme, and there are a number of possible themes a Gtk+ user might be using, changing the color this way is unlikely to look good in all themes.
If your GtkTreeView *view; consists of clickable rows, and you don't need the selection for anything (that is, you don't have a separate button or something that causes an action to be applied to all the selected rows in the GtkTreeView), then you can simply set the selection to follow the mouse cursor:
gtk_tree_view_set_hover_selection(view, TRUE);
this causes the row you hover over to be selected, and therefore also highlighted. You probably also want to limit the selection to one row at a time:
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(view),
GTK_SELECTION_SINGLE);
As Herbalist already mentioned, you can create a custom GtkCellRendererText derivative, which changes the PangoUnderline underline property depending on whether the text cell being rendered is also prelit (hovered over) or not:
#include <gtk/gtk.h>
#define CUSTOM_TYPE_CELL_RENDERER_TEXT (custom_cell_renderer_text_get_type())
#define CUSTOM_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_TEXT, CustomCellRendererText))
#define CUSTOM_CELL_RENDERER_TEXT_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), CUSTOM_TYPE_CELL_RENDERER_TEXT, CustomCellRendererTextClass))
#define CUSTOM_IS_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), CUSTOM_TYPE_CELL_RENDERER_TEXT))
#define CUSTOM_IS_CELL_RENDERER_TEXT_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), CUSTOM_TYPE_CELL_RENDERER_TEXT))
#define CUSTOM_CELL_RENDERER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CUSTOM_TYPE_CELL_RENDERER_TEXT, CustomCellRendererTextClass))
GType custom_cell_renderer_text_get_type(void) G_GNUC_CONST;
typedef struct {
GtkCellRendererText renderer;
} CustomCellRendererText;
typedef struct {
GtkCellRendererTextClass parent_class;
} CustomCellRendererTextClass;
G_DEFINE_TYPE(CustomCellRendererText, custom_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
void custom_cell_renderer_text_render(GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *backarea,
const GdkRectangle *cellarea,
GtkCellRendererState state)
{
if (state & GTK_CELL_RENDERER_PRELIT) {
const PangoUnderline prelit = PANGO_UNDERLINE_SINGLE;
PangoUnderline curr;
g_object_get(cell, "underline", &curr, NULL);
g_object_set(cell, "underline", prelit, NULL);
((GtkCellRendererClass *)custom_cell_renderer_text_parent_class)->render(cell, cr, widget, backarea, cellarea, state);
g_object_set(cell, "underline", curr, NULL);
} else
((GtkCellRendererClass *)custom_cell_renderer_text_parent_class)->render(cell, cr, widget, backarea, cellarea, state);
}
void custom_cell_renderer_text_class_init(CustomCellRendererTextClass *cls)
{
((GtkCellRendererClass *)cls)->render = custom_cell_renderer_text_render;
return;
}
void custom_cell_renderer_text_init(CustomCellRendererText *renderer)
{
return;
}
GtkCellRenderer *custom_cell_renderer_text_new(void)
{
return g_object_new(CUSTOM_TYPE_CELL_RENDERER_TEXT, NULL);
}
If you then replace your gtk_cell_render_text_new() with custom_cell_render_text_new() (and change GtkCellRenderText * to CustomCellRenderText *) in your GtkTreeView code, the row you hover on in the GtkTreeView will become underlined.
Note that all cells in the row you hover over will be highlighted, not just the cell/column you hover over. This is because in a GtkTreeView, the row (or index) is the unit being manipulated (rather than a specific cell on a specific column).
If you use the above renderer only for some columns in your GtkTreeView, the text in those columns will get underlined even when the mouse hovers over some other column on that row.
Also note that if you don't want all rows to indicate clickability, you can add a third column in your data model -- name "sensitive", type G_TYPE_BOOLEAN for gboolean type; value TRUE if the row is clickable, FALSE if the row is non-clickable -- and change the if clause in custom_cell_renderer_text_render() to
const GtkStateFlags flags = gtk_cell_renderer_get_state(cell, widget, state);
if ((state & GTK_CELL_RENDERER_PRELIT) &&
!(flags & GTK_STATE_FLAG_INSENSITIVE)) {
Gtk+ will render rows with TRUE normally, and rows with FALSE as separators or disabled text, because the column names in the model are automatically associated with the GtkCellRenderer properties of the same name.
You could make a custom CellRendererText and set the underline property if the PRELIT flag is present.
i only know in Python:
class My_CellRendererText( Gtk.CellRendererText ):
def __init__( self ):
super().__init__()
def do_render( self, cr, widget, background_area, cell_area, flags ):
self.props.underline = ( ( flags & Gtk.CellRendererState.PRELIT ) != 0 )
return Gtk.CellRendererText.do_render( self, cr, widget, background_area, cell_area, flags )
GObject.type_register( My_CellRendererText )
I have a table that is filled with entry boxes, labels, and buttons.
Currently, if I compile the code, I can get input from a text box but only if the users presses the enter key, and the text only comes from the box they are currently typing in.
I would like to be able to get input from both text boxes when the "Login" button is pushed. I've tried using the same callback function that's used for enter key on the entry box, but GTK gives me an error.
If anyone could show me some code that would allow for me to get text from my entry boxes that are within tables (I know the method for retrieving data from tables and v/boxes is different) it would be greatly appreciated, as I can't seem to find it in any tutorials.
Will update w/working code.
Error when trying to attach status bar to table:
(Entry:5526): Gtk-CRITICAL **: gtk_table_attach: assertion `child->parent == NULL' failed
(Entry:5526): GLib-GObject-WARNING **: invalid cast from GtkTable' toGtkStatusbar'
Your callback function (named callback) needs to access both GtkEntry widgets in order to obtain their values. There are several ways this can be accomplished. Many GTK C programs use global variables, or global variables with file scope (ie a variable declared as static outside of any function within a file).
Remove your entry1 and entry2 variables near the top of the file before any functions:
static GtkWidget *entry1 = 0;
static GtkWidget *entry2 = 0;
And then modify the callback like so:
/* Our callback.
* The data passed to this function is printed to stdout */
static void callback( GtkWidget *widget, gpointer data)
{
const gchar *entry_text1;
const gchar *entry_text2;
g_print ("Hello again - %s was pressed\n", (char *) data);
entry_text1 = gtk_entry_get_text (GTK_ENTRY (entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
You should additionally make similar modifications to the enter_callback function, and don't forget to remove the GtkWidget pointers to both GtkEntry from main.
As an alternative to using (static) global variables, create a data structure to hold the entries:
typedef struct login_data
{
GtkWidget *entry1;
GtkWidget *entry2;
} login_data;
This then gets passed to the callback (rather than text string as before), and the callback changes like so:
static void callback( GtkWidget *widget, gpointer data)
{
login_data* ld = (login_data*)data;
const gchar *entry_text1;
const gchar *entry_text2;
entry_text1 = gtk_entry_get_text (GTK_ENTRY (ld->entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (ld->entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
The data structure is dynamically allocated to prevent it going out of scope (not strictly necessary in simple applications) and this is done before using g_signal_connect to connect the callback to the entries:
login_data* ld = g_malloc(sizeof(*ld));
// callback function to execute when login is clicked
g_signal_connect (LoginButton, "clicked", G_CALLBACK (callback), (gpointer) ld);
Using this method, you must change all references to entry1 and entry2 to ld->entry1 and ld->entry2. Lastly, before the program exits, you should call g_free on the dynamically allocated struct ie g_free(ld).
BTW, for this program you don't need two separate callbacks, remove enter_callback and just use callback for both.
I want to create a grid with buttons. When a button is clicked I want it to change color, and 0 or 1 get stored in an array depending on the current state of the button.
Now I do this by creating the buttons with two for loops (rows, and columns).
Inside the for loops;
/*Create an ID number for the button being created*/
btn_nr ++;
char btn_nr_str[3];
sprintf(btn_nr_str,"%d",btn_nr); //convert nr to string
/*Create button*/
button = gtk_button_new();
/* When the button is clicked, we call the "callback" function
* with a pointer to the ID */
gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (callback)(gpointer) btn_nr_str);
/* Insert button into the table */
gtk_table_attach_defaults (GTK_TABLE(table), button, col, col+1, row, row+1);
gtk_widget_show (button);
The callback function;
void callback( GtkWidget *widget, gpointer nr)
{
GdkColor buttonColor;
gdk_color_parse ("black", &buttonColor);
gtk_widget_modify_bg ( GTK_WIDGET(widget), GTK_STATE_NORMAL, &buttonColor);
g_print ("Hello again - %s was pressed\n", (char *) nr);
}
The buttons are created like wanted, and when clicked they turn black.
However, all buttons print the last created button's ID.
How do I pass the right ID on?
You are accessing a local array (btn_nr_str) from outside (the callback) its scope (the for cycle). The idea is correct (using user_data) but the implementation is not.
For your specific case, you can use the type conversion macros provided by GLib. They are meant for exactly this purpose:
/* In the for cycle */
g_signal_connect(button, "clicked", G_CALLBACK(callback), GINT_TO_POINTER(btn_nr);
/* In the callback */
gint btn_nr = GPOINTER_TO_INT(user_data);
P.S.: gtk_signal_connect has been deprecated years ago.
As shown in the example below, this callback function is when the user clicks an OK button. I can get window (the top level widget) from button by using gtk_widget_get_toplevel, but I'm stuck trying to get a widget pointer for a GtkEntry widget with name ENTRY.
/* Called when OK button is clicked */
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
//The line directly below is the one I get an error on
GtkWidget *entry = lookup_widget( GTK_WIDGET(button), "ENTRY" );
gchar *text1, *text2;
text1 = gtk_entry_get_text( GTK_ENTRY(entry));
text2 = g_strconcat("Hello, ", text1, NULL);
GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET(button));
GtkWidget *dialog = gtk_message_dialog_new( window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
text2);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
But I get the error "undefined reference to lookup_widget." I can find a billion examples of snippets of code using lookup_widget, but not a single one full source code example showing the headers that enable the use of it. I'm using Anjuta3.2.0 and the latest Glade plugin.
As Basile Starynkevitch says, lookup_widget() was a function generated by Glade 2. However, code generation by Glade has been deprecated for quite a long time now, in favor of (first) libglade and (later) GtkBuilder. In fact, Glade 3 won't even do it.
The preferred solution is to pass a pointer to your ENTRY as the user data pointer when you connect the signal, or, if you're using gtk_builder_connect_signals(), store a pointer to ENTRY in your class and pass the class as the user data pointer.
However, if you must use lookup_widget(), here's the source that Glade 2 generated as of about 6 years ago:
GtkWidget*
lookup_widget (GtkWidget *widget,
const gchar *widget_name)
{
GtkWidget *parent, *found_widget;
for (;;)
{
if (GTK_IS_MENU (widget))
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
else
parent = widget->parent;
if (!parent)
parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
if (parent == NULL)
break;
widget = parent;
}
found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
widget_name);
if (!found_widget)
g_warning ("Widget not found: %s", widget_name);
return found_widget;
}
For this to work, you have to do the following for every widget contained within a toplevel window:
g_object_set_data_full (G_OBJECT (toplevel), "name-of-widget", gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref);
and then the following once for each toplevel window:
g_object_set_data (G_OBJECT (toplevel), "name-of-toplevel", toplevel);
Seems to me to be more trouble than it's worth.
Glade-2 implements lookup_widget() in support.c and the header is support.h
Once the GLADE GUI is converted to C codes these files are generated automatically.
i have dialog window with GtkEntry. I want to select all text in entry right after dialog window becomes visible to user. I tried this, but its not working, i see no selection:
static void OnEntryShow(GtkWidget *entry, gpointer user_data)
{
gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
}
...
gtk_entry_set_text(GTK_ENTRY(myEntry), "text");
g_signal_connect(myEntry, "show", G_CALLBACK(OnEntryShow), NULL);
if (gtk_dialog_run(GTK_DIALOG(myDialog)) == GTK_RESPONSE_OK)
...
How can i select text in GtkEntry after GtkDialog becomes visible?
Perhaps you want the GtkEntry to grab focus?
Try this:
gtk_widget_grab_focus (entry);
where entry is in this case the pointer to your GtkEntry widget.
The documentation of the function can be found here.
You should use the function documented here.
text_entry.select_region(0,2) will select the first two characters, while (0, -1) will select the entire text.
Here's a solution I've used for gtkmm using the get_iter_at_offset and select_range functions.
Gtk::TextIter match_start = m_textBuffer->get_iter_at_offset(0);
Gtk::TextIter match_end = m_textBuffer->get_iter_at_offset(-1); // -1 to select all
m_textBuffer->select_range(match_start,match_end);