XbpBrowse

Grafische Primitive, XbaseParts und Darstellungsfragen allgemein.

Moderator: Moderatoren

Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

XbpBrowse

Beitrag von Jan »

Ich habe gerade die Aufgabe bekommen, einen Browse zu bauen. Darin soll eine Protokolldatei angezeigt werden. Um Unterschiede besser darzustellen sollen immer die Felder, die sich gegenüber dem Vorsatz geändert haben, eingefärbt werden.

Nun ist es überhaupt kein Problem, einzelne Sätze oder Felder in einem XbpBrowse einzufärben. Sowas mache ich häufig. Aber da ist die Bedingung immer eindeutig auf einen Wert in dem betreffenden Satz bezogen. Wie bekomme ich das hin, das diese Bedingung sich auf den vorigen Satz bezieht? Ich kann ja nicht dauernd rumskippen beim Anzeigen des Browses. Aber vielleicht den Wert des Browse-Feldes davor auslesen? Keine Ahnung ...

Wobei ich nicht die gesamte dbf im Browse anzeige. Sondern nur per Scope ausgefilterte Sätze.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15696
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von brandelh »

Musst du das geänderte Feld hervorheben oder nur die Zeile mit Änderungen ?

Auf jeden Fall musst du die Werte und Vergleiche ermitteln und dann dieses Ergebnis (Array) für Farbanzeige nutzen, beim Skippen das jedesmal zu machen geht nicht (viel zu langsam).
Was mich eher wundert ist die Frage ob die geänderten Daten zum letzten Satz oder im gleichen Satz gemeint sind (also welche die überschrieben wurden) ?
Gruß
Hubert
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

hallo Hubert,

das ist eine dbf, in der jedes Mal, wenn ein Satz in einer anderen dbf geändert wurde, der alte Satz in der Protokolldatei angehängt wird. Es wird also eine Historie der Änderungen protokolliert. Und damit man in dem Browse auf diesem Protokoll sofort sieht, welches Feld genau sich geändert hat, soll dieses farbig hinterlegt werden.

Ich habe ein wenig mit :rowPos und :getRow gespielt, das Ergebnis ist aber nicht sonderlich prickelnd.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9361
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Tom »

Der harte Weg:

Code: Alles auswählen

oColumn:ColorBlock := {||If(SameData(cFieldName,cAlias),ColorSame(),ColorDifferent())}

FUNCTION SameData(cFieldName,cAlias)
LOCAL xData := (cAlias)->FieldGet((cAlias)->FieldPos(cFieldName), nRec := (cAlias)->(RecNo()), lSame := .T.
(cAlias)->(DbSkip(-1))
IF (cAlias)->(RecNo()) # nRec .and. (cAlias)->FieldGet((cAlias)->FieldPos(cFieldName) # xData
  lSame := .F.
ENDIF
IF (cAlias)->(RecNo()) # nRec
  (cAlias)->(DbGoto(nRec))
ENDIF
RETURN lSame
Ins Blaue getippt und nicht getestet.

Der weichere Weg geht über Ownerdrawing. Da holt man sich einfach über GetCell( aInfo[XBP_DRAWINFO_ITEM] ) den Wert der aktuellen und über XBP_DRAWINFO_ITEM-1 den vorigen Zellenwert und vergleicht sie. Dann setzt man über oPS:SetColor() die Farben, feddisch. Das ist auch am schnellsten, weil man keine Tabellenbewegungen braucht. So ähnlich kann man auch im ColorBlock arbeiten, aber das ist ein wenig komplizierter.
Herzlich,
Tom
hschmidt
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 164
Registriert: Mo, 09. Jan 2006 17:06
Wohnort: Paderborn
Hat sich bedankt: 2 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von hschmidt »

Hallo Jan,

wenn Du für die BrowseColumn eine Colorblock-Methode definierst, z.B.

Code: Alles auswählen

    ::colorblock    := {|xValue,a,nRow|self:SetCellColor (xValue,a,nRow)}
kannst Du in der Methode über

Code: Alles auswählen

::DataArea:getCellColor(MAX(nRow -1,1))
den Inhalt der vorherigen Zelle ermitteln. Wenn dieser ungleich xValue ist, muss eine andere Farbe gesetzt werden.

Viele Grüße

Hans
hschmidt
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 164
Registriert: Mo, 09. Jan 2006 17:06
Wohnort: Paderborn
Hat sich bedankt: 2 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von hschmidt »

Hallo,

Code: Alles auswählen

::DataArea:getCellColor(MAX(nRow -1,1))


ist falsch. Es muss

Code: Alles auswählen

::DataArea:getCell(MAX(nRow -1,1))
heißen.
Mit GetcellColor kann man die Farbe einer Zelle ermitteln, mit GetCell den Inhalt....

Viele Grüße

Hans
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9361
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Tom »

Und wo kriegst Du "nRow" her?
Herzlich,
Tom
hschmidt
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 164
Registriert: Mo, 09. Jan 2006 17:06
Wohnort: Paderborn
Hat sich bedankt: 2 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von hschmidt »

aus dem Parameter meiner SetCellColor-Methode....
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

Tom,

das hatte ich mich auch gefragt. In der Doku gibt es eine ganze Menge Funktionen, die als Parameter nRow haben möchten. Aber wo ich das herbekomme steht nirgends. Ich hab dann voller Verzeweiflung einfach oBrows:rowPos genommen. Was auch irgendwie funktioneirt.

Problem: Lt. Doku hat :colorblock nur eine Übergabe, nämlich |xValue|. Nix nRow. Mag ja aber undokumentiert sein, muß ich mal probieren.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
hschmidt
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 164
Registriert: Mo, 09. Jan 2006 17:06
Wohnort: Paderborn
Hat sich bedankt: 2 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von hschmidt »

Jan hat geschrieben: Problem: Lt. Doku hat :colorblock nur eine Übergabe, nämlich |xValue|. Nix nRow. Mag ja aber undokumentiert sein, muß ich mal probieren.

Jan
Ja, das ist tatsächlich nicht dokumentiert. Funktioniert aber. Ich arbeite schon ewig mit dieser Mimik.

Hans
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9361
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Tom »

RowPos liefert den Cursor. Das ist ohnehin keine sehr verlässliche Information. Man kann auch mit CellFromPos und ähnlichem hantieren, aber am schönsten und verlässlichsten geht's entweder über eine skippende Funktion (siehe Beispiel) oder eben Ownerdrawing. Da weiß ich nämlich immer, in welcher Zelle ich stehe, und kann auf die jeweils vorige oder folgende zugreifen.
Herzlich,
Tom
hschmidt
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 164
Registriert: Mo, 09. Jan 2006 17:06
Wohnort: Paderborn
Hat sich bedankt: 2 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von hschmidt »

Hallo Tom,
Tom hat geschrieben:RowPos liefert den Cursor. Das ist ohnehin keine sehr verlässliche Information. Man kann auch mit CellFromPos und ähnlichem hantieren, aber am schönsten und verlässlichsten geht's entweder über eine skippende Funktion (siehe Beispiel) oder eben Ownerdrawing. Da weiß ich nämlich immer, in welcher Zelle ich stehe, und kann auf die jeweils vorige oder folgende zugreifen.
meine Methode hat nichts mit der Cursorposition zu tun, sondern liefert direkt den Inhalt der vorherigen Zelle zurück.
Man muss nur aufpassen, dass man nicht in der ersten Zeile steht, deshalb der Ausdruck

Code: Alles auswählen

MAX(nRow -1,1)
Viele Grüße

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

Re: XbpBrowse

Beitrag von brandelh »

Dann reicht ein Array mit geänderter Feldnummer !

Code: Alles auswählen

aSatzPuffer := {} // Inhalt des letzten Satzes
aSatzTemp := {}
aSatzInfo := {} // je Satz ein Array mit den FeldPos() Infos der geänderten Daten ... 
nFeldAnz := fcount()

go top
IsErsterSatz := .t.
do while .t.
   if IsErsterSatz
      IsErsterSatz := .f.
      aSatzInfo := { { } } // erster Satz in Infoliste hat keine Änderungen
   else
      aSatzTemp := {}
      for x := 1 to nFeldAnz
         if fieldget(x) # aSatzPuffer[x]
            aadd(aSatzTemp,x) // geändertes Feld merken, nur diese hervorheben
         endif
      next       
      aadd(aSatzInfo,aSatzTemp)
   endif
   aSatzPuffer := scatter() // ganzen Satz merken
   dbSkip()
endif
aSatzInfo[x] entspricht dem Datensatz recno() ... ich vermute kein Index
aSatzInfo[x] => leeres Array ... keine Änderung
aSatzInfo[x][x ... n] FieldPos() des geänderten Feldes, dieses musst du einfärben

Dieses Array muss nun die Änderungsinfos liefern, ohne Index einfach RecNo() nutzen.

Mehr Platz würde es benötigen, wenn für jedes Feld ein logischer Wert hinterlegt ist, eventuell wäre das aber einfacher.
Auf jeden Fall, muss die Info nur einmal ermittelt werden und bei neuen Sätzen eventuell diese anhängen.
Des Browse selbst greift auf die Array-Werte zu, wählt so die Farbe und das sollte schnell gehen.
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9361
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Tom »

Ich habe gerade den von Hans empfohlenen Weg ausprobiert. Direkt im ColorBlock die Zelleninhalte zu vergleichen ist am elegantesten und am schnellsten. Es gleicht im Prinzip dem Weg über das Ownerdrawing

Code: Alles auswählen

::ColorBlock := {|x,a,n|IF(n>1.AND.oColumn:DataArea:GetCell(n-1)==x,SameColor(),DifferentColor())}
Herzlich,
Tom
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

Hallo Tom,

ich bastele gerade an Deinem Beispiel rum. Nachdem ich ein paar Dutzend klammern nachgeführt habe :-) sieht das schon sehr gut aus.

