Array browsen mit Checkbox

Moderator: Moderatoren

Antworten
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Array browsen mit Checkbox

Beitrag von Ewald »

Moin zusammen,
ich habe mich noch mal von der Couch erhoben und feile an ein paar Feinheiten ;-)
Das Einblenden des Check-Kästchens im Browse ist ja eine so schöne Sache, das ich da einfach nicht drauf verzichten will. Dabei stoße ich aber auf zwei Probleme, die ich nicht so richtig in den Griff bekomme.

Das erste Problem ist, das es einen Crash gibt, wenn das zu browsende Array leer ist. Das kann ja im Programmverlauf immer wieder auftreten und führt ohne diesen Code für die Checkbox nicht zu Problemen.
Klar, aa[nkey,16] usw. wird gesucht und wenn es das nicht gibt kracht es.
Im Moment durchforste ich die Quellcodes wo das vorkommen kann und belege das Array mit einem Dummy Element vor. Eine schlechte Lösung.
Besser wäre es, wenn ich diese Zeile inaktiv stellen könnte wenn das Array leer ist. Aber wo und wie kann ich das machen ???

Und das zweite Problem ist, das ich mich irgendwie nicht gegen einen Mausklick wehren kann. In diesem Beispiel sollte die Checkbox nur gewählt werden können, wenn das 7. Element des Arrays leer ist. Wenn ich das
aber richtig sehe, hat protect keine Auswirkungen auf Mausklicks. Selbst wenn ich nur ein pures (edit)protect {||.t.} einfüge kann ich die Checkbox trotzdem anklicken und aktivieren.

Bin wie immer für jeden Tip dankbar.
Ewald

Code: Alles auswählen

asize(aa,0)
aadd(aa,{NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL,.f.})  // Das will ich eigentlich nicht machen

@ 05.5,00 dcbrowse ob1 data aa size 100,28 fit ;
          pointer nkey ;
          mark 16 ;
          MKCOLOR nil,GRA_CLR_WHITE,GRA_CLR_BLUE

DCBROWSECOL DATA {|x|x:=DC_GetColArray(16,ob1), ;
      IIF(x,BITMAP_CHECKBOX_CHECKED_S,BITMAP_CHECKBOX_UNCHECKED_S)} ;
      PARENT ob1 HEADER 'Sel' WIDTH 1 ;
      TYPE XBPCOL_TYPE_BITMAP ;
      EVAL {|oB|oB:dataArea:lbClick := {|a,b,o|IIF(ob1:colPos=16,(aa[nkey,16]:=!aa[nkey,16],ob1:refreshCurrent()),nil)}} ;
      protect {||if(!empty(DC_GetColArray(07,ob1)),.t.,.f.)}  
Benutzeravatar
Wolfgang Ciriack
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2932
Registriert: Sa, 24. Sep 2005 9:37
Wohnort: Berlin
Hat sich bedankt: 13 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Wolfgang Ciriack »

Zu 2.: Würde ich mal so probieren:

Code: Alles auswählen

DCBROWSECOL DATA {|x|x:=DC_GetColArray(16,ob1), ;
      IIF(x,BITMAP_CHECKBOX_CHECKED_S,BITMAP_CHECKBOX_UNCHECKED_S)} ;
      PARENT ob1 HEADER 'Sel' WIDTH 1 ;
      TYPE XBPCOL_TYPE_BITMAP ;
      EVAL {|oB|oB:dataArea:lbClick := {|a,b,o|IIF(ob1:colPos=16 .and. !empty(DC_GetColArray(07,ob1),(aa[nkey,16]:=!aa[nkey,16],ob1:refreshCurrent()),nil)}} 
Viele Grüße
Wolfgang
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Ewald »

Hallo Wolfgang,
erst mal danke für den Tip. Der funktioniert so.
Ich hatte aber trotzdem schon an meinem Verstand gezweifelt. Wirklich keine IIF-Verschachtelung die ich nicht ausprobiert habe - und trotzdem konnte man die Checkbox immer noch aktivieren.
Schließlich und endlich lag das Problem aber nicht in der Browserzeile sondern im Browse-Object selbst.
Wenn man da den mark Parameter setzt kann man in den Quellcode der Zeile reinschreiben was man will. Ein Klick in die Zeile setzt dann auch den Haken und wechseln auf .t. - trotz if if and when.

Code: Alles auswählen

@ 05.5,00 dcbrowse ob1 data aa size 100,28 fit ;
          pointer nkey ;
          mark 16 ;             <---------- da ist der böse Bube 
          MKCOLOR nil,GRA_CLR_WHITE,GRA_CLR_BLUE
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Tom »

Zum ersten Problem: DC_GetColArray() kann zwar mit der Situation umgehen, dass das Array leer ist, retourniert dann aber immer einen String. Ich habe schon einen Parameter für die Funktion angeregt (Default), aber das hat Roger noch nicht umgesetzt. Also gibt es zwei Lösungen:

x:=DC_GetColArray(16,ob1), ;
IIF(ValType(x)=='L' .AND. x,BITMAP_CHECKBOX_CHECKED_S,BITMAP_CHECKBOX_UNCHECKED_S)

oder

x:=DC_GetColArray(16,ob1), ;
IIF(Len(aa) > 0 .AND. x,BITMAP_CHECKBOX_CHECKED_S,BITMAP_CHECKBOX_UNCHECKED_S)

Edit: Noch eleganter wäre es, im Fall eines leeren Arrays nix anzuzeigen, also eine leere Bitmap.
Herzlich,
Tom
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Tom »

Ach so: Du musst eigentlich DC_GetColArray(16,oBrowse) nicht in "x" umspeichern.
Herzlich,
Tom
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Ewald »

Hallo Tom,
danke dafür, das war es. Den Knackpunkt habe ich an der Stelle überhaupt nicht vermutet. Man lernt nie aus ;-)
Ich habe mich für die Variante len(aa) entschieden.
Gruß
Ewald
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Tom »

