xbpcrt Fenster

Auf dem Weg von Clipper, FoxPro u.ä. nach Xbase++

Moderator: Moderatoren

Antworten
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

xbpcrt Fenster

Beitrag von saul »

Hallo,
ich habe angefangen in meinen aus Clipper in xbase übertragenen Code GUI Teile zu implantieren und habe sofort das erste Problem. Um dies zu erläutern habe ich den Code entsprechend verkleinert. Mit der Func Appsys() wird das Textfenster erzeugt und ich kann aus einen kleinen Menü auswählen. Wähle ich das Browserfenster, so erhalte ich die Anzeige wie gewünscht und ich kann in der Datenbank lesen.
Ab hier habe ich ein Problem.
1. In der Eventschleife reagiert das Programm nicht auf die ESC Taste um zum vorherigen Fenster wieder zurückzukehren.
2. Wie und wo muß ich welchem Fenster den Focus geben, was muß destroyed werden?
3. Ist das Browse Objekt wie ein Fenster zu behandeln mit setfocus und destroy?

Code: Alles auswählen

#include "directry.ch"
#include "DLL.CH"
#include "inkey.ch"
#include "regclass.ch"
#include "xbp.ch"
#pragma Library( "XppUi2.lib" )
//////////////////////////////////////////////////////////////////////
//  APPSYS.PRG
//  Copyright:
//      Alaska Software GmbH, (c) 1997-1999. Alle Rechte vorbehalten.
//  Inhalt:
//      AppSys() - Standard Applikationsfenster erzeugen
//  Bemerkungen:
//      Diese Datei ist Teil der XppRt0.lib.
//  Syntax:
//      Die Funktion AppSys() wird automatisch beim Programstart
//      aufgerufen.
//////////////////////////////////////////////////////////////////////
****************************************************************************
* Funktion AppSys() um Standard-Ausgabegeraete zu erzeugen
****************************************************************************
PROCEDURE AppSys()
  #define DEF_ROWS      25
  #define DEF_COLS       80
  public oCrt //war früher Zeile 1 bei Local mußte aber public und am Ende
                 //jeden Programmes muß oCrt:destroy() freigegeben werden
  aSizeDesktop    := AppDesktop():currentSize()         // Anordnen in der Mitte des Desktop-Fensters
  DEF_FONTHEIGHT = 24
  DEF_FONTWIDTH = 12
  aPos := { 25,77 }
  // XbpCRT-Fenster erzeugen
  oCrt := XbpCrt():New ( NIL, NIL, aPos, DEF_ROWS, DEF_COLS )
  oCrt:FontWidth  := DEF_FONTWIDTH
  oCrt:FontHeight := DEF_FONTHEIGHT
  oCrt:title        := "Prüffix"
  oCrt:automark:= .f.
  oCrt:icon        := 1
  oCrt:sysmenu  := .f.	                               // macht rechts oben die Icons weg
  oCrt:FontName:= "System VIO"
  oCrt:Create()
  oCrt:PresSpace()                                    // Presentation Space initialisieren
  SetAppWindow ( oCrt ) 	               // XbpCrt wird aktives Fenster und Ausgabegerät
RETURN

procedure main
  mmende = " "
  do while mmende <> "E"
    @6,1 clear to 23,78
    @07,15 prompt "Browse Fenster wählen"
    @09,15 prompt "Hier passiert im Moment nix"
    @21,15 prompt "Ende"
    @23,7 say "Wählen Sie mit C up oder C down + RETURN oder erstem Buchstaben"
    menu to opt1
    if lastkey() = 27 .or. opt1=3
      exit
    endif
    do case
      case opt1 = 1
        browser()			// Fenster mit xbpbrowse für Daten aufrufen
      endcase
    enddo
  wait
