Array browsen mit Checkbox

Moderator: Moderatoren

Array browsen mit Checkbox

Beitragvon Ewald » Di, 02. Feb 2016 16:35

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
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 398
Registriert: Sa, 08. Apr 2006 13:07
Wohnort: Datteln

Re: Array browsen mit Checkbox

Beitragvon Wolfgang Ciriack » Di, 02. Feb 2016 20:12

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
Benutzeravatar
Wolfgang Ciriack
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 2220
Registriert: Sa, 24. Sep 2005 8:37
Wohnort: Berlin

Re: Array browsen mit Checkbox

Beitragvon Ewald » Mi, 03. Feb 2016 14:56

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
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 398
Registriert: Sa, 08. Apr 2006 13:07
Wohnort: Datteln

Re: Array browsen mit Checkbox

Beitragvon Tom » Mi, 03. Feb 2016 15:16

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: 6680
Registriert: Do, 22. Sep 2005 22:11
Wohnort: Berlin

Re: Array browsen mit Checkbox

Beitragvon Tom » Mi, 03. Feb 2016 15:19

Ach so: Du musst eigentlich DC_GetColArray(16,oBrowse) nicht in "x" umspeichern.
Herzlich,
Tom
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 6680
Registriert: Do, 22. Sep 2005 22:11
Wohnort: Berlin

Re: Array browsen mit Checkbox

Beitragvon Ewald » Mi, 03. Feb 2016 15:32

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
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 398
Registriert: Sa, 08. Apr 2006 13:07
Wohnort: Datteln

Re: Array browsen mit Checkbox

Beitragvon Tom » Mi, 03. Feb 2016 15:37

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
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 6680
Registriert: Do, 22. Sep 2005 22:11
Wohnort: Berlin

Re: Array browsen mit Checkbox

Beitragvon Ewald » Mi, 03. Feb 2016 22:29

: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
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 398
Registriert: Sa, 08. Apr 2006 13:07
Wohnort: Datteln

Re: Array browsen mit Checkbox

Beitragvon Tom » Mi, 03. Feb 2016 22:51

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
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 6680
Registriert: Do, 22. Sep 2005 22:11
Wohnort: Berlin

Re: Array browsen mit Checkbox

Beitragvon Ewald » Mi, 03. Feb 2016 23:30

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
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 398
Registriert: Sa, 08. Apr 2006 13:07
Wohnort: Datteln

Re: Array browsen mit Checkbox

Beitragvon Wolfgang Ciriack » Do, 04. Feb 2016 7:21

Code: Alles auswählen
aadd(ab,Aclone(aa[nkey]))
Viele Grüße
Wolfgang
Benutzeravatar
Wolfgang Ciriack
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 2220
Registriert: Sa, 24. Sep 2005 8:37
Wohnort: Berlin

Re: Array browsen mit Checkbox

Beitragvon brandelh » Do, 04. Feb 2016 7:25

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
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
 
Beiträge: 13273
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim


Zurück zu eXpress++

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste