C++ Builder Snippets  


Eingaben in die TEdit-Komponenten auf Zahlen beschränken:
 
Da die Frage "wie beschränke ich die Eingabemöglichkeiten der TEdit auf Zahlen" nun seit Jahren unverändert weit oben in den Top-Listen aller C++ Builder Foren und Newsgroups zu finden ist, werde ich hier einige Vorgehensweisen auflisten.
Eine der einfachsten Lösungen ist die Verwendung einer Eingabefeld- Komponente, die diese Funktionalität beinhaltet, wie z.B. die TZahlEdit-Komponente von Fred Nest. Die TZahlEdit bietet neben der Möglichkeit, die Eingabe auf Zahlen zu beschränken auch Eigenschaften, die es erlauben die Min- und Maxgrenzen für die einzugebenden Zahlen zu definieren. TZahlEdit (Freeware mit Source) können Sie hier herunterladen.
Will man diese Funktionalität selbst implementieren, um möglichst wenig fremde Komponenten zu verwenden, richtet sich der Aufwand danach, welche Zahlen der Anwender eingeben darf.

Sind es nur positive Integer-Werte, ist die Lösung am einfachsten: dem Steuerelement-Style muss in diesem Fall nur um ES_NUMBER ergänzt werden. Dafür kann z.B. die Funktion SetIntEdit() (unten) verwendet werden. Diese wird einfach in OnCreate- oder OnShow-Ereignisbehandlung des Formulars aufgerufen. SetIntEdit() erwartet den Zeiger auf die entsprechende TEdit-Komponente als Parameter:
//---------------------------------------------------------------------------
// Funktion SetIntEdit() beschränkt die Eingaben in die TEdit-Komponente
// auf ganze (positive) Zahlen
//---------------------------------------------------------------------------
void SetIntEdit(TEdit* plEdit)
{
  SetWindowLong(plEdit->Handle, GWL_STYLE, GetWindowLong(
    plEdit->Handle, GWL_STYLE) | ES_NUMBER);
}
//---------------------------------------------------------------------------
// OnCreate-Ereignis des Formulars
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  SetIntEdit(Edit1);
}
Falls der Anwender aber in der Lage sein muss, auch negative Werte einzugeben, reicht ES_NUMBER-Style nicht mehr aus. In diesem Fall muss eine Ereignisbehandlung für OnKeyPress-Event der TEdit dafür sorgen, dass numerische Zeichen und Minus akzeptiert werden:
//---------------------------------------------------------------------------
// Ereignisbehandlung für OnKeyPress-Ereignis der Eingabefelder für
// positive und negative ganze Zahlen:
//---------------------------------------------------------------------------
void __fastcall TForm1::EditIntKeyPress(TObject *Sender, char &Key)
{
  // Zeiger auf Sender casten:
  TEdit* pEdit = dynamic_cast<TEdit*>(Sender);
  // Zeichen verwerfen, falls weder Minus-Zeichen am Anfang des
  // Eingabestrings noch eine Ziffer eingegeben:
  if((Key == '-' && (pEdit->SelStart || pEdit->Text.Pos("-"))) ||
    ((Key < '0' || Key > '9') && Key != 8 && Key != '-'))
    Key = 0;
}
Ähnlich ist es bei Kommazahlen: da müssen wir ebenfalls die Eingabemöglichkeit für das Dezimaltrennzeichen schaffen, und wo wir schon dabei sind, können wir ja auch gleich Punkt oder Komma als Dezimaltrennzeichen akzeptieren und bei der Eingabe ggf. automatisch konvertieren:
//---------------------------------------------------------------------------
// Ereignisbehandlung für OnKeyPress-Ereignis der Eingabefelder für
// positive und negative Kommazahlen:
//---------------------------------------------------------------------------
void __fastcall TForm1::EditDoubleKeyPress(TObject *Sender, char &Key)
{
  // Zeiger auf Sender casten:
  TEdit* pEdit = dynamic_cast<TEdit*>(Sender);
  // Falls Punkt oder Komma eingegeben und noch kein Dezimaltrennzeichen
  // im Eingabestring vorhanden, Dezimaltrennzeichen einsetzen:
  if((Key == '.' || Key == ',') && !pEdit -> Text.Pos(DecimalSeparator))
    Key = DecimalSeparator;
  // Zeichen verwerfen, falls weder Minus-Zeichen am Anfang des
  // Eingabestrings noch eine Ziffer eingegeben:
  else if((Key == '-' && (pEdit->SelStart || pEdit->Text.Pos("-"))) ||
         ((Key < '0' || Key > '9') && Key != 8 && Key != '-'))
    Key = 0;
}
Bei allen oben aufgeführten Vorgehensweisen hat der Anwender allerdings immer noch die Möglichkeit, unzulässige Zeichen über die Zwischenablage einzufügen. Um die Eingabe über die Zwischenablage abzufangen, kann eine einfach zu implementierende Methode verwendet werden: in der OnEnter-Ereignisbehandlung der TEdit wird die Zwischenablage mit Hilfe der Open()-Methode der TClipboard()-Klasse "deaktiviert" und beim Verlassen der Steuerelemente mit Hilfe der Close()-Methode wieder aktiviert. Die Daten in der Zwischenablage gehen dabei nicht verloren, sind aber nicht verwendbar solange unsere Zahlen-TEdits Eingabefokus besitzen.

//---------------------------------------------------------------------------
// OnEnter-Ereignis der Steuerelemente für die Zahleneingaben:
// Hier werden die Zwischenablagenfunktionen durch den Aufruf der
// Open()-Methode des Clipboard() deaktiviert. So kann verhindert werden,
// dass ungültige Zeichen über die Zwischenablage eingegeben werden.
//---------------------------------------------------------------------------
void __fastcall TForm1::EditEnter(TObject *Sender)
{
  // Zwischenablagenfunktionen blokieren:
  Clipboard()->Open();
}

//---------------------------------------------------------------------------
// OnExit-Ereignis der Steuerelemente für die Zahleneingaben:
// Hier wird die Zwischenablage wieder "aktiviert".
//---------------------------------------------------------------------------
void __fastcall TForm1::EditExit(TObject *Sender)
{
  // Zwischenablagenfunktionen freigeben:
  Clipboard()->Close();
}
Diese Methode lässt sich zwar sehr einfach implementieren, hat aber den Nachteil, dass weder das Kopieren des TEdit-Inhalts, noch Einfügen einer (zulässigen) Zahl möglich ist.

Eine elegantere (aber auch aufwendigere Lösung) ist die Behandlung der WM_PASTE-Botschaft, die von Windows beim Einfügen aus der Zwischenablage an die Steuerelemente gesendet wird. Das Einfügen wird nur dann erlaubt, wenn der Inhalt der Zwischenablage eine Zahl beinhaltet.


In der Header-Datei:
//----------------------------------------------------------------
// . . . 
private:

  // ConvertionToDoublePossible() prüft, ob der übergebene String
  // zu double konvertiert werden kann
  bool ConvertionToDoublePossible(AnsiString &sValueString);

  // Fensterprozedur (Botschaftsbehandlungsroutine) für die Edit3
  void __fastcall WndProcPasteNum(Messages::TMessage &Message);

  // Zeiger auf die ursprüngliche Fensterprozedur der Edit3
  TWndMethod OldWndProcEdit3;
