Edit->OnChange manuell auslösen mit Zeiger?



  • Worin liegt für dich der Unterschied vom Auslösen des Events und nachfolgenden Abarbeiten der Eventfunktionen zum direkten Auslösen der Eventfunktionen?



  • Okay, ich versuchs nochmal:
    * Auf einem Form befinden sich mehrere Edit's.
    * Für alle Edits existiert ein und dieselbe OnChange-Behandlung.
    * Wenn ich in einem Edit zur Laufzeit ein Zeichen eingebe, wird diese OnChange-Behandlung angesprungen.
    * Dort wird zuerst der Sender (das auslösende Edit) in einen Zeiger gecastet.
    * Dann werden Eigenschaften des auslösenden Edits über den Zeiger in Variablen gespeichert (Tag, Enabled, Text etc.).
    * Je nach Tag und Text des Edits werden weitere Edits mit demselben Text gefüllt.
    * Ergebnis: Nun gibt es Edits, deren Text in der OnChange-Behandlung vom Programm gefüllt wurde.
    ------------------------------------------------
    Bis hierhin funktioniert auch Alles sauber.
    ------------------------------------------------
    * Wenn man in diese (momentan) "programmgefüllten" Edits manuell etwas eingibt, werden wiederum andere Edits gefüllt...
    * Werden die Edits "programmgefüllt", werden die weiteren Edits dummerweise nicht gefüllt...
    * Deshalb möchte ich ein OnChange-Event auslösen, wenn bestimmte Edits ausgefüllt werden.

    **Problembild (stark vereinfacht):
    **
    vorhandene Vorraussetzung im OnChange:

    Edit1->Text manuell verändert ==> Edit2->Text wird automatisch mit Edit1->Text gefüllt
    Edit2->Text manuell verändert ==> Edit3->Text wird automatisch mit Edit2->Text gefüllt
    

    Wunschverhalten:

    Edit1->Text manuell verändert 
    ==> Edit2->Text wird automatisch mit Edit1->Text gefüllt 
    ==> Edit3->Text wird automatisch mit Edit2->Text gefüllt
    

    tatsächliches Verhalten:

    Edit1->Text manuell verändert 
    ==> Edit2->Text wird automatisch mit Edit1->Text gefüllt 
    ==> kein Change-Event 
    ==> Edit3->Text wird nicht gefüllt
    

    Das dient aber nur der Problembeschreibung. Das Form hat tatsächlich 28 Edits die auf verschiedenste Art und Weise miteinander verknüpft (zB. wie oben beschrieben) sind. Dazu kommen 34 CheckBoxes, die auch (teilweise abhängig von Eingaben in den Edits) mit verknüpft sind. Daher kann ich nicht mehr einfach schreiben: "wenn das gefüllt, fülle dies und jenes". Der Vollständigkeit halber, hier der Code des OnChange (noch nicht alle Wechselbeziehungen integriert):

    void __fastcall TForm1::EditChange(TObject *Sender)
    {
    	TEdit *VirtualEdit= static_cast<TEdit*>(Sender);
    	bool bAction= true, bEdtBad= false;
    	unsigned short ActNbr, k, Tag= (unsigned short)VirtualEdit->Tag;
    	short EingabeZahl= (short)StrToIntDef(VirtualEdit->Text, -1);
    
    	if(VirtualEdit->Modified)
    	{
    		Button1->Enabled= false;
    		MainMenu1->Items->Items[1]->Items[1]->Enabled= false;
    		// Modifikation eines Edit, welches weitere Werte beeinflusst:
    		switch(Tag)
    		{
    			case 1001: case 1002: case 1003: if(EingabeZahl>=2) ActNbr= 1;
    										else if(EingabeZahl==1) ActNbr= 2; break;
    			case 1004: case 1005: case 1006: if(EingabeZahl>=1) ActNbr= 3; break;
    			case 1007: case 1008: case 1009: if(EingabeZahl>=1) ActNbr= 4; break;
    			case 1010: case 1011: case 1012:
    			case 1013: case 1014: case 1015: if(EingabeZahl>=1) ActNbr= 8; break;
    			case 1016: case 1017: case 1018: if(EingabeZahl>=1) ActNbr= 6; break;
    			case 1019: case 1020: case 1021: if(EingabeZahl>=1) ActNbr= 8; break;
    			case 1022: case 1023: case 1024: if(EingabeZahl>=1) ActNbr= 5; break;
    			case 3010: case 3013: case 3016: case 3019: if(EingabeZahl>0) ActNbr= 7; break;
    			default: bAction= false;
    		}
    		if(bAction)
    		{
    			bool bTmpEn;			// "Enabled" der temporären virt. Komponente
    			unsigned short TmpTag;	// "Tag" der temp. virt. Komponente
    			AnsiString TmpTxt;		// "Text" des temp. virt. Edit
    
    			for(k=0; k<ComponentCount; k++)
    			{
    				if(Components[k]->ClassNameIs("TEdit"))
    				{
    					TEdit *VETmp= static_cast<TEdit*>(Components[k]);
    					bTmpEn= VETmp->Enabled;
    					TmpTag= (unsigned short)VETmp->Tag;
    					TmpTxt= VETmp->Text;
    
    					switch(ActNbr)
    					{
    						case 3: if(TmpTag==Tag+3 && bTmpEn) VETmp->Text= EingabeZahl; break;
    						case 4: if(TmpTag==Tag-3) VETmp->Text= EingabeZahl; break;
    						case 5: if(((TmpTag==1022) || (TmpTag==1023) || (TmpTag==1024)) && bTmpEn)
    								 VETmp->Text=EingabeZahl; break;
    						case 6: if(((TmpTag==Tag-3) || (TmpTag==Tag-6)) && bTmpEn) VETmp->Text=EingabeZahl; break;
    						case 7: if((TmpTag==Tag-2000) || (TmpTag==Tag-1999) || (TmpTag==Tag-1998))
    									VETmp->Text=EingabeZahl; break;
    						case 8: if((TmpTag==Tag+2000) || (TmpTag==Tag+1999) || (TmpTag==Tag+1998))
    								{ if(EingabeZahl!=((short)StrToIntDef(TmpTxt, -1))) bEdtBad= true; } break;
    					}
    				}
    			}
    			for(k=0; k<ComponentCount; k++)
    			{
    				if(Components[k]->ClassNameIs("TCheckBox"))
    				{
    					TCheckBox *VCB= static_cast<TCheckBox*>(Components[k]);
    					bTmpEn= VCB->Checked;
    					TmpTag= (unsigned short)VCB->Tag;
    
    					switch(ActNbr)
    					{
    						case 1: if((TmpTag==Tag+1000 || TmpTag==Tag+1003) && bTmpEn) VCB->Checked= false; break;
    						case 2: if((TmpTag==Tag+1000 || TmpTag==Tag+1003) && !bTmpEn) VCB->Checked= true; break;
    						case 8: if(bEdtBad && ((TmpTag==Tag+2000) || (TmpTag==Tag+1999) || (TmpTag==Tag+1998)) && bTmpEn)
    									VCB->Checked= false; break;
    					}
    				}
    			}
    		}
    	}
    }
    //---------------------------------------------------------------------------
    

    Ich hoffe das macht die Sache klarer... 😞



  • Braunstein schrieb:

    Worin liegt für dich der Unterschied vom Auslösen des Events und nachfolgenden Abarbeiten der Eventfunktionen zum direkten Auslösen der Eventfunktionen?

    Darin dass es nur um eine einzige Eventfunktion geht, die ich dann immer wieder aus sich selbst heraus aufrufen würde, was ich schlecht finde (weil es mein ganzes Konzept durcheinander bringt). Ich bin der Meinung die Events kommen in eine Warteschlange(?) und wenn die Eventfunktion verlassen wird, wird sie durch die Events in der Warteschlange wieder gestartet, immer schön nacheinander. Ist es nicht so?



  • BCB3-Hilfe schrieb:

    Wenn Sie feststellen wollen, ob sich die Eigenschaft Text in einem Eingabefeld geändert hat, verwenden Sie Modified. Die Eigenschaft Modified sollte auf true gesetzt werden, falls eine Anwendung die Eigenschaft Text in einem Eingabefeld direkt ändert.

    Wenn ich case 7 so abändere:

    case 7: if((TmpTag==Tag-2000) || (TmpTag==Tag-1999) || (TmpTag==Tag-1998))
    {	VETmp->Modified= true;
            VETmp->Text=EingabeZahl; } break;
    

    und im Schrittbetrieb durchgehe (TmpTag ist 1016, Tag ist 3016, Eingabezahl ist 4), springt das Prog nach VETmp->Text=EingabeZahl; gleich zum Aufruf der OnChange-Eventfunktion. Probleme: der if(Modified)-Teil wird nicht ausgeführt und das ursprüngliche OnChange ist noch garnicht vollständig abgearbeitet.



  • Prinzipiell schon. Du mußt bei deiner methode höllisch aufpassen, dass sich die Events nicht gegenseitig aufrufen und du in eine Endlosschleife gerätst.
    Ich sehe trotzdem hier nicht das Problem OnChange direkt, natürlich mit dem richtigen Sender (hatte ich vergessen), aufzurufen.
    Alternativ ginge vielleicht etwas mit SendMessage.

    SendMessage(VirtualEdit->Handle, EN_UPDATE, 0, 0);
    

    Ich weiß jetzt nicht ob das völlig korrekt ist. Ich kanns im Augenblick nicht testen.
    [edit]Jetzt sehe ich gerade deinen neuesten Post.
    Wenn du irgendwas an Text des Edits änderst (egal wie) wird immer OnChange aufgerufen. Wenn du das verhindern willst kannst du kurzfristig den Event aushängen.

    VirtualEdit->OnChange = 0;
    

    [edit]



  • Braunstein hat da mit allem Recht, deswegen solltest du mal das OnExit-Ereignis ins Auge fassen. Das wird nicht bei jedem Tastendruck ausgelöst.

    Ich würde nicht die Funktionalität ins Ereignis packen. Elegant würde man das lösen, indem man z. B. das TEdit ableitet und eine neue Methode für die Klasse schreibt. Ist die neue Klasse fertig, so schreibt man nachher die Funktionalität in die Methoden der einzelnen Instanzen. Die Methode ruft man im Ereignis und dort auf, wo du jetzt das Ereignis auslösen möchtest. So könnte es sogar mit OnChange funktioniern.



  • Braunstein schrieb:

    Du mußt bei deiner methode höllisch aufpassen, dass sich die Events nicht gegenseitig aufrufen und du in eine Endlosschleife gerätst.

    Jo, nich schön - ich weiß...

    Braunstein schrieb:

    Ich sehe trotzdem hier nicht das Problem OnChange direkt, natürlich mit dem richtigen Sender (hatte ich vergessen), aufzurufen.

    Genau da liegen die Probleme:
    1. befinde ich mich schon in der OnChange-Eventfunktion und möchte diese nicht unbedingt aus sich selbst heraus aufrufen.
    2. Wenn ich den Text verändere, was die OnChange-EvFkt aufruft, wird ja automatisch der richtige Sender genommen (hab ich auch beim 2. Aufruf der EvFkt anhand des Tag überprüft).
    3. Selbst wenn ich den Aufruf der OnChange-EvFkt aus sich selbst akzeptiere (nicht aushänge), funktioniert es so nicht. Wenn ich dabei Modified ordnungsgemäß true setze (wie in dem Beispiel mit "case 7", welches man sich in die gepostete Gesamtfunktion denken muss) wird bei erneutem Aufruf der OnChange-Eventfunktion (der dummerweise sofort geschieht) zwar der richtige Sender gecastet, aber Modified als false im Debugger angezeigt. Dadurch wird der if(Modified)-Zweig nicht angesprungen und der erneute Aufruf der Eventfunktion war für die Katz'.

    Braunstein schrieb:

    Alternativ ginge vielleicht etwas mit SendMessage.

    Das klingt interessant! 💡 Wird damit eine Windows-Message nachgebildet? Wie handhabt man das? Ist es nicht das, was ich wollte - ein Event manuell nachbilden? Bitte schreib mehr dazu.

    Braunstein schrieb:

    Wenn du irgendwas an Text des Edits änderst (egal wie) wird immer OnChange aufgerufen. Wenn du das verhindern willst kannst du kurzfristig den Event aushängen.

    Jo, is inzwischen mehr als klar.

    Fincki schrieb:

    [...] solltest du mal das OnExit-Ereignis ins Auge fassen. Das wird nicht bei jedem Tastendruck ausgelöst.

    Was soll ich denn damit? Das Problem sind die Verknüpfungen, nicht der Zeitpunkt des 1. OnChange-Aufrufs... Oder habe ich da was falsch interpretiert?

    Fincki schrieb:

    Ich würde nicht die Funktionalität ins Ereignis packen. Elegant würde man das lösen, indem man z. B. das TEdit ableitet und eine neue Methode für die Klasse schreibt. Ist die neue Klasse fertig, so schreibt man nachher die Funktionalität in die Methoden der einzelnen Instanzen. Die Methode ruft man im Ereignis und dort auf, wo du jetzt das Ereignis auslösen möchtest. So könnte es sogar mit OnChange funktioniern

    Das klingt ja schön einfach, wie du das so schreibst... kannst du mal ein Beispiel posten? Klassen selbst schreiben bzw. ableiten kann ich noch nicht / hab ich noch nie gemacht...



  • Kolumbus schrieb:

    Das klingt interessant! 💡 Wird damit eine Windows-Message nachgebildet? Wie handhabt man das? Ist es nicht das, was ich wollte - ein Event manuell nachbilden? Bitte schreib mehr dazu.

    Mehr als die eine Zeile gibt es eigentlich nicht dazu. Probiers einfach mal aus. Schau auch mal in der MSDN bei Edit-Controls nach.



  • Ok, Dankeschön erstmal bis hierhin...



  • SendMessage(VirtualEdit->Handle, EN_UPDATE, 0, 0);
    

    damit komme ich garnicht klar. Habe nur herausgefunden, dass eine Windows-Nachricht an einen Empfänger gesendet werden kann. Die Details bleiben mir verschlossen. Und Alles was ich dazu in der Hilfe oder dem I-Net finde sind für mich böhmische Dörfer. Ich werde an dieser Stelle abbrechen und mir was Anderes überlegen. Wird zwar dann unübersichtlicher, weil mehr Quelltext, aber was solls. Wenns nicht geht, gehts nicht! Wenn ich weder selbst beeinflußen kann wann OnChange ausgelöst wird (sondern die Eventfunktion für das jeweilige Edit aushängen muss, damit meine Funktion nicht "irgendwas" macht), noch das Modified über den Zeiger anständig setzen kann, fällt es eben aus. Hab' die Faxen dicke!

    Edit: ... Rechtschreibung ... 🙄



  • Du musst ja nicht die Eventfunktion aushängen.
    Du kannst ja auch darin prüfen ob es ein "gültiger" Aufruf gewesen ist...


Anmelden zum Antworten