# GAMBAS BOOK 3.15.2

## Control elements 1

### Chapters

02.07.2018
k16:k16.6:k16.6.3:start

## 16.6.3 Examples for using a TextBox - Validation of input

Securing the use of valid data in a program is part of the concept for avoiding runtime errors. In → chapter 16.6.2 Valid Data you will find information on the topic and approaches how to validate data from TextBoxes and their different specializations (MaskBox, ValueBox, HistoryBox, InputBox and ButtonBox). For the input of complex numbers, matrices, polynomials or vectors you will find examples in the chapters 29.1 Complex Numbers, 29.3.3 Matrix, 29.3.4 Polynomial and 29.3.5 Vector.

There is no generally valid procedure for checking whether an input string from a TextBox can be converted to a valid date - if the specializations cannot be used. However, the following examples should show you how to use different strategies to provide a program with valid data from an input string for processing.

## 16.6.3.1 Example 1

A number A is recorded in a TextBox and an average measured value (without unit) as a real number R in another TextBox. From the two inputs, a quotient with four decimal places is calculated in the program QM = (A²-Pi) / R and output in a third TextBox (read only). The contents of the output TextBox are deleted each time the entries are changed.

Figure 16.6.3.1.1: Calculation of QM

Before you get started quickly, you should consider the following hints in peace and quiet, although the order does not correspond to any order of precedence:

• The entries in the TextBoxes are of the data type String. To calculate the quotient, however, you need figures.
• When entering into the two TextBoxes, you should limit the input alphabet appropriately.
• While only single digits are allowed for entering the number as characters, the input alphabet for the real number can be written down in this way: {+-,0123456789}.
• Defining the second alphabet, for example, does not in any way protect you from completely pointless entries such as' +0,874-, 9', which forces you to validate the data. You must check whether the input string from the TextBox for the mean value R can be safely converted into a real number.
• The conversion of the comma used in our language area into a dot must be realized internally within the program.
• The numbers - stored in a suitably named variable - must be converted to the Integer data type, where it has been specified not to allow the number 0 as a valid date, which is to be checked. However, this has no effect on the input alphabet {0123456789} because otherwise, for example, the number 10 would be impossible.
• The measured value R is in good hands in a variable of the data type float. The conversion to this type must take this into account.
• Gambas provides you with CFloat (Value As Variant) a suitable function for the conversion.
• In order not to provoke an error' division by zero' when calculating the quotient, the input of a zero has to be filtered out and after an indication to the user a correction for the faulty denominator has to be offered.
• Before you start the calculation, you should check whether the input text boxes are not empty. In this case, interrupt the program flow, inform the user in an appropriate manner and offer correction possibilities.

The source code is presented in extracts:

```[1] ' Die Eigenschaft txbResult.ReadOnly wird auf TRUE gesetzt
[2] Public Sub btnCalculate_Click()
[3]   Dim sInputN, sInputR, sPatternN, sPatternR As String
[4]   Dim iCount As Integer
[5]   Dim fValue, fCoefficient As Float
[6]
[7]   If Not txbInteger.Text Then ' Prüfung: TextBox leer?
[8]      Message.Error("Eingabefehler 1!") ' Kommentar in einer MessageBox
[9]      txbInteger.SetFocus ' Fokus auf die TextBox txbInteger setzen
[10]      Return ' Prozedur verlassen
[11]   Endif
[12]   If Not txbReal.Text Then ' Prüfung: TextBox leer?
[13]      Message.Error("Eingabefehler 2!")
[14]      txbInteger.SetFocus
[15]      Return
[16]   Endif
[17]
[18]  '----------------------------------------------------------------------------
[19]
[20]   sInputN = Trim(txbInteger.Text) ' Leerzeichen am Anfang und am Ende entfernen
[21]   Try iCount = CInteger(sInputN) ' Versuch: Konvertierung String → Ganze Zahl
[22]   If Error Then ' Fehlerbehandlung
[23]      Message("Fehler 1")
[24]      txbInteger.SetFocus
[25]      Return
[26]   Endif
[27]
[28] ' Anzahl Null herausfiltern
[29]   If iCount = 0 Then
[30]      Message.Info("Die Anzahl muss größer als Null sein!")
[31]      txbReal.SetFocus
[32]      Return
[33]   Endif
[34]
[35] '----------------------------------------------------------------------------
[36]
[37]   sInputR = Trim(txbReal.Text) ' Leerzeichen am Anfang und am Ende entfernen
[38] ' Dezimalseparator der aktuellen Locale durch den Punkt ersetzen
[39]   sInputR = Replace\$(sInputR, Left\$(Format\$(0, ".0")), ".")
[40]
[41]   Try fValue = CFloat(sInputR) ' Versuch: Konvertierung String → Reelle Zahl
[42]   If Error Then
[43]      Message("Fehler 2")
[44]      txbReal.SetFocus
[45]      Return
[46]   Endif
[47]
[48]   If fValue = 0 Then ' Null herausfiltern
[49]      Message.Info("Die (reelle) Zahl 0 ist nicht zulässig!")
[50]      txbReal.SetFocus
[51]      Return
[52]   Endif
[53]
[54] '----------------------------------------------------------------------------
[55]
[56]   fCoefficient = Round((iCount * iCount - Pi()) / fValue, -4) ' Berechnung Quotient
[57]   txbResult.Text = Str(fCoefficient) ' Anzeige Quotient (Koeffizient QM)
[58]
[59] End ' btnCalculate_Click()
[60]
[61] '----------------------------------------------------------------------------
[62]
[63] Public Sub txbInteger_KeyPress() ' Umsetzung Eingabe-Alphabet
[64]   CheckInput("0123456789")
[65] End ' txbDigits_KeyPress()
[66]
[67] Public Sub txbReal_KeyPress() ' Umsetzung Eingabe-Alphabet
[68]   CheckInput("+-,0123456789")
[69] End ' txbDigits_KeyPress()
[70]
[71] Public Sub CheckInput(sAllowed As String) ' Idee Charles Guerin
[72]   Select Case Key.Code
[73]     Case Key.Left, Key.Right, Key.BackSpace, Key.Delete, Key.End, Key.Home, Key.Enter, Key.Return
[74]       Return
[75]     Default
[76]       If Key.Text And If InStr(sAllowed, Key.Text) Then
[77]          Return
[78]       Endif
[79]   End Select
[80]   Stop Event
[81] End ' CheckInput(sAllowed As String)
[82]
[83] ' Public Sub txbInteger_Change()
[84] '    txbResult.Clear
[85] ' End
[86] ' Public Sub txbReal_Change()
[87] '   txbResult.Clear
[88] ' End
[89]
[90] Public Sub TBIR_Change()
[91]   txbResult.Clear
[92] End ' TBIR_Change()```

Comment:

• In lines 83 to 88, the requirement is realized that each time the text property in the two text boxes txbInteger and txbReal is changed, the text in the output TextBox is deleted. For two TextBoxes the effort is still justifiable - but with 5 or more? Then it is worthwhile to set the virtual property Group in the IDE of all involved TextBoxes to the same value in each case - here TBIR - and to define a common event handler for all of them. The implementation for the two TextBoxes txbInteger and txbReal can be seen in lines 83 to 85.
• You can still formulate the notes and error messages specifically.
• A simplification would result in lines 20 to 33 by the use of a regular expression, since zero is not accepted as a pattern by the sample check and only correct numbers can be entered:
```[1]   sInputN = Trim(txbInteger.Text)
[2]   sPatternN = "^[1-9][0-9]*\$" ' Alternative mit Null: "^[0]{1}\$|^[1-9][0-9]*\$"
[3]   If sInputN Not Match sPatternN Then
[4]      Message.Error("Eingabefehler 3!")
[5]      txbInteger.SetFocus
[6]      Return
[7]   Endif
[8]   iCount = CInteger(sInputN)```

## 16.6.3.2 Example 2

To ensure that only certain characters - here it is the numbers 0 to 9 - are accepted in a TextBox, the following sample source code is offered in the documentation:

```' My text box only accepts digits

Public Sub MyTextBox_KeyPress()
If Instr("0123456789", Key.Text) = 0 Then
Stop event
Endif
End```

Hints:

• In the gambas documentation it is described that with the stop event you inform the interpreter that the current event should be' canceled'.
• Some events support the action of being aborted. The KeyPress event is one of them. If it is canceled, the keystroke is no longer processed - the input is rejected. It does not matter where Stop Event is located within the event handler. However, it is mandatory to cancel the event.

Works - but unfortunately, you can't correct the sequence of digits in any way, which can be considered a deficiency. Therefore, the following section introduces an improved solution in which you can move the cursor in the TextBox and delete individual digits with the BackSpace key:

```Public Sub txbDigits_KeyPress()
' Nur die Ziffern 0..9 als zulässige Ziffern zulassen
If (Key.Text Not Like "[0-9]") And (Key.Code <> Key.BackSpace) And (Key.Code <> Key.Left) \\
And (Key.Code <> Key.Right) Then
Stop Event
Endif ' Key.Text Not Like "[0-9]" ?
End ' txbDigits_KeyPress() ```

You will undoubtedly still discover a disadvantage - the input alphabet is not variable if you think, for example, of the case that all digits 0-9 are allowed, plus the two sign (+-) and the characters dot, comma and asterisk, as well as the letter x. The input alphabet is not variable. The following solution safely eliminates the disadvantage:

```Public Sub CheckInput(sAllowed As String) ' Idee Charles Guerin
Select Case Key.Code
Case Key.Left, Key.Right, Key.BackSpace, Key.Delete, Key.End, Key.Home, Key.Enter, Key.Return
Return
Default
If Key.Text And If InStr(sAllowed, Key.Text) Then
Return
Endif
End Select
Stop Event

End ' CheckInput(sAllowed As String)

Public Sub txbDigits_KeyPress()
CheckInput("+-,.*0123456789x")
End ' txbDigits_KeyPress()```

The check whether a character entered belongs to the input alphabet or not works without errors. However, remember to check the validity of the input string afterwards if, for example, the input string is to be interpreted as a term in a linear equation. The string -5,88*x+7,1+*23 contains only characters from the input alphabet and is nevertheless not suitable for processing, since it contains a syntax error in the sense of the term specification.

