6

GUI で、ユーザーが GtkEntry に挿入したテキストを変更したいと考えています。たとえば、ユーザーが「joHn doe」と入力すると、GUI はこれが適切にフォーマットされた名前ではないことを認識し、これを「John Doe」に変更します。

たとえばGtkEntry text change signalで説明されているように、ハンドラを「changed」シグナルに接続します。発生する問題は、シグナル ハンドラーのエントリを変更すると、王国が来るまで「変更された」シグナルが何度も発行されることです。

私は現在、文字列比較を行うことでこれを防いでおり、「名前付き」バージョンのテキストがエントリ内のテキストと等しくない場合にのみ、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;
}

どんな助けでも大歓迎です。

4

5 に答える 5

1

あなたの要件については、insert-text信号がより適切と思われます。insert-text入力前にテキストを変更できるようにします。insert_text_handlerの説明のコールバック関数テンプレート部分を利用できますGtkEditable。テキストを変更するために、関数を変更して使用できnameifyます(テキスト全体ではなくテキストまたは文字の一部を取得するため、最も簡単な変更はuppercase_next staticを宣言することです)。
お役に立てれば!

于 2013-05-14T16:54:27.513 に答える
0

と に接続するinsert-textdelete-textは正しい考えですが、 を使用して接続したいと考えていますg_signal_connect。を使用するg_signal_connect_afterと、修正する前に誤ったテキストがすでに表示されているため、表示がちらつく場合があります。またgtk_entry_set_text、 this の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");

テキストを変更する必要がない場合は、単に戻ります。

于 2013-07-06T13:33:14.140 に答える
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
}
于 2014-01-14T20:20:08.140 に答える