Hallo, Ewald.

Freut mich! :)

Woher soll die Funktion DC_GetColArray() auch wissen, welchen Datentyp Du erwartest, wenn das Array noch leer ist? :wink:

(Keine Sorge, in diese Falle bin ich aber auch schon getapert. :badgrin: )
Herzlich,
Tom
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Ewald »

:shock: :shock: :shock:
Ich hab mein Folgeproblem als lauffähigem Code mal hier angehangen - und wehe jemand lacht ;-)
In diesem Code erzeuge ich ja das Array aa und aus dem Array aa dann das Array ab. Und (fälschlicherweise ?) bin ich bis jetzt davon ausgegangen, das ich 2 verschiedene Arrays im Programm habe.
Die beiden Knöpfe von dc_arrayview() gaukeln mir das ja auch vor.
Jetzt ist mir aber aufgefallen, das alle Änderungen die ich mit diesem Testprogramm im Array aa vornehme sofort mit in das entsprechende Element von Array ab übernommen werden.
Ist das Array ab etwa nur eine Referenz von Array ab ? Was muss ich denn machen, wenn ich diese Referenz nicht will ?

Gruß
Ewald

Code: Alles auswählen

#include "dcdialog.ch"
#include "appevent.ch"
#include "dcbitmap.ch"
#include "DCPRINT.CH"
#include "XBP.CH"

proc main()
LOCAL GetList := {},aa:={},ab:={},nkey:=1,nkey1:=1

aadd(aa,{padr("Mustermann",50),padr("Karl",50)  ,"ja  "})
aadd(aa,{padr("Müller",50),    padr("Johann",50),"ja  "})
aadd(aa,{padr("Osterhase",50), padr("Jupp",50)  ,"nein"})
aadd(aa,{padr("Musterfrau",50),padr("Inge",50)  ,"nein"})
aadd(aa,{padr("Meier",50),     padr("Edit",50)  ,"ja  "})

for xi = 1 to len(aa)
aadd(ab,aa[xi])
next

@ 01,1  dcbrowse ob1 data aa size 100,10 fit ;
        edit xbeBRW_ItemSelected ;
        pointer nkey
          
dcbrowsecol element 1  header "Name"       width 25 parent ob1 ;
                       valid {||ob1:refreshall(),ob2:refreshall()}
dcbrowsecol element 2  header "Vorname"    width 25 parent ob1 ;
                       valid {||ob1:refreshall(),ob2:refreshall()}
dcbrowsecol element 3  header "Akte da"    width  6 parent ob1 ;
                       valid {||ob1:refreshall(),ob2:refreshall()}

@ 12,1  dcbrowse ob2 data ab size 100,10 fit ;
        edit xbeBRW_ItemSelected ;
        pointer nkey
          
dcbrowsecol element 1  header "Name"       width 25 parent ob2 
dcbrowsecol element 2  header "Vorname"    width 25 parent ob2 
dcbrowsecol element 3  header "Akte da"    width  6 parent ob2 

@ 25,0  dcpushbutton caption "Ende " size 10,1 ;
        action {||dc_readguievent(DCGUI_EXIT_OK,Getlist)}

@ 25,12 dcpushbutton caption "Array aa" size 10,1 ;
        action {||dc_arrayview(aa)}

