2013-05-14 3 views
4

В gui Я хочу изменить текст, который пользователь вставляет в GtkEntry. например, если пользователь вводит «joHn doe», мой gui должен видеть, что это не красиво отформатированное имя и изменяет его на «John Doe».GtkEntry изменить текст ввода пользователем

Я подключаю обработчик к «измененному» сигналу, как описано, например, GtkEntry text change signal. Возникающая проблема заключается в том, что если я изменяю запись в обработчике сигнала, «измененный» сигнал испускается снова и снова, пока не появится королевство.

В настоящее время я предотвращаю это, проводя сравнение строк, и я изменяю текст только в GtkEntryBuffer, если текст «исправленной» версии не соответствует тексту внутри записи. Однако я чувствую, что как программист, я должен иметь возможность изменять текст внутри записи без того, чтобы измененный обработчик вызывался снова и снова.

Обработчик измененный сигнал:

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); 
} 

и моя nameify функция:

/*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; 
} 

любая помощь приветствуется.

ответ

3

Невозможно подключиться к «измененному» сигналу, но более подходит для подключения к сигналу «вставить-текст». Еще лучше, если обработчик по умолчанию «insert-text» обновит запись. Вместо использования g_signal_connect_after для сигнала «вставить текст», чтобы обновить текст в записи, это предотвратит бесконечный запуск измененного сигнала. Это также должно быть сделано для сигнала «delete-text», потому что если пользователь удаляет прописную букву, капитал должен быть удален, а второй должен быть капитализирован.

так далее создание перспективы:

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); 

Тогда вы можете иметь эти обработчик сигналов:

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); 
} 

и они, чем может быть использованы с функцией nameify в исходном сообщении. вы можете даже указать указатель на данные вместо «NULL», чтобы использовать этот обработчик с различными функциями, которые могут изменять строку в записи.

+0

+1 Прямо на! Я пропустил часть удаления :) Пожалуйста, подумайте о том, чтобы принять ваш ответ, если он решил вашу проблему, это поможет кому-то, кто может столкнуться с этим в будущем :) –

0

Самое быстрое решение, на мой взгляд, было бы временно заблокировать ваш обратный вызов от вызова.

Группа функций, каждая из которых возвращает «handler_id» типа gulong. Вам нужно будет сохранить этот идентификатор, передать его на ваш обратный вызов, используя аргумент «userdata» (или просто использовать вместо него глобальную статическую переменную), затем введите код обработки текста между парой g_signal_handler_block/.

+0

Привет Ancurio, спасибо за ваши усилия, но, если я не ошибаюсь, это не очень помогает, потому что если я блокировать и разблокировать обработчик из обработчика, обработчик разблокируется, когда заканчивается. И после того, как мой обработчик завершает gtk_entry_ (buffer_), set_text все еще испускает сигнал, а затем снова зацикливается. Я действительно ищу способ обновить запись без отправки сигналов. – hetepeperfan

+0

@hetepeperfan Итак, вы попробовали мое предложение и все еще зациклились? – Ancurio

+0

На самом деле это было круто, так что курсор даже не мигал. – hetepeperfan

1

Для вашего требования insert-text сигнал кажется более подходящим. insert-text доступен для внесения изменений в текст перед вводом. Вы можете использовать шаблон функции обратного вызова insert_text_handler часть описания GtkEditable. Вы можете использовать nameify с изменениями функции (так как вы не получите весь текст, кроме частей текста или символов, простейшей модификацией может быть объявление uppercase_nextstatic) для внесения изменений в текст.
Надеюсь, это поможет!

+0

+1 для комментария об использовании сигнала «insert-text». Но нужно также учитывать, что происходит, когда кто-то удаляет символ, а сигнал «вставить-текст» не смотрит на символы, уже находящиеся в записи, только те, которые были вставлены, поэтому я собираюсь опубликовать немного альтернативное решение, которое предотвращает использование статических или глобальных переменных. – hetepeperfan

0

Подключение к insert-text и delete-text - это правильная идея, но вы хотите подключиться, используя g_signal_connect. Если вы используете g_signal_connect_after, то неправильный текст уже был отображен перед его исправлением, что может вызвать мерцание дисплея. Также вам нужно заблокировать обработчики сигналов при вызове gtk_entry_set_text, так как это испускает delete-text, а затем insert-text. Если вы не блокируете сигналы, вы будете рекурсивно вызывать свои обработчики сигналов. Помните, что сигналы GObject - это просто вызовы функций. Излучение сигнала такое же, как вызов обработчиков непосредственно из вашего кода.

Я предлагаю иметь обработчик для insert-text, который смотрит, нужно ли ему менять новый вход. Если он затем создать новую строку и сделать это в соответствии с GtkEditable документации

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"); 

Если вам не нужно, чтобы изменить вход только вернуться.

Для delete-text обработчика я бы смотреть, чтобы увидеть, если вам нужно изменить текст (помня, что ничего не было еще удалена), и если да обновить всю строку с

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"); 

снова просто вернуться, если вам не нужно менять текст.

0

проще, чем блокирование и разблокирование ваш сигнал просто логическое значение:

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 
} 
Смежные вопросы