Ausserordentliches Ereignis?



  • Hallo!

    Hilft mir leider nicht weiter, diese Eigenschaften kenne ich schon!

    Damit wird aber das "OnMouseDown" nicht hinfällig, der einzige Vorteil den ich daran erkennen kann, ist dass ich nicht für jedes Control ein eigenes OnMouseDown brauche, bzw. im OnMouseDown - Ereignis nicht mehr prüfen muss, um welches Objekt es sich eigentlich handelt...

    Mein Hilfesystem ist ausserdem komplizierter. (ist eigentlich gar kein Hilfesystem, das ganze hier aber zu erklären ist zu kompliziert und ich denke dann kann sich eh niemand was drunter vorstellen.)
    Im OnMouseDown - Ereignis brauche ich nämlich zudem die X und Y - Angaben, wo in dem Objekt hingeklickt wurde... Ausserdem brauche ich auch einen Zeiger auf das Control selbst, damit ich weiß, welches Control das Parent davon ist...

    Weiß jemand Rat, wie man sowas löst?

    tschüss
    Robert



  • Die x/y Angaben hast du doch schon (Parameter von OnMouseDown) und den Pointer auf den Client auch (Sender). Wo ist denn jetzt dein Problem.



  • Also, wenn ich Dich richtig verstehe, dann ist der Ablauf folgender:
    1. Ein Benutzer wählt (z.B. im Menü), daß er Hilfe braucht.
    2. Ein Klick auf einen Button oder sonstiges TControl bewirkt jetzt vorübergehend nicht,
    daß die Aktion ausgeführt wird, die dem OnClick-Ereignis zugeordnet ist, sondern eine
    spezielle "Hilfe-OnClick"-Routine.
    3. Nach der Hilfe soll wieder die Standard-OnClick-Routine zugeordnet sein.

    Wenn das so stimmt, ist die Lösung doch relativ einfach.
    1. Gehe alle aktiven Formulare Deiner Anwendung durch und biege für alle OnClick-Ereignisse die
    Ereignisbehandlungsmethode auf die für die Hilfe um. Merke Dir aber vorher die ursprünglichen
    Adressen.
    2. In Deiner "globalen" Hilfe-OnClick-Funktion identifiziere das Control über die Sender-Eigenschaft
    - wie von Braunstein vorgeschlagen. Die X/Y-Koordinaten bekommst Du auf ähnliche Weise über das
    MouseMove-Ereignis o.ä. raus. Vielleicht (Wahrscheinlich) gibt es auch einen Weg über die Win-API
    - dazu kannst Du sicherlich WebFritzi fragen.
    3. Setze die vorher gemerkten Ereignis-Methoden wieder auf die ursprünglichen Werte zurück.

    Das ganze funktioniert wahrscheinlich auch über Windows-Hooks, zu denen auch ein FAQ-Eintrag ex-
    istiert.

    Gruß,

    Alexander



  • Hallo Alexander!

    Erstmal vielen Dank für deine Antwort! Genau so, wie du das beschreibst sollte die Funktionsweise sein.

    Nur verstehe ich eines nicht so ganz: Ich gehe also alle Controls durch und setzt die Ereignisbehandlungsroutine auf was anderes, das dann meine Hilfefunktion wird.
    Nur, wie kann ich vorher die Events "zwischenspeichern", damit ich diese später wieder zuordnen kann. Damit komme ich nicht so ganz klar.

    Naja... während ich hier schreibe, kommt mir eigentlich ne Idee:
    2 TList Objekte, darin kann ich ja Zeiger zwischenspeichern.
    In die 1. Liste packe ich mir alle meine geänderten Controls und in die 2. Liste auf gleicher Höhe packe ich mir den Zeiger zum Event.
    Bei Beenden der Hilfe kann ich ja wieder alle meine Controls durchgehen, schaun ob das vielleicht in meiner 1. Liste drin ist - und wenn ja, das Ereignis der 2. Liste wieder zuweisen.

    Müsste doch so funktionieren?!? 🙂

    Ob das ne schöne Lösung gibt? Aber funktionieren müsste es...

    Danke dir für deinen Denkanstoss!

    tschüss
    Robert



  • rowisoft schrieb:

    2 TList Objekte, darin kann ich ja Zeiger zwischenspeichern.

    Das würde wohl gehen, besser würde ich aber finden, nur eine Liste zu verwenden (muß ja nicht TList
    sein), um die beiden (die ja zusammengehören) gemeinsam zu speichern. Also sowas wie Key/Value-
    Paare zu speichern. Möglich wäre es z.B. den Namen des Controls in eine TStringList zu speichern
    und die zugehörige Ereignis-Methode als Objekt (AddObject). Über FindComponent kann man dieses
    Control später wieder finden...
    Willst Du mehrere Methoden-Zeiger ablegen, würde ich Dir empfehlen, eine kleine Klasse oder Struct
    zu schreiben.

    Gruß,

    Alexander



  • Wenn es nur bei der einen Hilfsfunktion bleibt, könnte man bei klicken auf den Hilfebutton (oder Menupunkt etc.) ein Flag setzen welches dann in jeder implementierten OnMouseDown-Funktion (welche eine Hilfe hat) abgefragt wird. Dann entsprechend Flag eine zentrale Hilfsfunktion bzw. die Orginalroutine aufrufen. Dann Flag zurücksetzen.



  • Hallo!

    Wenn es nur bei der einen Hilfsfunktion bleibt, könnte man bei klicken auf den Hilfebutton (oder Menupunkt etc.) ein Flag setzen welches dann in jeder implementierten OnMouseDown-Funktion (welche eine Hilfe hat) abgefragt wird. Dann entsprechend Flag eine zentrale Hilfsfunktion bzw. die Orginalroutine aufrufen. Dann Flag zurücksetzen.

    Eben genau das wollte ich verhindern. Bei 90 Formularen - und dementsprechend viele TControls ist hier der Ärger vorprogrammiert. Und wenn dann neue Controls hinzugefügt werden (weil eine Software ja nie fertig ist) - wie oft wird da dann wohl vergessen, dieses Flag abzufangen?

    tschüss
    Robert



  • Hallo!

    Irgendwie raff ich das nicht.

    Wenn ich sozusagen den Hilfe-Button drücke, habe ich den folgenden Code eingebaut:

    MaskenDesignerList = new TList();
          MaskenDesignerEvents = new TList();
          for ( int i = 0; i < Form1->ActiveMDIChild->ComponentCount; i++)
          {
            if (dynamic_cast<TControl*>(Form1->ActiveMDIChild->Components[i]))
            {
              TControl *Element = dynamic_cast<TControl*>(Form1->ActiveMDIChild->Components[i]);
              MaskenDesignerList->Add(Element);
              TMouseEvent event = (((TButton*)Element)->OnMouseDown);
              MaskenDesignerEvents->Add(*(((TButton*)Element)->OnMouseDown));
              ((TButton*)Element)->OnMouseDown = MaskenDesignerElementMouseDown;
            }
          }
    

    Irgendwas (ich weiß aber nicht was) muss daran aber falsch sein. Wenn ich nachher sozusagen beim Ausschalten der Hilfefunktion diesen Code reinmache:

    for ( int i = 0; i < Form1->ActiveMDIChild->ComponentCount; i++)
          {
            if (dynamic_cast<TControl*>(Form1->ActiveMDIChild->Components[i]))
            {
              TControl *Element = dynamic_cast<TControl*>(Form1->ActiveMDIChild->Components[i]);
              for (int x = 0; x < MaskenDesignerList->Count; x++)
              {
                if (MaskenDesignerList->Items[x] == Element)
                {
                  ((TButton*)Element)->OnMouseDown = *((TMouseEvent*)(MaskenDesignerEvents->Items[x]));
                  break;
                }
              }
            }
          }
    

    Bleibt das OnMouseDown - Event immer noch auf auf die "Hilfefunktion". Der Debugger sagt mir auch, dass jedes Element von "MaskenDesignerEvents" meine Hilfefunktion ist.
    Daher gehe ich davon aus, dass ich beim Setzen schon was falsch mache, ich weiß aber nicht was...

    BTW: Wie kann ich denn auf TControl::OnMouseDown zugreifen, ohne jeweils auf irgendein spezielles Control (Button) casten zu müssen? Oder wie kann ich auf den jeweils richtigen Typ casten, das mit (TButton*) funktioniert zwar, kann aber doch auch nicht die optimale Lösung sein??!

    Vielleicht kann mir ja nochmal jemand helfen...

    Danke & tschüss
    Robert



  • Hast Du es schon mal mit MethodName() und MethodAdress() versucht? Diese scheinen mir besser für Dein vorhaben geeignet.



  • Hallo!

    Danke für deine Antwort.
    Mit MethodName komme ich nicht so ganz zurecht. Wenn ich z.B. mache
    ShowMessage(Button1.MethodName(&(Button1->OnMouseDown)));
    erhalte ich immer einen leeren String...

    Aber egal - das Problem ist gelöst. Habe mir in meiner Klasse einen Zeiger TMouseEvents deklariert und beim Starten der Hilfefunktion habe ich dann = new TMouseEvents[AnzahlDerControls] gemacht und diese einzeln gefüllt.
    Und diese konnte ich nachher dann auch wieder zurückgeben.
    Da war meine Idee mit TList wohl nicht so optimal, obwohl mich immer noch wundert, warum das nicht funktioniert hat. Aber egal, die neue Lösung gefällt mir eh besser...

    Danke trotzdem euch allen!

    tschüss
    Robert



  • rowisoft schrieb:

    Wie kann ich denn auf TControl::OnMouseDown zugreifen, ohne jeweils auf irgendein spezielles Control (Button) casten zu müssen?

    Ja, das fand ich auch toll, als ich damals damit rumexperimentiert hatte. Joe_M. hat die Richtung schon angedeutet.
    Man kann das auch dynamisch machen. Das sieht dann ungefähr so aus:

    for (int i=0; i<form->ComponentCount; ++i)
    {
       TMethod method;
       method.Data = this;
       method.Code = this->MethodAddress("FormMouseMove");
       PPropInfo PropInfo = GetPropInfo((PTypeInfo)form->Components[i]->ClassInfo(), "OnMouseMove");
       if (PropInfo && (*PropInfo->PropType)->Kind == tkMethod && 
           (AnsiString)(*PropInfo->PropType)->Name == String("TMouseMoveEvent"))
          SetMethodProp(static_cast<TObject *>(form->Components[i]), PropInfo, method);
    }
    

    Dabei ist FormMouseMove die Ereignisbehandlungsmethode, die Du neu zuweisen willst. In Deinem Fall also Deine "Hilfe"-
    Methode. OnMouseMove ist die Ereignis-Eigenschaft des Controls, der Du Deine Methode zuweisen willst. Vorher solltest Du
    aber noch prüfen, ob form->Components[i] auch vom Typ TControl ist.

    Gruß,

    Alexander


Anmelden zum Antworten