## 16.6.3.3 Example 3

This example does not focus on checking but on prevention, because the user is shown a hint text in the TextBox to minimize incorrect entries. A special TextBox developed by Tobias Boege is used - the Explain-TextBox. The Explain-TextBox is a TextBox, which allows to display an explanatory text (explanation) in the font color grey, if the TextBox is empty and does not have the focus. In this way, you might be able to dispense with explanatory labels in front of the text boxes:

Figures 16.6.3.3.3.1: Explain-TextBox

The class ExplainTextbox is provided in a project in the download area.

## 16.6.3.4 Example 4

It should be checked whether the input of a year number in the interval from 1600 to 2100 in a text box is or will be a leap year.

An astronomical year is the duration of the revolution of the Earth around the central body Sun - our star. In our time units this is 365 days, 5 hours, 48 minutes and 47 seconds. A normal calendar year - but what is already normal - has a length of 365 days. After 4 years, the 5 hours, 48 minutes and 47 seconds, which corresponds to about a quarter of a day, are combined into one day, the 29th of February, and thus a leap year has 366 days. There is a leap year every 4 years, but not every 100 years, but then every 400 years to compensate for the discrepancies of the inserted quarter days to 6 hours. I am thrilled!

As a preventive measure, the number of characters is limited to a maximum of 4 characters:

```[1] Public Sub Form_Open()
[2]   txbLeapYear.MaxLength = 4
[3]   ...
[4] End ' Form_Open()```

The function IsLeapYear (..) converts the above rule for leap years and returns the function value True if the year used as argument was or is a leap year:

```[1] Public Function IsLeapYear(iYear As Integer) As Boolean
[2]
[3]   If (iYear Mod 4) = 0 And (iYear Mod 100) <> 0 Or ((iYear Mod 400) = 0) Then
[4]      Return True
[5]   Else
[6]      Return False
[7]   Endif
[8]
[9] End ' Function IsLeapYear(..)```

In the following source code section - which is followed by a comment - you will see various (preliminary) checks:

```[1] Public Sub txbLeapYear_Activate()
[2]   Dim iCount As Integer
[3]   Dim sInput As String
[4]
[5]   sInput = Trim(txbLeapYear.Text) ' Entfernung von Leerzeichen am Anfang und am Ende des Strings
[6]
[7]   For iCount = 1 To Len(sInput)
[8]       If Mid(sInput, iCount, 1) Not Like "[1234567890]" Then ' Zeichen-Prüfung auch mit [0-9]
[9]          Message.Error("Eingabefehler - Zeichen!")
[10]          Return
[11]       Endif
[12]    Next
[13]
[14]   If Len(sInput) <> 4 Then
[15]      Message.Error("Jahreszahl nicht vierstellig!") ' optional
[16]      Return
[17]   Endif
[18]
[19]   If CInt(sInput) < 1600 Or CInt(sInput) > 2100 Then ' Bereichsprüfung [1600..2100]
[20]      Message.Error("Eingabefehler - Bereich!")
[21]      Return
[22]   Endif
[23]
[24]   If IsLeapYear(CInt(sInput)) Then ' Prüfung Schaltjahr und Kommentare
[25]      If CInt(sInput) < Year(Now) Then
[26]         Message.Info("Das Jahr " & sInput & " war ein Schaltjahr.")
[27]      Else
[28]         Message.Info("Das Jahr " & sInput & " wird ein Schaltjahr sein.")
[29]      Endif
[30]   Else
[31]      If CInt(sInput) < Year(Now) Then
[32]         Message.Info("Das Jahr " & sInput & " war kein Schaltjahr.")
[33]      Else
[34]         Message.Info("Das Jahr " & sInput & " wird kein Schaltjahr sein.")
[35]      Endif
[36]   Endif
[37]
[38] End ' txbLeapYear_Activate()```

Comment:

• In line 5, variable sInput is assigned the character string that is in the TextBox when the text input has been completed with the Return key.
• In lines 7 to 12, a character scanner checks whether all characters in the input string are digits (0… 9) after blank characters have been removed.
• If not exactly 4 digits have been entered - lines 14 to 17 - a corresponding message is displayed and you can make corrections (option).
• A range check for the specified time period is performed in lines 19 to 22.
• Since the argument of the function IsLeapYear (iYear AS Integer) (line 24) of the data type must be an integer, the input string is converted to an integer with CInt (..), which is also possible without any problems after the successful pre-checks.
• Dependent on the function value, detailed messages about the outcome of the check are displayed.

The alternative presented here uses a regular expression with which all checks are performed in one step:

```Public Sub txbLeapYear_Activate()
Dim sSubject, sPattern As String

sSubject = Trim(txbLeapYear.Text)
sPattern = "^([1][6789][0-9]{2})|[2][0]([0-9]{2})|2100\$" ' Check pattern as regular expression

If sSubject Not Match sPattern Then
Message.Error("Eingabefehler!")
Return
Endif

Message.Info(Subst\$("Das Jahr &1 ist &2ein Schaltjahr!",sSubject,IIf(IsLeapYear(CInt(sSubject)),"","k")))

End ' txbLeapYear_Activate()```

