GtkEntry: bestimmte Zeichen von der Eingabe ausschließen



  • Ich möchte ein kleines Programm schreiben, in dem man in mehreren Tabs einen Text eingeben kann. Zur Laufzeit sollen mittels Knopfdruck ("AddButton") neue Tabs eingefügt werden. Diese Tabs sollen jedoch nur Zeichen von a-z, A-Z, 0-9 sowie ".", "_" und "-" enthalten.
    Ich habe das ganze so gelöst, dass sich beim anklicken von AddButton ein kleines Fenster mit einem GtkEntry öffnet, in welches man einen Namen für den neuen Tab eingibt.
    Nun soll während der Texteingabe darauf geachtet werden, dass nur erlaubte Symbole eingegeben werden. Alle anderen Zeichen sollen bestenfalls gar nicht erst hinzugefügt werden.

    {
    //(...)
    NameEntry = gtk_entry_new();
    g_signal_connect(NameEntry, "preedit-changed", G_CALLBACK(on_NameEntry_key_press), NULL);
    
    }
    
    void on_NameEntry_key_press(GtkEntry *entry, gchar* string, gpointer user_data)
    {
      gchar forbidden[] = "áàâćĉéèêǵĝĥíìîĵḱḿńǹóòôṕŕśŝúùûǘǜẃẁŵýỳŷźẑßäöü ÁÀÂĆĈÉÈÊǴĜĤÍÌÎĴḰḾŃǸÓÒÔṔŔŚŜÚÙÛǗǛẂẀŴÝỲŶŹẐÄÖÜ\"§$%&/()=?'~²³\n{[]}^°@€<>|µ,;:\\";
      gint i;
    
      for (i=0; i< strlen(forbidden); i++)
      {
        if (string[0] == forbidden[i])
        {
          string = NULL; //Ziel: der Tastendruck soll komplett ignoriert werden
        }
      }
    }
    

    Leider passiert überhaupt nichts, wenn ich einen Buchstaben eingebe. 😞 Ich kann dennoch jedes Zeichen in das Feld eingeben, ganz gleich ob es in der forbidden-Variable gespeichert ist oder nicht.

    Alternativ habe ich es so abgewandelt, dass ich dem GtkEntry einen Buffer zuweise und diesen manipulieren möchte:

    {
    //(...)
      GtkEntryBuffer *NameBuffer =gtk_entry_buffer_new(NULL, -1);
      NameEntry = gtk_entry_new_with_buffer(NameBuffer);
      g_signal_connect(NameBuffer, "inserted-text", G_CALLBACK(on_NameEntry_key_press), NULL);
    
    }
    
    gchar *clear(gchar *text)
    {
    	gchar forbidden[] = "áàâćĉéèêǵĝĥíìîĵḱḿńǹóòôṕŕśŝúùûǘǜẃẁŵýỳŷźẑßäöü ÁÀÂĆĈÉÈÊǴĜĤÍÌÎĴḰḾŃǸÓÒÔṔŔŚŜÚÙÛǗǛẂẀŴÝỲŶŹẐÄÖÜ\"§$%&/()=?'~²³\n{[]}^°@€<>|µ,;:\\";
    	std::string buffer = text;
    
    	gint i;
    	for (i=0; i < strlen(forbidden); i++)
    	{
    		gint pos = (gint)buffer.find_first_of(forbidden[i]);
    		while (pos >= 0)
    		{
    			buffer.erase(pos, 1);
    			pos = (gint)buffer.find_first_of(forbidden[i]);
    		}
    	}
    	gchar *result = (gchar*)buffer.c_str();
    
    	gtk_button_set_label(GTK_BUTTON(CompileButton), result);
    
    	return result;
    }
    
    void on_NameEntry_key_press(GtkEntryBuffer *buffer, guint position, gchar *chars, guint n_chars, gpointer user_data)
    {
      gchar *name = clear((gchar*)gtk_entry_buffer_get_text(buffer));
      gtk_entry_buffer_set_text(NameBuffer, name, -1); //<-- hier Programmabsturz
    
      //Alternativ nur zum Test:
      gtk_entry_buffer_set_text(NameBuffer, "test", 4); //Text im GtkEntry ändert sich nicht!
    }
    

    Was genau mache ich denn falsch?

    Edit: In dem Codefenster wird die "forbidden"-Variable falsch angezeigt.

    Sie lautet:
    gchar forbidden[] = "áàâćĉéèêǵĝĥíìîĵḱḿńǹóòôṕŕśŝúùûǘǜẃẁŵýỳŷźẑßäöü ÁÀÂĆĈÉÈÊǴĜĤÍÌÎĴḰḾŃǸÓÒÔṔŔŚŜÚÙÛǗǛẂẀŴÝỲŶŹẐÄÖÜ\"§$%&/()=?'~²³\n{[]}^°@€<>|µ,;:\";



  • GR-Thunderstorm schrieb:

    Nun soll während der Texteingabe darauf geachtet werden, dass nur erlaubte Symbole eingegeben werden. Alle anderen Zeichen sollen bestenfalls gar nicht erst hinzugefügt werden.

    Ohne es jetzt gross getestet zu haben, würde ich das Signal

    changed
    

    verwenden. Du solltest aber jede zuvor gemachte gültigen Eingaben zwischenspeichern und bei unerwünschter Zeicheneingabe das Eingabefeld via

    gtk_entry_set_text
    

    mit dem gültigen, zwischengespeicherten Inhalt wieder überschreiben. Dann wird die letzte Eingabe ignoriert.



  • Wie schon von abcdefg geschrieben, solltest du beim Signal changed bleiben. Da du im zweite Beispiel std::strings verwendest, also zumindest zum Teil in C++ programmierst, könnte eine Möglichkeit so aussehen (ungetestet):

    void on_NameEntry_key_press(GtkEntry *entry, gchar* string, gpointer user_data)
    {
      std::string buffer = string;
      std::string::size_type pos =
        buffer.find_first_not_of("abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXY0123456789.-_");
      if ( pos == std::string::npos )
      {
        return;
      }
      buffer = buffer.erase(pos, 1)
      gtk_entry_set_text(entry, buffer.c_str())
    }
    


  • Vielen Dank, mit eurer Unterstützung habe ich es geschafft. 🙂

    Der Code von Stefkowa hat zum Programmabsturz geführt, aber auf der Grundlage konnte ich eine funktionierende Lösung erarbeiten. 🙂

    const gchar *clear(gchar *text)
    {
    	string buffer = text;
    
    	string::size_type pos = buffer.find_first_not_of("abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXY0123456789.-_");
    	while (pos != string::npos)
    	{
    		buffer.erase(pos,1);
    		pos = buffer.find_first_not_of("abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXY0123456789.-_");
    	}
    
    	gchar *result = new gchar;
    	strcpy(result,buffer.c_str());
    	return result;
    }
    
    void on_NameEntry_key_press(GtkEntry *entry, gchar* string, gpointer user_data)
    {
    	const gchar *buffer = clear((gchar*)gtk_entry_get_text(entry));
    	gtk_entry_set_text(entry, buffer);
    }
    

    Mit "changed" funktioniert nun auch das entsprechende Signal. Das sollte mal jemand in der Dokumentation von GTK verbessern. ⚠


Anmelden zum Antworten