Der Punkt ist, das die dbf nicht sehr groß ist. Ca. 1.500 Sätze. Da kann ich mir das viele Skippen erlauben, ich seh da bislang keine Geschwindigkeitseinbußen.

Ich muß aber noch ein wenig dran feilen, ein paar kleine Macken hat das Teil noch.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15696
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von brandelh »

Tom hat geschrieben:Ich habe gerade den von Hans empfohlenen Weg ausprobiert. Direkt im ColorBlock die Zelleninhalte zu vergleichen ist am elegantesten und am schnellsten. Es gleicht im Prinzip dem Weg über das Ownerdrawing

Code: Alles auswählen

::ColorBlock := {|x,a,n|IF(n>1 .AND. oColumn:DataArea:GetCell(n-1)==x ,SameColor(),DifferentColor())}
das finde ich mal genial ! Die gepufferten Werte des Brose verwenden ...

Skippen in der DBF mit aktivem XbpBrowse() kann aber Ärger machen ;-)
Gruß
Hubert
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

Hallo Tom,

wie bekommst Du das ans Laufen? Ich bekomme immer einen Laufzeitfehler
------------------------------------------------------------------------------
oError:args :
-> VALTYPE: C VALUE:
-> VALTYPE: N VALUE:0
oError:canDefault : .F.
oError:canRetry : .F.
oError:canSubstitute: .T.
oError:cargo : NIL
oError:description : Parameter hat falschen Typ
oError:filename :
oError:genCode : 2
oError:operation : < >==<0>
oError:osCode : 0
oError:severity : 2
oError:subCode : 3
oError:subSystem : BASE
oError:thread : 1
oError:tries : 0
das scheint von dem Vergleich oColumn:DataArea:GetCell(n-1)==x auszugehen.

Jan
Tom hat geschrieben:Ich habe gerade den von Hans empfohlenen Weg ausprobiert. Direkt im ColorBlock die Zelleninhalte zu vergleichen ist am elegantesten und am schnellsten. Es gleicht im Prinzip dem Weg über das Ownerdrawing

Code: Alles auswählen

::ColorBlock := {|x,a,n|IF(n>1.AND.oColumn:DataArea:GetCell(n-1)==x,SameColor(),DifferentColor())}
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15696
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 66 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von brandelh »

vermutlich werden intern alle Werte als String gespeichert, also besser direkt die Zellen vergleichen:

Code: Alles auswählen