## 16.6.3.5 Example 5

With the following source code you can completely synchronize the two TextBoxes txbA and txbB during input:

```Public Sub txbA_Change()
txbB.Text = txbA.Text
End ' txbA_Change()```

## 16.6.3.6 Example 6

```Public Sub txbInput_Activate()
Dim sInput As String = txbInput.Text

' Replace the decimal separator of the current (German) locale with the dot
Print sInput
sInput = Replace\$(sInput, Left\$(Format\$(0, ".0")), ".")
Print sInput

End```

## 16.6.3.7 Example 7

There are n TextBoxes on a form, where the content of k selected TextBoxes (k ≤ n) is to be deleted with one call. The solution is to define a unique selling point for the TextBoxes whose content is to be deleted, and the tag property is a good way to do this.

```Public Sub Form_Open()
FMain.Center

txbBox1.Tag = "L"
txbBox2.Tag = "L"
txbBox4.Tag = "L"
txbBox6.Tag = "L"
...
End ' Form_Open()

Private Sub TBMultiClear()
Dim C As Control
Dim tBox As TextBox
For Each C In Me.Controls
If C Is TextBox Then
If C.Tag = "L" Then
' Print C.Name ' Kontrolle
tBox = C
tBox.Clear
Endif
Endif
Next
End ' TBMultiClear()

Public Sub btnTBClear_Click()
TBMultiClear()
End ' btnTBClear_Click()```

## 16.6.3.8 Example 8

The following task must be processed: When activating the Activate-Event of a textbox A (printing on the return key) a certain action is to be triggered and then the cursor is to be placed in the textbox B, which receives the focus. This is done manually with the tab key if the TextBox B in the hierarchy immediately follows the TextBox A. You define the hierarchy of components in the IDE in the hierarchy window. The following source code also implements the above mentioned behavior:

```Public Sub txb_A_KeyPress()
If Key.Code = Key.Enter Or Key.Code = Key.Return Then
' ACTION ...
txb_B.SetFocus()
' Desktop.SendKeys("\t") ' Alternative if the Desktop component is used
Endif
End ' txb_A_KeyPress()```

The use of the alternative has the advantage that the text is marked in the TextBox B, just like when using the tabulator key.

## ﻿16.6.3 Beispiele für den Einsatz einer TextBox – Validierung von Eingaben

Die Absicherung des Einsatzes valider Daten in einem Programm ist Teil des Konzeptes zur Vermeidung von Laufzeitfehlern. Im → Kapitel 16.6.2 Valide Daten finden Sie Hinweise zum Thema und Ansätze, wie Sie Daten aus TextBoxen und ihren unterschiedlichen Spezialisierungen (MaskBox, ValueBox, HistoryBox, InputBox und ButtonBox) validieren können. Für die Eingabe von komplexen Zahlen, Matrizen, Polynomen oder Vektoren dagegen finden Sie Beispiele in den → Kapiteln 29.1 Komplexe Zahlen, 29.3.3 Matrix, 29.3.4 Polynom und 29.3.5 Vector.

Für die Prüfung, ob sich ein Eingabe-String aus einer TextBox in ein valides Datum konvertieren lässt – wenn die Spezialisierungen nicht verwendet werden können – gibt es kein allgemein gültiges Verfahren. Die folgenden Beispiele sollen Ihnen aber zeigen, wie Sie mit unterschiedlichen Strategien einem Programm valide Daten aus einem Eingabe-String zur Verarbeitung bereit stellen.

## 16.6.3.1 Beispiel 1

In einer TextBox werden eine Anzahl A erfasst und in einer weiteren TextBox ein Messwert-Mittelwert (ohne Einheit) als reelle Zahl R. Aus den beiden Eingaben wird im Programm ein Quotient mit vier Dezimalstellen berechnet QM = (A²-Pi) / R und in einer dritten TextBox ausgegeben (read only). Bei jeder Änderung der Eingaben wird der Inhalt der Ausgabe-TextBox gelöscht.

Abbildung 16.6.3.1.1: Berechnung QM

Bevor Sie zügig loslegen, sollten Sie folgende Hinweise in aller Ruhe durchdenken, wobei die Reihenfolge keiner Rangfolge entspricht:

• Die Eingaben in den TextBoxen sind vom Datentyp String. Für die Berechnung des Quotienten benötigen Sie aber Zahlen.
• Bei der Eingabe in die beiden TextBoxen sollten Sie das Eingabe-Alphabet aufgaben-adäquat einschränken.
• Während für die Eingabe der Anzahl als Zeichen nur einzelne Ziffern zulässig sind, kann das Eingabe-Alphabet für die reelle Zahl so notiert werden: {+-,0123456789}.
• Die Festlegung des 2. Alphabets zum Beispiel schützt in keiner Weise vor völlig sinnlosen Eingaben wie '+0,874-,9', was Sie zur Validierung der Daten zwingt. Sie müssen prüfen, ob sich der Eingabe-String aus der TextBox für den Messwert-Mittelwert R sicher in eine reelle Zahl konvertieren lässt.
• Die Konvertierung des in unserem Sprachraum gewohnten Kommas in einen Punkt müssen Sie programm-intern realisieren.
• Die Anzahlen – gespeichert in einer geeignet genannten Variable – müssen Sie in den Datentyp Integer konvertieren, wobei hier festgelegt wurde, die Anzahl 0 nicht als valides Datum zuzulassen, was zu prüfen ist. Auf das Eingabe-Alphabet {0123456789} hat das jedoch keine Auswirkungen, denn sonst wäre zum Beispiel die Anzahl 10 unmöglich.
• Der Messwert R ist in einer Variablen vom Datentyp Float gut aufgehoben. Die Konvertierung in diesen Typ muss dem Rechnung tragen.
• Gambas stellt Ihnen mit CFloat(Value As Variant) eine geeignete Funktion für die Konvertierung zur Verfügung.
• Um bei der Berechnung des Quotienten keinen Fehler 'Division durch Null' zu provozieren, ist die Eingabe einer Null auszufiltern und nach einem Hinweis an den Benutzer eine Korrektur für den fehlerhaften Nenner anzubieten.
• Bevor Sie die Berechnung anschieben, sollten Sie prüfen, ob die Eingabe-TextBoxen nicht leer sind. Für diesen Fall ist der Programmablauf zu unterbrechen, der Benutzer in geeigneter Weise zu informieren und Korrekturmöglichkeiten zu offerieren.

Der Quelltext wird auszugsweise vorgestellt:

```[1] ' Die Eigenschaft txbResult.ReadOnly wird auf TRUE gesetzt
[2] Public Sub btnCalculate_Click()
[3]   Dim sInputN, sInputR, sPatternN, sPatternR As String
[4]   Dim iCount As Integer
[5]   Dim fValue, fCoefficient As Float
[6]
[7]   If Not txbInteger.Text Then ' Prüfung: TextBox leer?
[8]      Message.Error("Eingabefehler 1!") ' Kommentar in einer MessageBox
[9]      txbInteger.SetFocus ' Fokus auf die TextBox txbInteger setzen
[10]      Return ' Prozedur verlassen
[11]   Endif
[12]   If Not txbReal.Text Then ' Prüfung: TextBox leer?
[13]      Message.Error("Eingabefehler 2!")
[14]      txbInteger.SetFocus
[15]      Return
[16]   Endif
[17]
[18]  '----------------------------------------------------------------------------
[19]
[20]   sInputN = Trim(txbInteger.Text) ' Leerzeichen am Anfang und am Ende entfernen
[21]   Try iCount = CInteger(sInputN) ' Versuch: Konvertierung String → Ganze Zahl
[22]   If Error Then ' Fehlerbehandlung
[23]      Message("Fehler 1")
[24]      txbInteger.SetFocus
[25]      Return
[26]   Endif
[27]
[28] ' Anzahl Null herausfiltern
[29]   If iCount = 0 Then
[30]      Message.Info("Die Anzahl muss größer als Null sein!")
[31]      txbReal.SetFocus
[32]      Return
[33]   Endif
[34]
[35] '----------------------------------------------------------------------------
[36]
[37]   sInputR = Trim(txbReal.Text) ' Leerzeichen am Anfang und am Ende entfernen
[38] ' Dezimalseparator der aktuellen Locale durch den Punkt ersetzen
[39]   sInputR = Replace\$(sInputR, Left\$(Format\$(0, ".0")), ".")
[40]
[41]   Try fValue = CFloat(sInputR) ' Versuch: Konvertierung String → Reelle Zahl
[42]   If Error Then
[43]      Message("Fehler 2")
[44]      txbReal.SetFocus
[45]      Return
[46]   Endif
[47]
[48]   If fValue = 0 Then ' Null herausfiltern
[49]      Message.Info("Die (reelle) Zahl 0 ist nicht zulässig!")
[50]      txbReal.SetFocus
[51]      Return
[52]   Endif
[53]
[54] '----------------------------------------------------------------------------
[55]
[56]   fCoefficient = Round((iCount * iCount - Pi()) / fValue, -4) ' Berechnung Quotient
[57]   txbResult.Text = Str(fCoefficient) ' Anzeige Quotient (Koeffizient QM)
[58]
[59] End ' btnCalculate_Click()
[60]
[61] '----------------------------------------------------------------------------
[62]
[63] Public Sub txbInteger_KeyPress() ' Umsetzung Eingabe-Alphabet
[64]   CheckInput("0123456789")
[65] End ' txbDigits_KeyPress()
[66]
[67] Public Sub txbReal_KeyPress() ' Umsetzung Eingabe-Alphabet
[68]   CheckInput("+-,0123456789")
[69] End ' txbDigits_KeyPress()
[70]
[71] Public Sub CheckInput(sAllowed As String) ' Idee Charles Guerin
[72]   Select Case Key.Code
[73]     Case Key.Left, Key.Right, Key.BackSpace, Key.Delete, Key.End, Key.Home, Key.Enter, Key.Return
[74]       Return
[75]     Default
[76]       If Key.Text And If InStr(sAllowed, Key.Text) Then
[77]          Return
[78]       Endif
[79]   End Select
[80]   Stop Event
[81] End ' CheckInput(sAllowed As String)
[82]
[83] ' Public Sub txbInteger_Change()
[84] '    txbResult.Clear
[85] ' End
[86] ' Public Sub txbReal_Change()
[87] '   txbResult.Clear
[88] ' End
[89]
[90] Public Sub TBIR_Change()
[91]   txbResult.Clear
[92] End ' TBIR_Change()```

