GtkEntry changes text to user input

In gui, I want to change the text that the user inserts into GtkEntry. for example, if the user enters "joHn doe", my gui should see that it is not a nicely formatted name and change it to "John Doe".

I connect the handler to the "modified" signal, as described, for example, GtkEntry Text Change Signal . The emerging problem is that if I change the record in the signal handler, the “changed” signal is emitted again and again until the kingdom appears.

I currently prevent this by comparing strings, and I only change the text in the GtkEntryBuffer if the text of the “corrected” version does not match the text inside the record. However, I feel like a programmer, I should be able to change the text inside the record without the modified handler being called again and again.

Modified signal handler:

void nameify_entry ( GtkEditable* editable, gpointer data ) { gchar* nameified; const gchar *entry_text; entry_text = gtk_entry_get_text( GTK_ENTRY(editable) ); nameified = nameify(entry_text); /*is it possible to change the buffer without this using this string comparison, without the "change" signal being emitted over and over again?*/ if ( g_strcmp0(entry_text, nameified) != 0 ){ GtkEntryBuffer* buf = gtk_entry_get_buffer(GTK_ENTRY(editable) ); gtk_entry_buffer_set_text( buf, nameified, -1 ); } g_free(nameified); } 

and my name function:

 /*removes characters that should not belong to a name*/ gchar* nameify ( const char* cstr ) { const char* c; gchar* ret_val; GString* s = g_string_new(""); gboolean uppercase_next = TRUE; g_debug( "string = %s", cstr); for ( c = cstr; *c != '0'; c = g_utf8_next_char(c) ) { gunichar cp = g_utf8_get_char(c); if ( cp == 0 ) break; if ( g_unichar_isalpha( cp ) ){ if ( uppercase_next ){ g_string_append_unichar( s, g_unichar_toupper(cp) ); uppercase_next = FALSE; } else{ g_string_append_unichar(s,g_unichar_tolower(cp)); } } if ( cp == '-' ){ g_string_append_unichar( s, cp); uppercase_next = TRUE; } if ( cp == ' '){ g_string_append_unichar( s, cp); uppercase_next = TRUE; } } ret_val = s->str; g_string_free(s, FALSE); return ret_val; } 

any help is appreciated.

+4
source share
5 answers

It is not very convenient to connect to the “modified” signal, but is more suitable for connecting to the “insert-text” signal. Even better, if the default "insert-text" handler updates the entry. Instead of g_signal_connect_after in the insert-text signal to update the text in the record, this will prevent the modified signal from running endlessly. This should also be done for the delete-text signal, because if the user deletes an uppercase letter, the capital must be deleted, and the second must be capitalized.

and so on:

 g_signal_connect_after( entry, "insert-text", G_CALLBACK(name_insert_after), NULL ); g_signal_connect_after( entry, "delete-text", G_CALLBACK(name_delete_after), NULL ); 

Then you can use these signal handlers:

 void name_insert_after (GtkEditable* edit, gchar* new_text, gint new_length, gpointer position, gpointer data) { /*prevent compiler warnings about unused variables*/ (void) new_text; (void) new_length; (void) position; (void) data; const gchar* content = gtk_entry_get_text( GTK_ENTRY(edit) ); gchar* modified = nameify( content); gtk_entry_set_text(GTK_ENTRY(edit),modified); g_free(modified); } void name_delete_after (GtkEditable* edit, gint start_pos, gint end_pos, gpointer data) { /*no op cast to prevent compiler warnings*/ (void) start_pos; (void) end_pos; (void) data; /*get text and modify the entry*/ int cursor_pos = gtk_editable_get_position(edit); const gchar* content = gtk_entry_get_text( GTK_ENTRY(edit) ); gchar* modified = nameify( content); gtk_entry_set_text(GTK_ENTRY(edit),modified); gtk_editable_set_position(edit, cursor_pos); g_free(modified); } 

and they can be used with the name function in the original message. you can even point to a pointer to the data instead of "NULL" to use this handler with various functions that can modify a row in a record.

+3
source

For your requirement, an insert-text signal seems more appropriate. insert-text is available for making possible changes to the text before entering. You can use the insert_text_handler callback function template part of the GtkEditable description. You can use nameify with changes to the function (since you will not get all the text except for parts of the text or characters, the simplest modification may be to declare uppercase_next static) to make changes to the text.
Hope this helps!

+1
source

The quickest solution, in my opinion, would be to temporarily block your callback from calling.

The g_signal_connect function g_signal_connect each returns a "handler_id" of type gulong . You will need to save this identifier, pass it to your callback using the userdata argument (or just use the global static variable instead), and then put the text processing code between g_signal_handler_block / g_signal_handler_unblock .

0
source

Connecting to insert-text and delete-text is the right idea, but you want to connect using g_signal_connect . If you use g_signal_connect_after , then the wrong text was already displayed before correcting it, which may cause the display to flicker. You also need to block the signal handlers when calling gtk_entry_set_text , as this emits delete-text , followed by insert-text . If you do not block signals, you will recursively call your signal handlers. Remember that GObject signals are just function calls. Emitting a signal is the same as calling handlers directly from your code.

I would suggest having a handler for insert-text that looks to see if it needs to change new input. If so, create a new line and do it according to the GtkEditable documentation

 g_signal_handlers_block_by_func (editable, insert_text_handler, data); gtk_editable_insert_text (editable, new-text, g_strlen(new_text) , position); g_signal_handlers_unblock_by_func (editable, insert_text_handler, data); g_signal_stop_emission_by_name (editable, "insert_text"); 

If you do not need to change the input, just come back.

For the delete-text handler, I'll see if you need to change the text (remember that nothing has been deleted yet), and if so, update the entire line with

 g_signal_handlers_block_by_func (editable, insert_text_handler, data); g_signal_handlers_block_by_func (editable, delete_text_handler, data); gtk_entry_set_text (GKT_ENTRY (editable), new-text); g_signal_handlers_unblock_by_func (editable, delete_text_handler, data); g_signal_handlers_unblock_by_func (editable, insert_text_handler, data); g_signal_stop_emission_by_name (editable, "delete_text"); 

return again if you do not need to change the text.

0
source

easier than locking and unlocking your signal, it just has a logical meaning:

 myHandler(...){ static int recursing=0; if(recursing){ recursing=0; return; } ... logic to decide if a change is needed recursing=1; gtk_entru_set_text(...); ... will recurse to your hander, which will clear the recursing variable and resume here } 
0
source

Source: https://habr.com/ru/post/1480669/


All Articles