::ColorBlock := {|x,a,n|IF(n>1 .AND. oColumn:DataArea:GetCell(n-1)==oColumn:DataArea:GetCell(n),SameColor(),DifferentColor())}
Gruß
Hubert
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

Hubert,

jupp, so klappt es ohne Fehlermeldung.

Ich habe jetzt aber noch zwei Probleme:

1) Korrekt wird nur die letzte Spalte des Browses angezeigt. Alle anderen Spalten werden immer in allen Reihen als geändert markiert.

2) Scrolle ich hoch sind immer alle Zellen als geändert markiert, auch die, die in der letzten Spalte beim Runterscrollen noch korrekt dargestellt wurden. Ds gilt immer dann, wenn ich über die erste angezeigte Reihe hochscrolle.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

So sieht beim Code im Moment aus:

Code: Alles auswählen

FOR i := 1 TO Len(aWalaStruktur)
    oSpalte := XBPColumn():new(oDlgAppWalasi, , , , {{XBP_PP_COL_HA_CAPTION, aWalaStruktur[i][1]}, ;
                                                     {XBP_PP_COL_DA_ROWWIDTH, aWalaStruktur[i][3] * 8}}) // Eine neue Spalte hinzufügen

    oSpalte:ColorBlock := {|x, a, n| IIF(n > 1 .AND. oSpalte:DataArea:GetCell(n - 1) == oSpalte:DataArea:GetCell(n), ;
                                         {GRA_CLR_BLACK, GRA_CLR_BACKGROUND}, ;
                                         {GRA_CLR_WHITE, GRA_CLR_BLUE})}

    oSpalte:dataLink := &("{|x| walasi->" + aWalaStruktur[i][1] + "}")                             // Den Datalink auf das Feld stellen
    oSpalte:create()                                                                               // Das Objekt erstellen

    oBrowseProtokollWala:addColumn(oSpalte)                                                        // Die Spalte dem Browse hinzufügen
NEXT
Wie üblich bei mir nix Klassen ;-)

aWalaStruktur ist aus DbStruct().

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9361
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Tom »

Das liegt daran, dass Du "oSpalte" im ColorBlock referenzierst. Das wäre dann immer nur die letzte Spalte.
Herzlich,
Tom
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

OK, Problem 1 ist behoben. Wie schon gedacht liegt das Problem darin, das oSpalte nach dem Durchlauf natürlich immer die letzte Spalte darstellt. Ich hab mal einfach ins blaue oSpalte: im Codeblock durch a: ersetzt - und siehe da, richtig geraten. Alle Spalten werden korrekt angezeigt.

Aber das hochscrollen klappt noch immer nicht.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9361
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Tom »

Das liegt daran, dass das von Hans gefundene "n" als ColorBlock-Parameter die Zeilenposition bezogen auf die Anzeige enthält, nicht jedoch die absolute Position innerhalb der Tabelle. Die oberste Zeile ist immer Zeile 1. Man müsste ein bisschen tricksen, um das hinzukriegen. GetCell liefert auch nur sichtbare Zellen, weshalb es als Parameter ebenfalls die Ordinalposition bekommt - und nicht die absolute. So oder so, vermutlich ist die Lösung mit dem Skippen dann doch besser.
Herzlich,
Tom
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14653
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: XbpBrowse

Beitrag von Jan »

So. Ich habe in den :stableBlock reingebaut, das der nach jedem Skip nach Oben ein RefreshAll machen soll. Das dauert zwar ein wenig, aber es funktioniert relativ gut.

Auf jeden Fall Euch allen vielen Dank für die interessante und vielseitige Dikussion, ich hätte nicht gedacht daß das dermaßen viele Ansichten und Ideen dazu gibt.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: XbpBrowse

Beitrag von AUGE_OHR »

Jan hat geschrieben:das ist eine dbf, in der jedes Mal, wenn ein Satz in einer anderen dbf geändert wurde, der alte Satz in der Protokolldatei angehängt wird.
wenn du 2 x DBF hast warum dann nicht 2 x Browse per SET RELATION ( oder mit SEEK() ) dann hast du die "Probleme" nicht.
gruss by OHR
Jimmy
Antworten