C++ WFormen, "Punkt" Operator fehler

fox40phil

Vice Admiral
Registriert
Okt. 2008
Beiträge
6.244
Hallo Programmierer Kollegen,

mein Projekt, das ich seit März habe weißt immer noch kleine Macken auf^^ und ich habe einige Ergänzungen gemacht.

Eine davon ist, das man in einer TextBox mithilfe des "Punkt (.)" Operators eine Dezimalzahl eingeben kann. Das Problem dabei ist aber, dass er bei der Umwandlung des Strings (Eingabe) zu Double den Wert mal 10 bzw. 100 oder mehr nimmt, je nach dem wieviele "Komma"stellen ich eingebe :freak:

z.B.:

Eingabe: 5.5
Umwandlung zu double: 55

Die 55 habe ich dann immer durch 10 geteilt, da ist mir noch nicht aufgefallen was bei mehr als einer Nachkommastelle passiert <.>

Eingabe: 5.5
Umwandlung zu double: 555


Ich hatte jetzt festgelegt, dass jeder Wert in der TextBox mit einem "Punkt" angegeben werden muss, da sonst die ganze Rechnung nicht mehr geht -.-" d.h. z.B. "10.0".
Damit auch solche Werte durch 10 geteilt werden können.
Nun habe ich ja das Problem, dass ich es bei 2 Kommastellen theoretisch durch 100 teilen müsste.
Kann man dazu eine Bedingung schreiben? Wenn ja wie?^^
Mir fällt nichts ein :(


ich hoffe ich hab es einigermaßen verständlich geschrieben ;)

Grüße & schönes Wochenende

Phil
 
Es wäre ganz hilfreich, wenn du mal den Code posten würdest, der für die Umwandlung der Benutzereingabe in eine Zahl verantwortlich ist. Dann können wir dir vielleicht sagen, wie es besser geht :)
 
Probier mal folgendes:

Ersetze in der TextBox den '.' durch ein ',' (Komma). Dann sollte die Konvertierung eigentlich ohne Probleme klappen.


Gruß
 
Jo, Double.Parse() - und damit auch System.Convert.ToDouble() - nehmen als Dezimaltrenner das landesspezifische Zeichen, also in Deutschland das Komma, statt des Punkts.
 
okay alles klar. Hinzu kommt, dass ich eine Abfrage habe, die nicht jedes Zeichen erlaubt! Kurz: Nur Zahlen >0 und bisher eben den Punkt, ich habe nun die Eigenschaft für den Punkt durch "Decimal" für das Komma ersetzt. Nun kann ich dazu aber nur das Kommata vom Numpad benutzten <.>....


Code:
private: System::Void tB_Isc_KeyDown(System::Object^  /*sender*/, System::Windows::Forms::KeyEventArgs^  e) 
{

	 // Initialize the flag to false.
	bNonNumberEntered_Isc = false;

	// Determine whether the keystroke is a number from the top of the keyboard.
	 if ( e->KeyCode < Keys::D0 || e->KeyCode > Keys::D9 )
	 {
		// Determine whether the keystroke is a number from the keypad.
		if ( e->KeyCode < Keys::NumPad0 || e->KeyCode > Keys::NumPad9 ) 
		{
			// Determine whether the keystroke is a backspace.
			if ( e->KeyCode != Keys::Back &&  e->KeyCode != Keys::[B]Decimal [/B])  // OemPeriod = PUNKT // Decimal = Komma
			{
				// A non-numerical keystroke was pressed.
				// Set the flag to true and evaluate in KeyPress event.
				bNonNumberEntered_Isc = true;
			 }
		}
	}

	// If shift key was pressed, it's not a number.
	if ( Control::ModifierKeys == Keys::Shift)
	 {
		 bNonNumberEntered_Isc = true;
		}

	} // KeyDown Event ENDE

diese Funktion wie sie aufgebaut ist gibt es bei der MSDN Hilfe.
Die dazu gehörige Liste mit den ganzen Keys: "klick"

Dort gibt es noch eines das nennt sich Oemcomma, aber das funktioniert nicht.
 
Ich nehme an, du kannst auch nur die Zahlentasten vom Numpad benutzen :)

