SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFocus

Grafische Primitive, XbaseParts und Darstellungsfragen allgemein.

Moderator: Moderatoren

Antworten
DelUser01

SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFocus

Beitrag von DelUser01 »

Hallo

Mit SetAppFocus() positioniere ich in einer Eingabeschleife die zu bearbeitenden SLEs.
Nun bin ich davon ausgegangen, dass beim setzen des Focus auf ein anderes SLE mit SetAppFocus( oSLE ) automatisch die Signale xbeP_KillInputFocus und xbeP_SetInputFocus erzeugt werden.
Dadurch würde ja z.B. der zugewiesene Block ausgeführt:
oSLE:KillInputFocus := { | uNIL1 , uNIL2 , oSle | oSle:getData() }

Nun habe ich festgestellt, dass diese Signale nur erzeugt werden wenn man die SLE-Felder z.B. per Mausklick wechselt. Wenn ich das aber mit einer eigenen Tasten-Steuerung (per Return, Tab, Up, Down) mache wird zwar der Focus gewechselt aber der Block für KillInputFocus nicht ausgeführt (weil die Signale nicht gesendet werden...)!

Die Überprüfung mit oSLE:hasInputFocus() zeigt dass der erwartete SLE den InputFocus hat.

Warum kommen diese Signale nicht?
Wo mache ich da einen Denkfehler?

Gruß
Roland
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von brandelh »

wie genau prüfst du ob die Events gesetzt werden ?

Man muss beachten, dass die Reihenfolge von SetInputFocus und KillInputFocus unerwartet ausfällt.
Anleitung hat geschrieben:Das Ereignis xbeP_KillInputFocus wird erzeugt, wenn der Eingabefokus von einem Xbase-Part genommen wurde (erst wird der Eingabefokus versetzt, dann wird das Ereignis generiert). Die ersten beiden Codeblock Parameter enthalten NIL und der dritte enthält self . Wenn der Codeblock bzw. die Methode ausgeführt wird, hat self keinen Eingabefokus mehr.
(erst wird der Eingabefokus versetzt, dann wird das Ereignis generiert) das meint, dass zunächst ein SetInputFocus() im neuen Contol ausgelöst wird und erst danach der KillInputFocus().
Je nach Code sieht es dann aus, als ob der codeblock nicht ausgeführt wird. Ich setze in solchen Fällen z.B. Tone(1000,3) ein, dies sollte dann immer zu hören sein wenn der Focuswechsel erfolgt.
Gruß
Hubert
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert,

mit der Reihenfolge hast Du natürlich recht.

Ich habe die Sache auf verschiedene Weise beobachtet. es verhält sich bei mir schon wie beschrieben. Beim Wechseln des Focus zwischen den SLEs mit AppSetFocus kommt kein KillInputfocus und kein SetInputFocus. Nur wenn ich z.B. mit der Maus in die verschiedenen Felder klicke.

Gruß
Roland
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von brandelh »

vielleicht zeigst du mal wie du die Tastensteuerung eingebaut hast ...
Gruß
Hubert
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert,

den Code kann ich nicht hier reinkopieren. Das sind zig Functions und sehr viele Zeilen. Ist halt im Laufe er Zeit gewachsen.

Im Grunde aber ein ganz normaler Aufbau (sehr verkürzt):

Code: Alles auswählen

Do While !lExit
   SetAppFocus( oSLE )      (=>zum gewünschten SLE)
   Do While ...
      AppEvent
      HandleEvent
   EndDo

   (  Benutzereingaben auswerten, nächste oSLE oder EXIT )
EndDo
Und beim SetAppFocus habe ich eben das erwartet.
Es ist schon ein wenig seltsam dass diese Events nicht verschickt werden.

MfG
Roland
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von brandelh »

Hi,

Code: Alles auswählen

///////////////////////////////////////////////////////////////////////////////
//
//  Function-oriented code created by the Xbase++ FormDesigner
//    Creation date: 22.07.2013 Time: 09:30:05
//
///////////////////////////////////////////////////////////////////////////////