return

  func browser				// hier wird links unten Fenster mit Daten angezeigt
    LOCAL nEvent, mp1, mp2, oXbp, oBrowse, cField, i
    USE formblat NEW
    // Dialogfenster versteckt erzeugen
    oXbp := GuiStdDialog( "Standard GUI Browser for DBF" )
    // Browser im Fenster erzeugen
    oBrowse := GuiBrowseDb( oXbp:drawingArea )
    // Spalten für alle Felder anfügen
    FOR i:=1 TO FCount()
      cField := FieldName( i )
      oBrowse:addColumn( FieldBlock(cField), , cField )
    NEXT
    // Der Browser füllt nach :resize() immer das Fenster aus
    oXbp:drawingArea:resize := {|mp1,mp2,obj| obj:childList()[1]:setSize(mp2) }
    oXbp:show()
    oBrowse:show()
    SetAppFocus( oBrowse )
    nEvent = 0
    DO WHILE nEvent <> xbeP_Close
      nEvent := AppEvent( @mp1, @mp2, @oXbp )
      if nEvent=xbeK_ESC
        quit
      endif
      oXbp:handleEvent( nEvent, mp1, mp2 )
    ENDDO
  RETURN .t.

   ******************************************************************
   * GUI Browser mit Navigations-Codeblöcken für DBF erzeugen
   ******************************************************************
   FUNCTION GuiBrowseDB( oParent, aPos, aSize )
      LOCAL oBrowse
      oBrowse := XbpBrowse():new( oParent,, aPos, aSize ):create()
      // Navigationscodeblöcke für den Browser
      oBrowse:skipBlock     := {|n| DbSkipper(n) }
      oBrowse:goTopBlock    := {| | DbGoTop()    }
      oBrowse:goBottomBlock := {| | DbGoBottom() }
      oBrowse:phyPosBlock   := {| | Recno()      }
      // Navigationscodeblöcke für den vertikalen Scrollbar
      oBrowse:posBlock      := {| | DbPosition()    }
      oBrowse:goPosBlock    := {|n| DbGoPosition(n) }
      oBrowse:lastPosBlock  := {| | 100             }
      oBrowse:firstPosBlock := {| | 0               }
   RETURN oBrowse

   ******************************************************************
   * Standard Dialogfenster versteckt erzeugen
   ******************************************************************
   FUNCTION GuiStdDialog( cTitle )
      LOCAL oDlg
      DEFAULT cTitle TO "Standard Dialog Window"
      oDlg          := XbpDialog():new( ,,{10,10}, {600,400},, .F. )
      oDlg:icon     := 1
      oDlg:taskList := .T.
      oDlg:title    := cTitle
      oDlg:titlebar := .F.
      oDlg:create()
      oDlg:drawingArea:setFontCompoundName( "10.Helv" )
   RETURN oDlg
mfg
Wolfgang
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: xbpcrt Fenster

Beitrag von AUGE_OHR »

saul hat geschrieben:1. In der Eventschleife reagiert das Programm nicht auf die ESC Taste um zum vorherigen Fenster wieder zurückzukehren.
2. Wie und wo muß ich welchem Fenster den Focus geben, was muß destroyed werden?
3. Ist das Browse Objekt wie ein Fenster zu behandeln mit setfocus und destroy?

Code: Alles auswählen

func browser	
...
    DO WHILE !lExit
...  
      // das ist kein Event sondern "nur" eine Konstante
      if nEvent=xbeK_ESC 
...
    ENDDO
    // aufräumen vor dem verlassen
    oDlg:destroy() 
RETURN .t.
ad 1.) Event´s beruhen auf #define xbeB_Event siehe c:\ALASKA\XPPW32\Include\appevent.ch
nach dem Event kommen dann die Konstanten

Code: Alles auswählen

nEvent := AppEvent(@mp1,@mp2,@oXbp,100*60*30)
DO CASE
   CASE nEvent == xbe_None                            // Timeout 30 min
...     
   CASE nEvent == xbeP_Keyboard .AND. mp1 == xbeK_ESC
      EXIT
   OTHERWISE
      oXbp:handleEvent(nEvent,mp1,mp2,oXbp)
ENDCASE
ad 2.) immer das letzte ;)
ad 3.) setAppFocus() ist für ein XbPart, setAppWindow() ist für ein "Fenster" wenn CRT im Spiel sind.

Bemerkung : Ich würde empfehlen zuerst ein XbpDialog() mit Menu zu bauen und dann die oDlg:drawingArea als "Fundament" für deine XbpCrt() "Fenster".
Das XbpCrt() sollte die oDlg:drawingArea "voll ausfüllen" ( SDI ) und der XbpDialog sollte eine "feste" Grösse haben.
Mit XbpCRT() MDI zu machen ist sehr kompliziert und nicht zu empfehlen ... da kann man gleich GUI machen.

Wenn du nun XbParts nach SDI verwenden willst nimmst du oDlg:drawingArea als Parent wenn es "über" deinem XbpCrt() liegen soll und machst es modal d.h. man kann das XbpCrt() nicht (unbeabsichtigt) erreichen.

Wenn du "nur" zwischen XbParts (GUI) "umschalten" willst reicht ein SetAppFocus(), aber wenn man im Hybrid Modus ist muss man "zwischen" den "Fenstern" auch noch mit SetAppWindow() auf das entsprechenden "Fenster umschalten".

Während ein XbPart den "Focus" hat, kann keine "Ausgabe" im XbpCrt() erfolgen.
In solchen Fällen ist das Programm im CRT "Fenster" so lange "festzuhalten" bis es wieder mit SetAppWindow() angesprochen wird.

Zusammenfassung : bleibe bei VIO oder gehe den "full" GUI Weg ...
Hybrid ist viel komplizierter und lohnt sich nicht wenn man nach GUI will

Empfehlung : siehe dir mal 3PP (Source) Libs wie Express++ oder Topdown an.
gruss by OHR
Jimmy
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: xbpcrt Fenster

Beitrag von saul »

Hallo,
danke für Deine Antwort. Ein Umstellen auf full GUI ist nicht möglich, da dies mit viel zu viel Arbeit bei den umfangreichen Programmen ist, zumindest im Moment.
Ich habe Deine Hilfe mal umgesetzt, zumindest soweit ich dies begriffen habe.