Versuch mal, statt des KeyDown-Events das KeyPress-Event abzufragen. Dann bekommst du nämlich ein Argument der Klasse KeyPressEventArgs, das eine Eigenschaft KeyChar hat. Da steht das Zeichen drin, das der Tastendruck ergibt, egal von welcher Taste es kommt. Im einfachsten Fall reicht also schon die Bedingung

Code:
(e->KeyChar == ",")

damit du beide Kommatasten verwenden kannst.
 
wie schon oben steht ist das dezimalsystem Kulturabhängig, aber wenn du aufn Deutschen Win schreibst, so sehe ich da ehe keine Probleme. Zweitens...e->KeyChar == ',' nicht zufällig mit einfachen hochkomme? Char ist kein String. Wenn der Compiler dass zulassen wird kann es ja sein dass du immer FALSE zurückbekommst, da man in erste Linie die Datentypen vergleicht und nicht den Wert.

und dein problem ist... Der wert Double darfst du nicht mit KOMA Parsen... denn in deinen Parser "." als 1000er Trennzeichen gilt! Sobald du den Parser mit kulturinfo auf US änderst wirst du auch den richtigen wert zurückbekommen. Benutze also "," statt "." in deinen Formular als Trennzeichen.
 
Zuletzt bearbeitet:
Das Event "KeyPressEventArgs" hab ich auch schon, da laut MSDN Hilfe die "KeyDown" & "KeyPress" Funktion zur Abfrage der Eingegebenen Tasten gehört.

Nun weiß ich nicht genau wie ich das mit dem KeyChar implementieren soll :rolleyes:.
Da in dem Event "KeyDown" eine boolsche Variable wahr oder falsch wird und das im "KeyPress" Event geprüft wird:

Code:
[COLOR="YellowGreen"]// This event occurs after the KeyDown event and can be used to prevent
// characters from entering the control.[/COLOR]
[COLOR="Blue"]private[/COLOR]: System::Void tB_Isc_KeyPress(System::Object^  /*sender*/, System::Windows::Forms::KeyPressEventArgs^  e) 
		 {

			[B] if ( e->KeyChar == ',')
			 {
					bNonNumberEntered_Isc = true;
			 }
			 else
			 {
				 bNonNumberEntered_Isc = false;

			 }[/B]



			 [COLOR="YellowGreen"]// Check for the flag being set in the KeyDown event.[/COLOR]
			 [COLOR="Blue"]if [/COLOR]( bNonNumberEntered_Isc == [COLOR="Blue"]true[/COLOR])
			 {
				[COLOR="YellowGreen"] // Stop the character from being entered into the control since it is non-numerical.[/COLOR]
				 e->Handled = [COLOR="Blue"]true[/COLOR];
				

			 }

		 } [COLOR="YellowGreen"]// KeyPress Event ENDE
//===================================================================[/COLOR]

Soll ich da jetzt einfach noch mal eine IF-Bedingung rein machen wie in dem "KeyDown" Event?

PS: ich kann Numpad Zahlen sowohl die anderen Zahlen eingeben ;) "D0-D9"

€dit: Leider geht das so nicht, ich kann kein "Komma" eingeben.
 
Zuletzt bearbeitet:
Kann es sein, daß du in den Fällen der if-Abfrage true und false vertauscht hast? :)
 
Mir scheint, du hast jetzt den Code, der abfragt, ob ein gültiges Zeichen eingegeben wurde, auf zwei Methoden verteilt - keyDown und keyPress. Nimm doch den ganzen Kram aus keyDown raus und tu ihn in keyPress rein. Dann hast du alles an einem Platz.

Ich versuch's mal. Ohne Garantie, weil ich diesen speziellen C++-Dialekt noch nie benutzt habe:

Code:
// This event occurs after the KeyDown event and can be used to prevent
// characters from entering the control.
private: System::Void tB_Isc_KeyPress(System::Object^  /*sender*/, System::Windows::Forms::KeyPressEventArgs^  e) 
		 {
			 bool hasComma = false;
			 if (Char::IsDigit(e->KeyChar))
			 {
					bNonNumberEntered_Isc = true;
			 }
			 else if (e->KeyChar == ',')
			 {
					bNonNumberEntered_Isc = hasComma;
					hasComma = true;
			 }
			 else
			 {
				 bNonNumberEntered_Isc = false;

			 }



			 // Check for the flag being set in the KeyDown event.
			 if ( bNonNumberEntered_Isc == true)
			 {
				 // Stop the character from being entered into the control since it is non-numerical.
				 e->Handled = true;
				

			 }

		 } // KeyPress Event ENDE