// . . . 
//----------------------------------------------------------------
In der CPP-Datei:
//---------------------------------------------------------------------------
// OnCreate-Ereignis des Formulars
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  // . . .

  // die Fensterprozedur zuweisen, die auf
  // an das Steuerelement gesendete Botschaften reagiert:
  OldWndProcEdit3 = Edit3->WindowProc;
  // Dem Edit3 eine neue Fensterprozedur für die
  // Behandlung der WM_PASTE-Botschaft zuweisen:
  Edit3->WindowProc = WndProcPasteNum;
}
//---------------------------------------------------------------------------
// ConvertionToDoublePossible() prüft, ob der übergebene String zu double
// konvertiert werden kann. Der übergebene String wird dabei von führenden
// und abschliessenden Leer- und Sonderzeichen bereinigt und das Dezimal-
// trennzeichen wird ggf. an die Systemeinstellung angepasst
//---------------------------------------------------------------------------
bool TForm1::ConvertionToDoublePossible(AnsiString &sValueString)
{
  try
  {
    sValueString = sValueString.Trim();
    int ilDecSepPos = sValueString.Pos((DecimalSeparator == '.' ?
      AnsiString(",") : AnsiString(".")));
    if(ilDecSepPos > 0) sValueString[ilDecSepPos] = DecimalSeparator;
    sValueString.ToDouble();
    return true;
  }
  catch(...) { return false; }
}

//---------------------------------------------------------------------------
// Fensterprozedur (Botschaftsbehandlungsroutine) für die Edit3
//---------------------------------------------------------------------------
void __fastcall TForm1::WndProcPasteNum(Messages::TMessage &Message)
{
  // falls jemand versucht, etwas über die Zwischenablage
  // einzufügen und sich in der Ablage ein Text befindet:
  if(Message.Msg == WM_PASTE && Clipboard()->HasFormat(CF_TEXT))
  {
    // prüfen, ob der Clipboard-Inhalt in
    // double-Wert konvertiert werden kann:
    AnsiString slDoubleStr = Clipboard()->AsText;
    if(ConvertionToDoublePossible(slDoubleStr))
    {
      // fals Konvertierung möglich, Inhalt des Eingabefeldes markieren
      // (anderenfalls kann es passieren, dass zwei Zahlen im Feld stehen)
      Edit3->SelectAll();
      // den Clipboard-Inhalt mit der ggf. "Dezialtrennzeichenkorrigierten"
      // Version der Textdarstellung der Zahl aktualisieren:
      Clipboard()->AsText = slDoubleStr;
    }
    else return; // falls keine Zahl in der Ablage, nichts tun
  }
  // zum Schluss die Botschaft an die ursprüngliche
  // Botschaftsbehandlungsroutine des TEdit übergeben:
  OldWndProcEdit3(Message);
}
Die OnKeyPress-Ereignisbehandlungsroutine muss wie folgt erweitert werden, damit die Standard-Tastenkombinationen für die Zwischenablage ebenfalls benutzbar sind:
//---------------------------------------------------------------------------
// Ereignisbehandlung für OnKeyPress-Ereignis der Eingabefelder für
// positive und negative Kommazahlen:
//---------------------------------------------------------------------------
void __fastcall TForm1::EditDoubleKeyPress(TObject *Sender, char &Key)
{
  // Zwischenablagefunktionen über die Tastatur erlauben:
  if(((GetKeyState(VK_SHIFT) & 0x8000) && (GetKeyState(VK_INSERT) & 0x8000))
    || (GetKeyState(VK_CONTROL) & 0x8000))
    return;

  // Zeiger auf Sender casten:
  TEdit* pEdit = dynamic_cast<TEdit*>(Sender);
  // Falls Punkt oder Komma eingegeben und noch kein Dezimaltrennzeichen
  // im Eingabestring vorhanden, Dezimaltrennzeichen einsetzen:
  if((Key == '.' || Key == ',') && !pEdit -> Text.Pos(DecimalSeparator))
    Key = DecimalSeparator;
  // Zeichen verwerfen, falls weder Minus-Zeichen am Anfang des
  // Eingabestrings noch eine Ziffer eingegeben:
  else if((Key == '-' && (pEdit->SelStart || pEdit->Text.Pos("-"))) ||
         ((Key < '0' || Key > '9') && Key != 8 && Key != '-'))
    Key = 0;
}

  Download BCB5
Projekt-Quellcode
Download
Demo-Exe

© '99-2002 by S. Kreutzmann