#include "Gra.ch"
#include "Xbp.ch"
#include "Appevent.ch"
#include "Font.ch"
#include "common.ch"


#PRAGMA LIBRARY( "ascom10.lib" )

procedure AppSys()
return

PROCEDURE Main
   LOCAL nEvent, mp1, mp2, aSize
   LOCAL oDlg, oXbp, drawingArea, aEditControls := {} , aJumpControls := {}

   IF IsMemberVar(XbpDialog(),"ClientSize") == .T.
      aSize := {0,0}
   ELSE
      aSize := {600,400}
   ENDIF

   oDlg := XbpDialog():new( AppDesktop(), , {676,458}, aSize, , .F.)
   IF aSize[1] == 0 .AND. aSize[2] == 0
      oDlg:ClientSize := {584,366}
   ENDIF
   oDlg:taskList := .T.
   oDlg:title := "Focus Test"
   oDlg:create()

   drawingArea := oDlg:drawingArea
   drawingArea:setFontCompoundName( "8.Arial" )

   oXbp := XbpSLE():new( drawingArea, , {24,324}, {84,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } } )
   oXbp:tabStop := .T.
   oXbp:cargo := "1"
   oXbp:create()
   aadd(aJumpControls,oXbp)

   oXbp := XbpSLE():new( drawingArea, , {24,288}, {84,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } } )
   oXbp:tabStop := .T.
   oXbp:cargo := "2"
   oXbp:create()
   aadd(aJumpControls,oXbp)

   oXbp := XbpSLE():new( drawingArea, , {24,252}, {84,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } } )
   oXbp:tabStop := .T.
   oXbp:cargo := "3"
   oXbp:create()
   aadd(aJumpControls,oXbp)

   oXbp := XbpSLE():new( drawingArea, , {24,216}, {84,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } } )
   oXbp:tabStop := .T.
   oXbp:cargo := "4"
   oXbp:create()
   aadd(aJumpControls,oXbp)

   oXbp := XbpPushButton():new( drawingArea, , {468,324}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } } )
   oXbp:caption := "Ende"
   oXbp:tabStop := .T.
   oXbp:create()
   oXbp:activate := {|| PostAppEvent( xbeP_Close ) }



   oDlg:show()
   SetAppFocus(oDlg)
   SetAppFocus(oXbp)

   nEvent := xbe_None
   DO WHILE nEvent <> xbeP_Close
      nEvent := AppEvent( @mp1, @mp2, @oXbp )
      do case
         case nEvent = xbeP_Keyboard .and. mp1 = xbeK_ENTER .and. oXbp:isDerivedFrom( "XbpSle" )
              tone(100,2)
              // PostAppEvent( xbeP_Keyboard, xbeK_TAB ) - indirekt, dann aktuellen Event unterdrücken
              mp1 := xbeK_TAB      // oder auf gewünschte Taste umbiegen.
              DebugPrint("ENTER => TAB "+oXbp:cargo)
         case nEvent = xbeP_KillInputFocus .and. oXbp:isDerivedFrom( "XbpSle" )
              DebugPrint("KillInputFocus in SLE "+oXbp:cargo)
         case nEvent = xbeP_SetInputFocus .and. oXbp:isDerivedFrom( "XbpSle" )
              DebugPrint("SetInputFocus in SLE "+oXbp:cargo)
         case nEvent = xbeP_KillInputFocus
              DebugPrint("KillInputFocus NON SLE ")
         case nEvent = xbeP_SetInputFocus
              DebugPrint("SetInputFocus NON SLE ")
         case nEvent = xbeP_Keyboard .and. mp1 = xbeK_ALT_1
              DebugPrint("ALT 1")
              setAppFocus(aJumpControls[1])
         case nEvent = xbeP_Keyboard .and. mp1 = xbeK_ALT_2
              DebugPrint("ALT 2")
              setAppFocus(aJumpControls[2])
         case nEvent = xbeP_Keyboard .and. mp1 = xbeK_ALT_3
              DebugPrint("ALT 3")
              setAppFocus(aJumpControls[3])
         case nEvent = xbeP_Keyboard .and. mp1 = xbeK_ALT_4
              DebugPrint("ALT 4")
              setAppFocus(aJumpControls[4])
      end case
      oXbp:handleEvent( nEvent, mp1, mp2 )
   ENDDO