Code: Alles auswählen

  	DO WHILE nEvent <> xbeP_Close
  	  nEvent := AppEvent( @mp1, @mp2, @oXbp,100*60*30)
			DO CASE
  	 	CASE nEvent == xbe_None                            // Timeout 30 min
				exit
  	 	CASE nEvent == xbeP_Keyboard .AND. mp1 == xbeK_ESC
      	EXIT
   		OTHERWISE
      	oXbp:handleEvent(nEvent,mp1,mp2,oXbp)
			ENDCASE
  	ENDDO
  	oBrowse:destroy()
	  oXbp:destroy()
Bei dieser Version kann ich die Do While Schleife verlassen. Leider gibt es dann bei oXbp:destroy() eine Fehlermeldung: falscher Objekt Status. Lasse ich oBrowse:destroy() weg gibt es keine Fehlermeldung.

Code: Alles auswählen

			case opt1 = 1
				browser()										// Fenster mit xbpbrowse fr daten aufrufen
  			SetAppWindow ( oCrt ) 					  // XbpCrt wird aktives Fenster und Ausgabeger„t
  			SetAppFocus( oCrt )
Wenn ich dann wieder zum xbpcrt Fenster zurückkehren möchte, bleibt das xbpDialogfenster weiterhin sichtbar und die Auswahl im xbpcrt Fenster funktionieren auch nicht.
mfg
Wolfgang
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: xbpcrt Fenster

Beitrag von AUGE_OHR »

saul hat geschrieben:Bei dieser Version kann ich die Do While Schleife verlassen. Leider gibt es dann bei oXbp:destroy() eine Fehlermeldung: falscher Objekt Status. Lasse ich oBrowse:destroy() weg gibt es keine Fehlermeldung.
...
Wenn ich dann wieder zum xbpcrt Fenster zurückkehren möchte, bleibt das xbpDialogfenster weiterhin sichtbar und die Auswahl im xbpcrt Fenster funktionieren auch nicht.
"wo" hast du die DO WHILE Schleife ?

In deinem vorherigen Beispiel hast du sowohl in der CRT als auch im Browse eine DO WHILE Schleife ...
das ist "prozedural"es "Denken" und funktioniert nicht mit GUI.

Bei GUI könnte jedes XbPart zu jeder Zeit "alles" machen, also bestimmst du nicht die "Action" sondern die "Reaktion" auf ein XbPart.

Eine DO WHILE Schleife brauchst du "pro Thread", aber wenn du nur die Main hast solltest du auch nur eine DO WHILE Schliefe haben.
Im optimalsten Fall hast du also für eine 100000 Zeilen Application nur eine einzige DO WHILE Schleife.

wie ich die schon vorschlug solltest du die Reihenfolge ändern und zuerst einen GUI XbpDialog ":create()"n und auf die :drawingArea dein XbpCRT() legen.
Das XbpBrowse() wird "danach" erzeugt und verwendet als Parent ebenfalls die :drawingArea und wird durch die DO WHILE des XbpDialog "gesteuert".

Dabei wird aber nicht jede "Reaktion" in die DO WHILE geschrieben, die würde ja dann immer "grösser" werden, sondern man nutzt die :Keyboard Slot des XbPart.

Code: Alles auswählen

oBrowse:keyboard := {|| {| nKeyCode, uNIL, oSelf | MyBrowseKey(nKeyCode,oSelf) }}

PROCEDURE MyBrowseKey(nKeyCode,oBrowse)
DO CASE
     CASE nKeyCode = xbeK_ESC
ENDCASE
saul hat geschrieben:Ein Umstellen auf full GUI ist nicht möglich, da dies mit viel zu viel Arbeit bei den umfangreichen Programmen ist, zumindest im Moment.
Nun ich gehe mal davon aus das du eine "Plan" hast wie du nach GUI kommst ?

Ich meine mit "Plan", ein "Framework" also ein "Gerüst", wo du deine Module einbaust.
Wenn du dir nicht selbst eins bauen kannst würde ich auf 3PP Libs wie Express++ oder Topdown zurück greifen.

Auch kann ich nur raten eine komplette GUI Application vorher zu "planen" bevor man die erste Zeile schreibt.
... Spagetti Code unter GUI wird nicht funktionieren ...
gruss by OHR
Jimmy
Juergen
UDF-Programmierer
UDF-Programmierer
Beiträge: 92
Registriert: Di, 19. Dez 2006 19:37
Wohnort: Düsseldorf
Kontaktdaten:

Re: xbpcrt Fenster

Beitrag von Juergen »

Hallo,

ich würde eXpress++ empfehlen. Eines der Samples nennt sich MdiCrt. Basis ist ein Hauptmenü, aus
dem heraus beliebige Crt-Fenster aufgerufen werden, diese laufen in einem eigenen Prozeß.

Ich denke das ist für Clippercode optimal, zumal die Datenbanken aufgrund der eigenen Prozesse
mehrfach aufgerufen werden können.

Gruß

Jürgen
Antworten