@ 25,23 dcpushbutton caption "Array ab" size 10,1 ;
        action {||dc_arrayview(ab)}

dcread gui fit ;
title "SQL Suche Datenstand aktuell" 

return 

proc appsys
return
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Tom »

Code: Alles auswählen

ab := aClone(aa)
Ergänzung: Ja, durch die Zuweisung ":=" erzeugt man im Fall von Arrays keine Kopie, sondern tatsächlich nur eine Referenz. Das ist einerseits zuweilen ganz schick (wenn man etwa in abgeleiteten Browse-Klassen auf die Datenquelle zugreifen möchte, ohne mit PUBLICs oder PRIVATEs hantieren zu müssen), andererseits aber auch gefährlich, denn die Änderung an der vermeintlichen Kopie wirkt sich auf das Original aus - und umgekehrt. Deshalb ist beim Kopieren "aClone()" zu verwenden.
Herzlich,
Tom
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Ewald »

Gran malör dü kack ...
Das gesamte Array kopieren habe ich nur für das Testprogramm gemacht. Eigentlich will ich im ersten Browse eine Zeile markieren (Checkbox) und dieses Element soll dann in das zweiter Array übernommen werden. (Wenn es noch nicht drin ist.) Das habe ich mit dieser Funktion gemacht. Element 16 ist eine eindeutige Nummer. Element 1 ist die Checkbox. Da bekomme ich aclone ja nicht reingebastelt. Oder muss ich da wohl noch schlussendlich ein ac:=aclone(ab) ins Spiel bringen ?
Gruß
Ewald

Code: Alles auswählen

function fwahl(xlist)
local ff:=ascan(ab,{|xa|xa[16]=aa[nkey,16]})
if (empty(ff)) .and. aa[nkey,1]
aadd(ab,aa[nkey])
endif

ob2:refreshall()
return .t.
Benutzeravatar
Wolfgang Ciriack
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2932
Registriert: Sa, 24. Sep 2005 9:37
Wohnort: Berlin
Hat sich bedankt: 13 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von Wolfgang Ciriack »

Code: Alles auswählen

aadd(ab,Aclone(aa[nkey]))
Viele Grüße
Wolfgang
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15689
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Array browsen mit Checkbox

Beitrag von brandelh »

Hierzu ist es wichtig zu verstehen, wie Xbase++ Arrays verwaltet.

Code: Alles auswählen

a := { 1, 2, 3 }
enthält a 3 einzelne Werte.

Code: Alles auswählen

a := { {1,2,3}, {2,3,4}, {3,4,5} }
enthält a 3 Referenzen auf je 3 Array Variablen.

a[1] enthält somit eine Referenz auf das Array mit 3 Werten: {1,2,3}

Code: Alles auswählen

b := a
b ist eine eigene Variable, die den Inhalt von a erhält, der INHALT ist nun aber genau die Referenz von a

Code: Alles auswählen

b := aclone(a) 
b ist eine eigene Variable, die den Inhalt von a erhält, wobei die INHALTE der alten Referenzen umkopiert werden und somit neue Referenzen enthalten sind.
eine Änderung in b wird sich somit nichtmehr auf die Inhalte von a auswirken.

Deine Aufgabe ...

aa ist das Datenarray des Browsers ...

Eine Zeile daraus:

Code: Alles auswählen

aa[ nAktiveZeile ]
ist eine Referenz auf die Originalwerte der Daten.

Code: Alles auswählen

aclone( aa[ nAktiveZeile ] )
liefert eine Kopie der Daten in ein neues Array, welches in einem Funktionsaufruf bb heisen könnte.

Beispiel

Code: Alles auswählen

oBrowser:itemSelected := {| u1, u2, oB | AktionFuerEineZeile( aclone( aa[ oB:PhyPosBlock ] ) )  } // Array Index = oB:PhyPosBlock

function AktionFuerEineZeile( bb ) // bb soll eine neue Kopie der Datenzeile liefern.
oder einfacher zu debuggen ...

Code: Alles auswählen

oBrowser:itemSelected := {| u1, u2, oB | AktionFuerEineZeile( oB, aa ) }

function AktionFuerEineZeile( oB, aa ) // oB ist eine Referenz auf das Browse Objekt, aa auf die Daten
    local i, bb
    i := oB:PhyPosBlock
    if i >= 0 .and. i <= len(aa) // Sicherstellen dass es die Datenzeile gibt ... sollte unnötig sein
       bb := aclone( aa[ i ] )
...  
oB:getData() könnte auch die Daten einer Zeile zurückgeben, aber es ist vom Cursortyp abhängig
Gruß
Hubert
Antworten