////////////////////////////////////////////////////////////////////// // // PROGRESS.PRG // // Copyright: // Alaska Software, (c) 1997-2002. Alle Rechte vorbehalten. // // Inhalt: // Das Programm enth„lt die Klasse ProgressBar, welche eine // Fortschrittsanzeige verwaltet. Sie ist von XbpStatic abgeleitet. // Die Fortschrittsanzeige ist durch GraBox() realisiert, indem // farbige Quadrate im Micro Presentation Space von XbpStatic // von links nach rechts gezeichnet werden (horizontale Anzeige). // // Wenn ein Progressbar h”her ist als breit, werden die Quadrate // von unten nach oben gezeichnet (vertikale Anzeige). // // Bemerkungen: // - Automatische Anzeige // // Das Zeichnen der Quadrate erfolgt in einem separaten Thread und wird // durch ein Signal in der Methode :increment() ausgel”st. Falls // diese Methode nicht innerhalb von :maxWait/100 Sekunden gerufen // wird, erfolgt automatisch eine neue Anzeige. // // - Fortschrittsanzeige bei DbCreateIndex() / OrdCreate() // // Im Beispiel wird der Fortschritt bei der Erzeugung eines Indexes // angezeigt. Wird ein ProgressBar Objekt in dieser Situation // verwendet, muá die Indexdatei wieder geschlossen werden, nachdem // sie erzeugt wurde. Dadurch wird der Codeblock vernichtet, in dem // das ProgressBar Objekt eingebettet ist. // // Hinweis: Ein ProgressBar Objekt berwacht selbst, wann es sich // tats„chlich neu zeichnen muá. Bei der Index-Erzeugung wird die // Anzeige nur dann aktualisiert, wenn ein zus„tzliches Quadrat // gezeichnet werden muá. // ////////////////////////////////////////////////////////////////////// #include "Appevent.ch" #include "Gra.ch" #include "Xbp.ch" //// /////* //// * Die Main Prozedur zeigt den Gebrauch eines ProgressBar Objekts //// * im Zusammenhang mit der Erzeugung einer Datenbank und eines Indexes //// */ ////#ifdef DEBUG //// ////PROCEDURE Main //// LOCAL nEvent, mp1, mp2, oXbp, i, oProgress, oDlg //// //// SetColor( "N/W,W+/N" ) //// CLS //// //// /* //// * Objekt erzeugen und Wertebereich fr die //// * Fortschrittsanzeige festlegen //// */ //// oProgress := ProgressBar():new( ,, {120,200}, {400,24},, .F. ) //// oProgress:create() //// oProgress:minimum := 1 //// oProgress:maximum := 2000 //// //// ? "Datenbank wird erzeugt" //// //// DbCreate( "TEST", { {"NUMBER", "C", 16, 0} } ) //// USE Test EXCLUSIVE //// //// DO WHILE LastRec() < 2000 //// DbAppend() //// REPLACE FIELD->NUMBER WITH PadL( Recno()^2, 16, "0" ) //// oProgress:increment() //// ENDDO //// //// WAIT "Datenbank ist erzeugt. Taste drcken, um Index zu generieren" //// //// //// /* //// * Aktuellen Wert im ProgressBar zurcksetzen, Farbe und Gr”áe „ndern //// */ //// oProgress:current := 1 //// oProgress:color := GRA_CLR_RED //// oProgress:setSize( {300,20} ) //// DbCreateIndex( "Test", "NUMBER", ; //// {|| oProgress:increment(), NUMBER } ) //// SET INDEX TO Test //// //// //// WAIT "Index wird neu erzeugt. ProgressBar ist vertikal. Taste drcken..." //// oProgress:current := 1 //// oProgress:color := GRA_CLR_GREEN //// oProgress:setPos ( {10,30} ) //// oProgress:setSize( {15,220} ) //// //// DbCreateIndex( "Test", "NUMBER", ; //// {|| oProgress:increment(), NUMBER } ) //// SET INDEX TO Test //// //// //// WAIT "Index wird neu erzeugt. Anzeige erfolgt in kleinem ProgressBar." //// oProgress:current := 1 //// oProgress:color := GRA_CLR_PINK //// oProgress:setSize( {120,12} ) //// //// DbCreateIndex( "Test", "NUMBER", ; //// {|| oProgress:increment(), NUMBER } ) //// //// SET INDEX TO Test //// WAIT "Die n„chste Taste beendet das Programm" //// oProgress:destroy() //// ////RETURN //// ////#endif // DEBUG //// /* * Klasse fr eine Fortschrittsanzeige */ CLASS ProgressBar FROM XbpStatic, Signal, Thread PROTECTED: VAR squares, every, _current METHOD displayHoriz, displayVert EXPORTED: VAR maxWait, color VAR minimum, current, maximum ASSIGN METHOD minimum, current, maximum METHOD init , create , destroy , setSize METHOD display, execute, increment ENDCLASS /* * Objekt initialisieren und Thread:interval() auf 0 setzen. * Dadurch wird :execute() automatisch wiederholt ausgefhrt. */ METHOD ProgressBar:init( oParent, oOwner, aPos, aSize, aPP, lVisible ) ::Thread:init() ::Thread:setInterval( 0 ) ::Thread:atStart := {|| ::xbpStatic:show() } ::Signal:init() ::xbpStatic:init( oParent, oOwner, aPos, aSize, aPP, lVisible ) ::xbpStatic:type := XBPSTATIC_TYPE_RAISEDBOX ::xbpStatic:paint := {|| ::display() } ::color := GRA_CLR_BLUE ::squares := 1 ::current := 0 ::every := 1 ::maxWait := 100 ::minimum := 0 ::maximum := 100 RETURN /* * Systemresourcen anfordern, Anzahl der Quadrate berechnen (:squares), * die in den ProgressBar hineinpassen und Thread starten. */ METHOD ProgressBar:create( oParent, oOwner, aPos, aSize, aPP, lVisible ) ::xbpStatic:create( oParent, oOwner, aPos, aSize, aPP, lVisible ) aSize := ::currentSize() ::squares := Int( aSize[1] / (aSize[2]+1) ) ::start() RETURN /* * Thread vom ProgressBar stoppen und Systemresourcen freigeben */ METHOD ProgressBar:destroy /* * Automatische Wiederholung von :execute() abschalten. */ ::thread:setInterVal( NIL ) IF ::thread:active /* * Thread ist noch aktiv. * Signal ausl”sen, damit :wait() verlassen wird. */ ::signal() ENDIF IF ThreadObject() <> ::thread /* * Der aktuelle Thread ist nicht der Thread von ProgressBar (self). * Daher muá der aktuelle Thread auf das Ende von self:thread * warten. */ ::thread:synchronize(0) ENDIF /* * Systemresourcen werden nach dem Ende von self:thread freigegeben */ ::xbpStatic:destroy() RETURN self /* * Gr”áe vom ProgressBar „ndern und zuvor alles mit der * Hintergrundfarbe bermalen. */ METHOD ProgressBar:setSize( aSize ) LOCAL oPS, aAttr[ GRA_AA_COUNT ], _aSize oPS := ::lockPS() _aSize := ::currentSize() _aSize[1] -= 2 _aSize[2] -= 2 aAttr [ GRA_AA_COLOR ] := GRA_CLR_BACKGROUND GraSetAttrArea( oPS, aAttr ) GraBox( oPS, {1,1}, _aSize, GRA_FILL ) ::unlockPS( oPS ) ::xbpStatic:setSize( aSize ) RETURN self /* * ASSIGN Methode fr :minimum */ METHOD ProgressBar:minimum( nMinimum ) IF ::maximum <> NIL .AND. nMinimum > ::maximum ::minimum := ::maximum ::maximum := nMinimum ELSE ::minimum := nMinimum ENDIF ::current := ::minimum RETURN self /* * ASSIGN Methode fr :current */ METHOD ProgressBar:current( nCurrent ) IF Valtype( nCurrent ) == "N" ::current := nCurrent IF Valtype( ::maximum ) + Valtype( ::minimum ) == "NN" ::every := Int( ( ::maximum - ::minimum ) / ::squares ) ::_current := ::current ENDIF ENDIF RETURN ::current /* * ASSIGN Methode fr :maximum */ METHOD ProgressBar:maximum( nMaximum ) IF ::minimum <> NIL .AND. nMaximum < ::minimum ::maximum := ::minimum ::minimum := nMaximum ELSE ::maximum := nMaximum ENDIF ::current := ::minimum RETURN self /* * Aktuellen Wert inkrementieren und gegebenenfalls * die Anzeige aktualisieren */ METHOD ProgressBar:increment( nIncrement ) IF Valtype( nIncrement ) <> "N" nIncrement := 1 ENDIF /* * W„hrend der Fortschrittsanzeige wird PROTECTED VAR :_current * inkrementiert, um den Overhead der ASSIGN Methode :current() * zu umgehen. */ ::_current += nIncrement IF Int( ::_current % ::every ) == 0 /* * Dies unterbricht die ::wait( ::maxWait ) Methode in :execute(). * ProgressBar wird dann sofort in seinem eigenen Thread aktualisiert. * Da die Anzeige in einem separaten Thread erfolgt, wird der aktuelle * Prozess, dessen Fortschritt visualisiert wird, nicht durch die * Anzeige verlangsamt. Wird beispielsweise eine Index-Datei erzeugt, * so wird die Anzeige nicht in dem Thread aktualisiert, in dem der * Index generiert wird. Vielmehr wird lediglich ein Signal fr * self:thread ausgel”st. */ ::signal() ENDIF RETURN /* * ProgressBar automatisch alle ::maxWait / 100 Sekunden anzeigen. * Die Methode wird in self:thread ausgefhrt und wird automatisch * wiederholt, da :setInterval() auf Null gesetzt ist. */ METHOD ProgressBar:execute ::wait( ::maxWait ) ::display() RETURN self /* * Aktuellen Status eines fortlaufenden Prozesses visualisieren */ METHOD ProgressBar:display LOCAL oPS := ::lockPS() LOCAL aSize := ::currentSize() LOCAL aAttr [ GRA_AA_COUNT ] aSize[1] -= 2 aSize[2] -= 2 IF aSize[1] > aSize[2] ::displayHoriz( oPS, aSize, aAttr ) ELSE ::displayVert ( oPS, aSize, aAttr ) ENDIF ::unlockPS( oPS ) RETURN self /* * Quadrate von links nach rechts anzeigen (horizontale Anzeige) */ METHOD ProgressBar:displayHoriz( oPS, aSize, aAttr ) LOCAL nX, aPos1, aPos2, nCenter /* * Maximale X Koordinate fr Quadrate */ nX := aSize[1] * ::_current / ( ::maximum - ::minimum ) nX := Min( nX, aSize[1] ) /* * Bereich rechts von den Quadraten mit Hintergrundfarbe fllen */ aAttr [ GRA_AA_COLOR ] := GRA_CLR_BACKGROUND GraSetAttrArea( oPS, aAttr ) GraBox( oPS, {1+nX,1}, {aSize[1],aSize[2]}, GRA_FILL ) /* * Fllfarbe fr die Quadrate definieren */ aAttr [ GRA_AA_COLOR ] := ::color GraSetAttrArea( oPS, aAttr ) /* * Position fr erstes (linkes) Quadrat berechnen */ aPos1 := { 2, 2 } ::squares := Int( aSize[1] / (aSize[2]+1) ) nCenter := 2 + ( aSize[1] - (::squares * (aSize[2]+1)) ) / 2 aPos1[1] := Max( 2, nCenter ) aPos2 := { aPos1[1]+aSize[2]-2 , aSize[2]-1 } /* * Quadrate zeichnen */ DO WHILE aPos2[1] < nX GraBox( oPS, aPos1, aPos2, GRA_FILL ) aPos1[1] += aSize[2]+1 aPos2[1] += aSize[2]+1 ENDDO IF aPos2[1] < aSize[1] GraBox( oPS, aPos1, aPos2, GRA_FILL ) ENDIF RETURN self /* * Quadrate von unten nach oben anzeigen (vertikale Anzeige) */ METHOD ProgressBar:displayVert( oPS, aSize, aAttr ) LOCAL nY, aPos1, aPos2, nCenter /* * Maximale Y Koordinate fr Quadrate */ nY := aSize[2] * ::_current / ( ::maximum - ::minimum ) nY := Min( nY, aSize[2] ) /* * Bereich oberhalb der Quadrate mit Hintergrundfarbe fllen */ aAttr [ GRA_AA_COLOR ] := GRA_CLR_BACKGROUND GraSetAttrArea( oPS, aAttr ) GraBox( oPS, {1,nY}, {aSize[1],aSize[2]}, GRA_FILL ) /* * Fllfarbe fr die Quadrate definieren */ aAttr [ GRA_AA_COLOR ] := ::color GraSetAttrArea( oPS, aAttr ) /* * Position fr erstes (unterstes) Quadrat berechnen */ aPos1 := { 2, 2 } ::squares := Int( aSize[2] / (aSize[1]+1) ) nCenter := 2 + (aSize[2] - (::squares * (aSize[1]+1)) ) / 2 aPos1[2] := Max( 2, nCenter ) aPos2 := { aSize[1]-1, aPos1[2]+aSize[1]-2 } /* * Quadrate zeichnen */ DO WHILE aPos2[2] < nY GraBox( oPS, aPos1, aPos2, GRA_FILL ) aPos1[2] += aSize[1]+1 aPos2[2] += aSize[1]+1 ENDDO IF aPos2[2] < aSize[2] GraBox( oPS, aPos1, aPos2, GRA_FILL ) ENDIF RETURN self