//===================================================================
 
also, das hab ich jetzt mal gemacht. In der Press Methode gibt es leider kein "e->KeyCode" sondern das hab ich dann mit "e->KeyChar" lösen. Leider kommt jetzt bei jeder IF Bedingung ein Fehler:
error C3063: <-Operator: Alle Operanden müssen den gleichen Enumerationstyp aufweisen.




Code:
private: System::Void tB_Isc_KeyPress(System::Object^  /*sender*/, System::Windows::Forms::KeyPressEventArgs^  e) 
		 {
			 
			// Initialize the flag to false.
			 bNonNumberEntered_Isc = false;

			 // Determine whether the keystroke is a number from the top of the keyboard.
[COLOR="Red"]error C3063[/COLOR]			 if ( e->KeyChar < Keys::D0 || e->KeyChar > Keys::D9 )
			 {
				 // Determine whether the keystroke is a number from the keypad.
[COLOR="Red"]error C3063[/COLOR]				 if ( e->KeyChar < Keys::NumPad0 || e->KeyChar > Keys::NumPad9 ) 
				 {
					 // Determine whether the keystroke is a backspace.
[COLOR="Red"]error C3063[/COLOR]					 if ( e->KeyChar != Keys::Back && e->KeyChar != ',') // &&  e->KeyCode != Keys::Decimal )  // OemPeriod = PUNKT // 
					 {
						 // A non-numerical keystroke was pressed.
						 // Set the flag to true and evaluate in KeyPress event.
						 bNonNumberEntered_Isc = true;
					 }
				 }
			 }

			
			 // If shift key was pressed, it's not a number.
			 if ( Control::ModifierKeys == Keys::Shift)
			 {
				 bNonNumberEntered_Isc = true;
			 }

			
			 // Check for the flag being set in the KeyDown event.
			 if ( bNonNumberEntered_Isc == true)
			 {
				 // Stop the character from being entered into the control since it is non-numerical.
				 e->Handled = true;
				

			 }

		 } // KeyPress Event ENDE


:confused_alt:

€dit: Ich könnte "if ( e->KeyChar <= '0' || e->KeyChar >= '9' )" schreiben, aber was schreib ich dann für "return"/"delete" ?

€dit2
: Also die Eingabe & Berechnung funktioniert mit Komma. Aber ich kann die Zahl nicht löschen^^ wie gesagt das mit dem "return". Ich hab jetzt "back" (if ( e->KeyChar != 'back' && e->KeyChar != ','))rein geschrieben, es kommt kein Fehler aber es geht uach nicht.

Die folgenden Tasten können abgerufen und festgelegt werden:

a-z, A-Z.

STRG.

Satzzeichen.

Numerische Tasten im oberen Bereich der Tastatur und auf der Zehnertastatur.

EINGABETASTE.

Die folgenden Tasten können nicht abgerufen oder festgelegt werden:

Die TAB-TASTE.

EINFG und LÖSCHEN.

POS1.

ENDE.

BILD-AUF und BILD-AB.

F1-F2.

ALT.

Pfeiltasten.
Quelle: MSDN - KeyChar
 
Zuletzt bearbeitet:
Backspace hab ich vergessen, das müßte mit e->KeyChar == '\b' gehen.
 
Nun blockiere ich eine Eingabe des Kommas, wenn ich dann aber noch mal drauf drücke erscheint es :freak: und es gibt ne Exception =/


Hier mal die Komplette "Leave" Methode, mit der Eingabe Variable etc:

Code:
private: System::Void tB_Isc_Leave(System::Object^  sender, System::EventArgs^  e) 
 {
	[COLOR="YellowGreen"]// Fehlermeldung reset[/COLOR]
	label_Fehlermeldung->Text ="";
	[COLOR="YellowGreen"]//----------------------------[/COLOR]
	[B]bKommaUeberpruefung [/B]= false;

	try
	{
					 
		int iTemp;
		Isc_eingabe= tB_Isc->Text;

		if(Isc_eingabe == String::Empty)
		{
			Isc_eingabe= "0";
		}
			
		iStop= 0;
		iTemp = Isc_eingabe->Length;
				
		
		if (iTemp <= 5)
		{
                        [COLOR="YellowGreen"]// Umwandlung der Eingabe in "float"[/COLOR]
			WrPhil->fKurzschlussstrom_inA= (float)System::Convert::ToDouble(Isc_eingabe);


		}
		else
		{
			[COLOR="YellowGreen"]// Fehlermeldung
			// -Englisch-[/COLOR]
			label_Fehlermeldung->Text ="Error: Don't enter values longer than five signs! Entry = 0";
			Isc_eingabe = "0,0";
			WrPhil->fKurzschlussstrom_inA= (float) System::Convert::ToDouble(Isc_eingabe);
			tB_Isc->Text = Isc_eingabe;
				
		}
		WrPhil->vergleiche_Isc_pro_Eingang();
	
	} [COLOR="YellowGreen"]// Try ENDE
[/COLOR]
	catch(char * str )
	{
	}

} [COLOR="YellowGreen"]// ENDE tB_Isc_Leave (..)
//----------------------------------------------------------[/COLOR]

Code:
public:
		 bool [B]bNonNumberEntered_Isc[/B];
		 bool [B]bKommaUeberpruefung[/B];
		 String^ [B]Isc_eingabe[/B];
		 int [B]iStop[/B]; [COLOR="YellowGreen"]// Damit nur ein Komma eingegeben werden kann[/COLOR]


Code:
[COLOR="YellowGreen"]//----------------------------------------------------------
// This event occurs after the KeyDown event and can be used to prevent
// characters from entering the control.[/COLOR]
private: System::Void tB_Isc_KeyPress(System::Object^  /*sender*/, System::Windows::Forms::KeyPressEventArgs^  e) 
{ 
	[COLOR="YellowGreen"]// Initialize the flag to false.[/COLOR]
	bNonNumberEntered_Isc = false;

	[COLOR="YellowGreen"]// Determine whether the keystroke is a number from the top of the keyboard.[/COLOR]
		 if ( e->KeyChar < '0' || e->KeyChar > '9' )
		{
			 [COLOR="YellowGreen"]// Determine whether the keystroke is a backspace.[/COLOR]
			if ( e->KeyChar != '\b' )
			{
				 bKommaUeberpruefung = Isc_eingabe->Contains("[B],[/B]");

				 if ( bKommaUeberpruefung == true && iStop != 1 )
				 {
							
					iStop = 1;
					[COLOR="YellowGreen"]// A non-numerical keystroke was pressed.
					// Set the flag to true and evaluate in KeyPress event.[/COLOR]
					bNonNumberEntered_Isc = true;
								
				}
			}
}

[INDENT]if ( Control::ModifierKeys == Keys::Shift)
{
	bNonNumberEntered_Isc = true;
}
		
if ( bNonNumberEntered_Isc == true)
{
	[COLOR="YellowGreen"]// Stop the character from being entered into the control since it is non-numerical.[/COLOR]
	e->Handled = true;
}[/INDENT]

} // KeyPress Event ENDE
[COLOR="YellowGreen"]//===================================================================[/COLOR]
 
Zuletzt bearbeitet:
Wofür brauchst du denn die iStop-Variable? Dadurch, daß du abfragst, ob Isc_Eingabe->Contains(","), sollte doch schon sichergestellt sein, daß nur ein Komma eingegeben werden kann.

Außerdem mußt du vorher noch abfragen, ob tatsächlich ein Komma eingegeben wurde und nicht irgendein anderes Nicht-Ziffer/Backspace-Zeichen.

Wenn du dann noch Exceptions bekommst, poste mal die genaue Fehlermeldung.
 
soo^^ folgendes. Ich soll nun doch mit nem Punkt ("."), bei der Eingabe, arbeiten. Naja das ändert am Problem erst mal nichts.

Aber ich hab es jetzt so gelöst!

Wie hier in dem Link: MSDN - Convert.ToDouble-Methode (String) (C++, natürlich).
Kurz: ich habe es jetzt doch mit der Try & Catch Variante geschafft und zwar...gibt es wie man dort (Link) nach schauen kann verschiedene Exception-Funktionen? die man Abfragen kann.

Bei mir sieht das ganze jetzt so aus:
Das ist jetzt ein Ausschnitt aus "private: System::Void tB_Isc_Leave(System::Object^ sender, System::EventArgs^ e) "
Code:
	[COLOR="YellowGreen"]// Create a NumberFormatInfo object and set several of its
	// properties that apply to numbers.[/COLOR]
	NumberFormatInfo^ provider = [COLOR="Blue"]gcnew [/COLOR]NumberFormatInfo;
	provider->NumberDecimalSeparator = [COLOR="DarkRed"]"."[/COLOR];
	provider->NumberGroupSeparator = [COLOR="DarkRed"]","[/COLOR];

	[COLOR="Blue"]try[/COLOR]
	{
		Isc_eingabe= tB_Isc->Text;

		if(Isc_eingabe == String::Empty)
		{
			Isc_eingabe= [COLOR="DarkRed"]"0"[/COLOR];
		}
			
		[COLOR="Blue"]try [/COLOR][COLOR="YellowGreen"]// Es wird probiert die Eingabe zu convertieren![/COLOR]
		{
			WrPhil->fKurzschlussstrom_inA= ([COLOR="Blue"]float[/COLOR]) System::Convert::ToDouble(Isc_eingabe, provider);

		}
		[COLOR="YellowGreen"]// Sollte das nicht klappen kommen die "catches" zum Einsatz[/COLOR]
		[COLOR="Blue"]catch[/COLOR]([B]System::OverflowException^[/B])
		{
			[COLOR="YellowGreen"]// Fehlermeldung
			// -Englisch-[/COLOR]
			label_Fehlermeldung->Text =[COLOR="DarkRed"]"Error: Conversion from String-to-double overflowed."[/COLOR];
			Isc_eingabe = [COLOR="DarkRed"]"0.0"[/COLOR];
			WrPhil->fKurzschlussstrom_inA= ([COLOR="Blue"]float[/COLOR]) System::Convert::ToDouble(Isc_eingabe);
			tB_Isc->Text = Isc_eingabe;
				
		}
		[COLOR="Blue"]catch [/COLOR]( [B]System::FormatException^ [/B]) 
		{
			[COLOR="YellowGreen"]// Fehlermeldung
			// -Englisch-[/COLOR]
			label_Fehlermeldung->Text =[COLOR="DarkRed"]"Error: The String was not formatted as a double."[/COLOR];
			Isc_eingabe = [COLOR="DarkRed"]"0.0"[/COLOR];
			WrPhil->fKurzschlussstrom_inA= ([COLOR="Blue"]float[/COLOR]) System::Convert::ToDouble(Isc_eingabe);
			tB_Isc->Text = Isc_eingabe;

		}
		[COLOR="Blue"]catch [/COLOR]( [B]System::ArgumentException^[/B] ) 
		{
			[COLOR="YellowGreen"]// Fehlermeldung
			// -Englisch-[/COLOR]
			label_Fehlermeldung->Text =[COLOR="DarkRed"]"Error: The String pointed to null."[/COLOR];
			Isc_eingabe = [COLOR="DarkRed"]"0.0"[/COLOR];
			WrPhil->fKurzschlussstrom_inA= ([COLOR="Blue"]float[/COLOR]) System::Convert::ToDouble(Isc_eingabe);
			tB_Isc->Text = Isc_eingabe;
		}

		WrPhil->vergleiche_Isc_pro_Eingang(); [COLOR="YellowGreen"]// Funktionsaufruf zum Berechnen[/COLOR]
	
	}
	[COLOR="Blue"]catch[/COLOR](char * str )
	{
	}

mache es für euch immer noch farblich :) ;) damit man es besser lesen kann^^.

Also,wenn ich jetzt eine Zahl wie "5.5" eingebe rechnet er weiter, da er diese konvertieren kann! Wenn ich jetzt "5.5." eingebe trifft das 2. Catch ein, da die Zahl mit 2 Punkten und mehr nicht konvertiert werden kann.

vielleicht hilft dies dem ein oder anderen ;) und mein Problem ist somit gelöst :)

Was war der Fehler:
Ich hatte in der Catch-Funktion diese "System::OverflowException^" nicht, da ich mich bisher noch nicht auskannte mit den Try & Catch Funktionen
 
Zurück
Oben