RETURN

*------------------------------------------------------------------
function DebugPrint(uTxt)
   static oDlg := NIL,oXbp  := NIL
   local cBufferTxt := "--- Ende ---"
   local cTxt
   DEFAULT uTxt TO ""
   cTxt := var2char(uTxt)
   if IsNil(oDlg)
      oDlg             := XbpDialog():new( AppDesktop(),,{5,20},{300,500} )
      oDlg:title       := "Debug Print Fenster"
      oDlg:alwaysOnTop := .t.
      oDlg:clipChildren:= .t.
      oDlg:create()
      oXbp             := XbpMle():new(oDlg:drawingArea,,{0,0},;
                                                   {oDlg:drawingArea:currentsize()[1],;
                                                    oDlg:drawingArea:currentsize()[2]})
      oXbp:horizScroll := .F.
      oXbp:create()
      oXbp:SetData(cBufferTxt)
      oDlg:resize      := { |aAlt,aNeu| oXbp:setSize( oDlg:drawingArea:currentsize() ) }
      oDlg:show()
   else
      * cBufferTxt := oXbp:GetData()
      cBufferTxt := oXbp:editBuffer()
   endif
   if ! empty(cTxt)
      cBufferTxt := time()+" "+cTxt+chr(13)+chr(10)+cBufferTxt
   endif
   if ! empty(cBufferTxt)
      oXbp:SetData(cBufferTxt)
   endif
return NIL
wenn du dieses Beispiel mit GUI=YES kompilierst und testest, wirst du sehen, dass es egal ist, ob mit TAB, MAUS oder ALT_1 bis ALT_4 (SetAppFocus) das SLE gewechselt wird.
Wenn vorher ein SLE oder MLE oder sonstiges Eingabecontrol aktiv war, wird dieses zuerst einen KillInputFocus Event versenden (der Wechsel scheint laut Hilfe dann schon erfolgt zu sein),
dann folgt der SetInputFocus im neuen Control (außer es ist kein Eingabekontrol wie z.B. ein PushButton).

Bei deinem kleinen Beispiel scheint es mir, als ob du mehrere Eventschleifen hättest, das ist sehr gefährlich.
Wahrscheinlich geht der Event in deiner Steuerung verloren.
Gruß
Hubert
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert,

das Hauptfenster meiner Anwendung ist (noch) ein XbpCrt.
Ich habe vermutlich durch Parameter beim XbpDialog und/oder dem XbpSle die automatischen TAB-Funktionen abgeschaltet. Das mache ich alles selbst.
Das erklärt trotzdem nicht warum die Event-Signale fehlen.

Es sind zwar verschiedene verschachtelte Schleifen die das von AppEvent + HandleEvent zurückgegebene behandeln bevor es zum eigentlichen SLE kommt aber natürlich kontrolliere ich die Signale im Kern des Programms.
Da kommt beim Focus-Wechsel alles mögliche, nur nicht Kill+Set.

MfG
Roland
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von brandelh »

ein KillInputFokus wird z.B. auch beim Fensterwechsel erzeugt (z.B. weil eine MSGBOX() aufgeht oder weil dein Hauptprogramm kurz aufgerufen wird.
Hast du für den GUI Teil auch SetAppWindow() gesetzt ?
Es gibt da viele Möglichkeiten, auf jeden Fall erzeugt ein XbpSLE(), das den InputFocus hatte :!: , beim verlieren des Focus einmal diesen Event.
Eventuell verliert es diesen bei deiner Steuerung früher, als du es erwartest ;-)
Gruß
Hubert
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert,