Kommentar:

• In den Zeilen 83 bis 88 wird die Forderung realisiert, dass bei jeder Änderung der Text-Eigenschaft in den beiden TextBoxen txbInteger und txbReal der Text in der Ausgabe-TextBox gelöscht wird. Für zwei TextBoxen ist der Aufwand noch vertretbar – aber bei 5 oder mehr? Dann lohnt es sich, bei allen beteiligten TextBoxen die virtuelle Eigenschaft Group in der IDE jeweils auf den gleichen Wert – hier TBIR – zu setzen und für alle einen gemeinsamen Event-Handler zu definieren. Die Implementation für die beiden TextBoxen txbInteger und txbReal sehen Sie in den Zeilen 83 bis 85.
• Die Hinweistexte und Fehlermeldungen können Sie noch spezifisch formulieren.
• Eine Vereinfachung ergäbe sich in den Zeilen 20 bis 33 durch den Einsatz eines regulären Ausdrucks, da durch die Musterprüfung Null als Muster nicht akzeptiert wird und nur korrekte Anzahlen eingegeben werden können:
```[1]   sInputN = Trim(txbInteger.Text)
[2]   sPatternN = "^[1-9][0-9]*\$" ' Alternative mit Null: "^[0]{1}\$|^[1-9][0-9]*\$"
[3]   If sInputN Not Match sPatternN Then
[4]      Message.Error("Eingabefehler 3!")
[5]      txbInteger.SetFocus
[6]      Return
[7]   Endif
[8]   iCount = CInteger(sInputN)```

## 16.6.3.2 Beispiel 2

Damit nur bestimmte Zeichen – hier sind es die Ziffern 0 bis 9 – in einer TextBox akzeptiert werden, wird in der Dokumentation der folgende Beispiel-Quelltext offeriert:

```' My text box only accepts digits

Public Sub MyTextBox_KeyPress()
If Instr("0123456789", Key.Text) = 0 Then
Stop event
Endif
End```

Hinweise:

• In der Gambas-Dokumentation wird beschrieben, dass man mit dem Stop Event dem Interpreter mitteilt, dass das aktuelle Event 'gecancelt' werden soll.
• Manche Ereignisse unterstützen die Aktion, abgebrochen zu werden. Das KeyPress-Ereignis gehört dazu. Wenn es abgebrochen wird, dann wird der Tastendruck nicht weiter verarbeitet – die Eingabe wird verworfen. Dabei ist es egal, wo Stop Event innerhalb des Event-Handlers steht. Es ist aber zwingend erforderlich, um das Ereignis abzubrechen.

Funktioniert – doch leider können Sie die Ziffernfolge in keiner Weise korrigieren, was als Mangel angesehen werden kann. Deshalb wird im folgenden Abschnitt eine verbesserte Lösung vorgestellt, bei der Sie den Cursor in der TextBox bewegen und mit der BackSpace-Taste einzelne Ziffern löschen können:

```Public Sub txbDigits_KeyPress()
' Nur die Ziffern 0..9 als zulässige Ziffern zulassen
If (Key.Text Not Like "[0-9]") And (Key.Code <> Key.BackSpace) And (Key.Code <> Key.Left) \\
And (Key.Code <> Key.Right) Then
Stop Event
Endif ' Key.Text Not Like "[0-9]" ?
End ' txbDigits_KeyPress() ```

Einen Nachteil werden Sie sicher noch entdecken – das Eingabe-Alphabet ist nicht variabel, wenn Sie beispielsweise an den Fall denken, dass alle Ziffern 0-9 zulässig sind sowie zusätzlich die beiden Vorzeichen (+-) und die Zeichen Punkt, Komma und Sternchen wie auch der Buchstabe x. Die folgende Lösung behebt den Nachteil sicher:

```Public Sub CheckInput(sAllowed As String) ' Idee Charles Guerin
Select Case Key.Code
Case Key.Left, Key.Right, Key.BackSpace, Key.Delete, Key.End, Key.Home, Key.Enter, Key.Return
Return
Default
If Key.Text And If InStr(sAllowed, Key.Text) Then
Return
Endif
End Select
Stop Event

End ' CheckInput(sAllowed As String)

Public Sub txbDigits_KeyPress()
CheckInput("+-,.*0123456789x")
End ' txbDigits_KeyPress()```

Die Prüfung, ob ein eingegebenes Zeichen zum Eingabe-Alphabet gehört oder nicht, arbeitet fehlerfrei. Denken Sie aber daran, den Eingabe-String anschließend noch einer Validitätsprüfung zu unterziehen, wenn zum Beispiel der Eingabe-String als Term in einer linearen Gleichung aufgefasst werden soll. Der String -5,88*x+7,1+*23 enthält nur Zeichen aus dem Eingabe-Alphabet und ist trotzdem für die Verarbeitung nicht geeignet, da er einen Syntax-Fehler im Sinne der Term-Vorgabe enthält.

## 16.6.3.3 Beispiel 3

Dieses Beispiel setzt nicht auf Prüfung sondern auf Prävention, weil dem Benutzer ein Hinweis-Text in der TextBox angezeigt wird, um Fehleingaben zu minimieren. Genutzt wird eine spezielle von Tobias Boege entwickelte TextBox – die Explain-TextBox. Die Explain-TextBox ist eine TextBox, die es erlaubt, einen erklärenden Vorgabe-Text (Explanation) in der Schriftfarbe grau anzuzeigen, wenn die TextBox leer ist und nicht den Fokus hat. Damit könnten Sie u.U. auf erklärende Beschriftungen vor den TextBoxen verzichten:

Abbildung 16.6.3.3.1: Explain-TextBox

Die Klasse ExplainTextbox wird Ihnen in einem Projekt im Download-Bereich zur Verfügung gestellt.

## 16.6.3.4 Beispiel 4

Es soll geprüft werden, ob es sich bei der Eingabe einer Jahreszahl im Intervall von 1600 bis 2100 in eine TextBox um ein Schaltjahr handelte oder handeln wird.

Ein astronomisches Jahr ist die Dauer der Revolution der Erde um den Zentralkörper Sonne – unseren Stern. In unseren Zeiteinheiten sind das sekundengenau 365 Tage, 5 Stunden, 48 Minuten und 47 Sekunden. Ein normales Kalender-Jahr – aber was ist schon normal – hat eine Länge von 365 Tagen. Nach 4 Jahren werden die 5 Stunden, 48 Minuten und 47 Sekunden, was ja in etwa einem Viertel-Tag entspricht, zu einem Tag, dem 29. Februar, zusammengefasst und damit hat ein Schaltjahr 366 Tage. Ein Schaltjahr gibt es alle 4 Jahre, jedoch alle 100 Jahre nicht, dann aber alle 400 Jahre doch, um die Abweichungen der eingefügten Viertel-Tage zu 6 Stunden auszugleichen. Ich bin begeistert!

Als vorbeugende Maßnahme wird die Anzahl der Zeichen auf maximal 4 Zeichen begrenzt:

```[1] Public Sub Form_Open()
[2]   txbLeapYear.MaxLength = 4
[3]   ...
[4] End ' Form_Open()```

Die Funktion IsLeapYear(..) setzt die o.a. Regel für Schaltjahre um und gibt den Funktionswert True zurück, wenn das als Argument eingesetzte Jahr ein Schaltjahr war oder ist:

```[1] Public Function IsLeapYear(iYear As Integer) As Boolean
[2]
[3]   If (iYear Mod 4) = 0 And (iYear Mod 100) <> 0 Or ((iYear Mod 400) = 0) Then
[4]      Return True
[5]   Else
[6]      Return False
[7]   Endif
[8]
[9] End ' Function IsLeapYear(..)```

Im folgenden Quelltext-Abschnitt – dem ein Kommentar folgt – sehen Sie diverse (Vor-)Prüfungen:

```[1] Public Sub txbLeapYear_Activate()
[2]   Dim iCount As Integer
[3]   Dim sInput As String
[4]
[5]   sInput = Trim(txbLeapYear.Text) ' Entfernung von Leerzeichen am Anfang und am Ende des Strings
[6]
[7]   For iCount = 1 To Len(sInput)
[8]       If Mid(sInput, iCount, 1) Not Like "[1234567890]" Then ' Zeichen-Prüfung auch mit [0-9]
[9]          Message.Error("Eingabefehler - Zeichen!")
[10]          Return
[11]       Endif
[12]    Next
[13]
[14]   If Len(sInput) <> 4 Then
[15]      Message.Error("Jahreszahl nicht vierstellig!") ' optional
[16]      Return
[17]   Endif
[18]
[19]   If CInt(sInput) < 1600 Or CInt(sInput) > 2100 Then ' Bereichsprüfung [1600..2100]
[20]      Message.Error("Eingabefehler - Bereich!")
[21]      Return
[22]   Endif
[23]
[24]   If IsLeapYear(CInt(sInput)) Then ' Prüfung Schaltjahr und Kommentare
[25]      If CInt(sInput) < Year(Now) Then
[26]         Message.Info("Das Jahr " & sInput & " war ein Schaltjahr.")
[27]      Else
[28]         Message.Info("Das Jahr " & sInput & " wird ein Schaltjahr sein.")
[29]      Endif
[30]   Else
[31]      If CInt(sInput) < Year(Now) Then
[32]         Message.Info("Das Jahr " & sInput & " war kein Schaltjahr.")
[33]      Else
[34]         Message.Info("Das Jahr " & sInput & " wird kein Schaltjahr sein.")
[35]      Endif
[36]   Endif
[37]
[38] End ' txbLeapYear_Activate()```

Kommentar:

• In der Zeile 5 wird der Variablen sInput die Zeichenkette zugewiesen, die in der TextBox steht, wenn die Texteingabe mit der Return-Taste abgeschlossen wurde.
• In den Zeilen 7 bis 12 erfolgt in einem Zeichen-Scanner die Prüfung, ob alle Zeichen im Eingabe-String Ziffern (0..9) sind, nachdem Leerzeichen entfernt worden sind.
• Wurden nicht genau 4 Ziffern eingegeben – Zeilen 14 bis 17 – so erfolgt eine entsprechende Mitteilung und Sie können Korrekturen vornehmen (Option).
• Eine Bereichsprüfung auf den vorgegebenen Zeitraum wird in den Zeilen 19 bis 22 vorgenommen.
• Da das Argument der Funktion IsLeapYear(iYear AS Integer) (Zeile 24) vom Daten-Typ eine ganze Zahl sein muss, wird der Eingabe-String mit CInt(..) in eine ganze Zahl konvertiert, was nach den erfolgreichen Vorprüfungen auch problemlos möglich ist.
• ListenpunktJe nach Funktionswert werden detaillierte Mitteilungen zum Ausgang der Prüfung angezeigt.

Die hier vorgestellte Alternative nutzt einen regulären Ausdruck, mit dem sämtliche Prüfungen in einem Schritt erfolgen:

```Public Sub txbLeapYear_Activate()
Dim sSubject, sPattern As String

sSubject = Trim(txbLeapYear.Text)
sPattern = "^([1][6789][0-9]{2})|[2][0]([0-9]{2})|2100\$" ' Prüf-Muster als regulärer Ausdruck

If sSubject Not Match sPattern Then
Message.Error("Eingabefehler!")
Return
Endif

Message.Info(Subst\$("Das Jahr &1 ist &2ein Schaltjahr!",sSubject,IIf(IsLeapYear(CInt(sSubject)),"","k")))

End ' txbLeapYear_Activate()```

## 16.6.3.5 Beispiel 5

Mit dem folgenden Quelltext können Sie die beiden TextBoxen txbA und txbB bei der Eingabe komplett synchronisieren:

```Public Sub txbA_Change()
txbB.Text = txbA.Text
End ' txbA_Change()```

## 16.6.3.6 Beispiel 6

In diesem Activate-Ereignis ersetzen Sie ein Komma – so wie Sie es zum Beispiel bei der Eingabe von Dezimalzahlen gewohnt sind – intern durch einen Punkt, so dass nach einer Validitätsprüfung des Eingabe-Strings dem Programm eine Dezimalzahl zur Verarbeitung übergeben werden kann. Probieren Sie es aus:

```Public Sub txbInput_Activate()
Dim sInput As String = txbInput.Text

' Dezimalseparator der aktuellen Locale durch den Punkt ersetzen
Print sInput
sInput = Replace\$(sInput, Left\$(Format\$(0, ".0")), ".")
Print sInput

End ' txbInput_Activate()```

## 16.6.3.7 Beispiel 7

Auf einem Formular existieren n TextBoxen, bei denen von k ausgewählten TextBoxen (k ≤ n) der Inhalt mit einem Aufruf gelöscht werden soll. Die Lösungsidee besteht darin, für die TextBoxen, deren Inhalt zu löschen ist, ein Alleinstellungsmerkmal zu definieren und dafür bietet sich zum Beispiel die Tag-Eigenschaft an.

```Public Sub Form_Open()
FMain.Center

txbBox1.Tag = "L"
txbBox2.Tag = "L"
txbBox4.Tag = "L"
txbBox6.Tag = "L"
...
End ' Form_Open()

Private Sub TBMultiClear()
Dim C As Control
Dim tBox As TextBox
For Each C In Me.Controls
If C Is TextBox Then
If C.Tag = "L" Then
' Print C.Name ' Kontrolle
tBox = C
tBox.Clear
Endif
Endif
Next
End ' TBMultiClear()

Public Sub btnTBClear_Click()
TBMultiClear()
End ' btnTBClear_Click()```

## 16.6.3.8 Beispiel 8

Folgende Aufgabe ist zu bearbeiten: Bei der Auslösung des Activate-Events einer Textbox A (Druck auf die Return-Taste) soll eine bestimmte Aktion ausgelöst werden und danach der Cursor in die TextBox B gesetzt werden, die den Fokus erhält. Von Hand geht das mit der Tabulatortaste, wenn die TextBox B in der Hierarchie unmittelbar der TextBox A folgt. Die Hierarchie von Komponenten legen Sie in der IDE im Hierarchie-Fenster fest. Der folgende Quelltext realisiert das oben genannte Verhalten ebenso:

```Public Sub txb_A_KeyPress()
If Key.Code = Key.Enter Or Key.Code = Key.Return Then
' AKTION ...
txb_B.SetFocus()
' Desktop.SendKeys("\t") ' Alternative, wenn die Komponente Desktop verwendet wird
Endif
End ' txb_A_KeyPress()```

Die Verwendung der Alternative hat den Vorteil, dass der Text in der TextBox B markiert wird, wie das auch bei der Verwendung der Tabulatortaste erfolgt.

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k16/k16.6/k16.6.3/start.txt · Last modified: 02.07.2018 (external edit)