beim Fensterwechsel werden die Events auch richtig erzeugt.
Beim Dialog und SLE ist Parent der Desktop und Owner das CRT.
SetAppWindow ist das XbpCrt.

MfG
Roland
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von brandelh »

Beim Dialog und SLE ist Parent der Desktop und Owner das CRT.
Ich vermute mal mit Dialog ist ein unabhängiges Fenster von XbpDialog() gemeint, dort ist der Desktop als Parent OK.
Aber alle Controls auf dem Fenster müssen XbpDialog:drawingArea oder ein darauf liegendes anderes Control haben.
Denn wenn ein Control einen Event hier z.B. Keyboard ENTER nicht selbst verarbeiten kann, dann gibt es diesen Event an seinen Parent weiter.
So kann man z.B. die Steuerung direkt ans Fenster hängen statt bei jedem Control alle Zusatztasten abfangen zu müssen.

In deinem Fall würden alle diese unbehandelten Events an den Destop gehen.
Wie gesagt, Windows versendet immer die Nachrichten, Xbase liest die für uns relevanten ein, wenn es sie zuordnen kann.
Ob das jetzt die Ursache deines Problemes ist kann ich aber auch nicht sagen, denn ich programmiere ausschließlich XbpCRT() oder XbpDialog() Anwendungen.
SetAppWindow ist das XbpCrt.
Wenn man getrente Fenster hat, muss man beim SetDisplayfocus() SetAppWindow() auf diesen Dialog setzen, sonst werden alle Systemdialoge (z.B. MsgBox() ) das XbpCRT als aktives Fenster anzeigen.
Eine Systemmeldung sollte aber auf das vorher focusierte Fenster zurückspringen. Auch in das richtige SLE (außer man will nach einer Fehlermeldung woanders hin.).
Ein Rücksetzen des Cursors ins alte SLE wird aber von Xbase++ nicht automatisch unterstützt, das habe ich meiner XbpDialog-Klasse selbst beigebracht.
(nicht unproblematisch in Verbindung von zwei aufeinanderfolgenden fehlschlagenden Syntaxprüfungen, da ja mit dem Zurücksetzen sofort wieder eine Fehlmeldung mit Rücksetzung auf das andere SLE erfolgt. :arrow: Endlosschleife )
Gruß
Hubert
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert,

das mit dem Focus-Events geht zwar immer noch nicht aber ich habe das inzwischen anderweitig gelöst.
(Wenn es nicht richtig funktioniert...)

Aber vielleicht finden wir es noch heraus warum das nicht geht.

MfG
Roland
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Nachtrag 1:

Inzwischen habe ich eine umfangreichere Protokollierung eingebaut um die Events Auszuwerten.
Es tauchen jetzt auch wieder KillInputFocus und SetInputFocus auf.
Aber immer noch nicht beim reinklicken in ein SLE sondern erst bei der ersten Tasteneingabe im SLE, z.B. Pfeil rechts.
Also immer noch seltsam...

Gruß
Roland
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von brandelh »

Eventuell hilft dir mein Trick für die Fensterfarben:

Wenn man von einem Dialog A ein Control von Dialog B den Focus setzt, bekomme ich häufig ein Fenster mit aktivem SLE aber ohne die "Aktivfarbe im Titel" (ich hoffe das ist verständlich ...) ;-)
Aus diesem Grunde verwende ich 2 Aufrufe:

Code: Alles auswählen

oDlg1 = aktueller Dialog ...
oDlg2 = Zieldialog
oDlg2:oSle = SLE das den Eingabefocus erhalten soll.

// hier ist die Titelleiste von oDlg2 nicht immer richtig eingefärbt.
SetAppFocus(oDlg2:oSle)  

// so stimmt es immer !
SetAppFocus(oDlg2)  
SetAppFocus(oDlg2:oSle)  

...
Gruß
Hubert
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert

ich werde das testen...

Gruß
Roland
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Hubert

Dein Vorschlag mit Deinem Code hat leider keine Verbesserung gebracht.

Code: Alles auswählen

SetAppFocus(oDlg2)  
SetAppFocus(oDlg2:oSle)
Es ist ja nicht so dass nur der Fensterkopf nicht die aktive Farbe bekommt, der Dialog und der von mir focusierte SLE hat eben den Focus nicht.
Im Augenblick habe ich immer noch die Lösung mit Sleep(15) vor dem SetAppFocus(oSLE).

Die Events KillInputFocus und SetInputFocus sind inzwischen wieder da.
Was auch immer zwischenzeitlich schiefgelaufen war.

Gruß
Roland
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von AUGE_OHR »

Roland Gentner hat geschrieben:Im Grunde aber ein ganz normaler Aufbau (sehr verkürzt):

Code: Alles auswählen

Do While !lExit
   SetAppFocus( oSLE )      (=>zum gewünschten SLE)
   Do While ...
      AppEvent
      HandleEvent
   EndDo

   (  Benutzereingaben auswerten, nächste oSLE oder EXIT )
EndDo
das ist leider "Procedural" gedacht !
solange er "Benutzereingaben auswerten, nächste oSLE oder EXIT" Code ausführt kann er keinen Event "empfangen" !

wenn du mit XbParts, welches Classes sind, arbeitest solltest du mit OOP arbeiten wie es der Formdesigner ( XppFD.EXE ) als Class Code generiert.

Das PRG ohne "_" wird auch bei Änderungen im Formdesigner nicht verändert !
in die PRG ohne "_" schreibst du nun deinen Code für "Benutzereingaben auswerten, nächste oSLE oder EXIT".

Code: Alles auswählen

CLASS NewForm FROM _NewForm
   EXPORTED:
      METHOD init
      METHOD create
      // hier die neuen Method(en)
ENDCLASS
Im Formdesigner kann man ja keine Slots "bestücken". Das muss man nun "manuell" machen

Code: Alles auswählen

METHOD NewForm:create( oParent, oOwner, aPos, aSize, aPP, lVisible )
   ::_NewForm:create( oParent, oOwner, aPos, aSize, aPP, lVisible )

   ::oSLE1:setInputFocus := {| u1, u2, oSelf | ::MyWhen(oSelf,"oSLE1") }
   ::oSLE1:killInputFocus := {| u1, u2, oSelf | ::MyValid(oSelf,"oSLE1") }

   ::oSLE2:setInputFocus := {| u1, u2, oSelf | ::MyWhen(oSelf,"oSLE2") }
   ::oSLE2:killInputFocus := {| u1, u2, oSelf | ::MyValid(oSelf,"oSLE2") }

   ::oSLE3:setInputFocus := {| u1, u2, oSelf | ::MyWhen(oSelf,"oSLE3") }
   ::oSLE3:killInputFocus := {| u1, u2, oSelf | ::MyValid(oSelf,"oSLE3") }
...

   ::show()
RETURN self

METHOD NewForm:MyWhen(oSelf,cVar)
...
RETURN self
METHOD NewForm:MyValid(oSelf,cVar)
...
RETURN self
dein Code sollte also in der Class laufen und nicht in der Event-Loop.
gruss by OHR
Jimmy
DelUser01

Re: SetAppFocus(oSLE) erzeugt kein KillInputFocus/SetInputFo

Beitrag von DelUser01 »

Hallo Auge_Ohr

nun, ich denke dass OOP genauso prozedural abläuft wie alles andere. OOP ist nur eine andere Art der Programmierung und erfordert an bestimmten Stellen eine andere Denkweise.
Das wäre etwas anderes wenn automatisch durch EventHandle ein selbstständig ablaufender Task gestartet würde...
Schlussendlich bleibt auch bei OOP das gesamte Programm stehen wenn durch HandleEvent ein Funktion ausgeführt wird.

Insgesamt funktioniert ja (fast) alles. Es kommt eben zu Überschneidungen wenn ich beiden Steuerungen nicht 100%ig trenne.

Gruß
Roland
Antworten