Montag, 6. Juni 2016

Forms mal generisch: alle Items eines Blockes verstecken und wieder einblenden

Dieser Beitrag kommt aus der praktischen Arbeit heraus gerade. Der Kunde hat die Anforderung: fast alle Items eines Datenblockes nach Klick auf einer Checkbox ausblenden und wieder einblenden danach. Da ich mir durchaus vorstellen kann, dass das auch woanders vorkommen könnte, möchte ich meine favorisierte Lösung vorstellen.

Die Lösung dazu ist entweder sehr trivial oder mit ein bisschen mehr Invest auch schöner, dafür aber anspruchsvoller umsetzbar.

Meine 1. Idee (trivialer Ansatz) war: alle Items nacheinander mit ihrem Namen ansprechen und dann ausblenden. Einfacher Ansatz, aber viel Tipperei, evtl. ein Item vergessen und Wiederholungen. Und ich stehe ja mehr auf Wiederverwendbarkeit und generische Ansätze.

Code dafür:
pkg_item.verstecken('BLOCK.ITEM1'); bis pkg_item.verstecken('BLOCK.ITEM32');
Dazu sollten auch alle Eingaben gelöscht werden.
:BLOCK.ITEM1 := NULL;

pkg_item.verstecken('BLOCK.ITEM1'); macht einfach
set_item_property ('BLOCK.ITEM1', visible, property_false);

Nun der generische und schönere Ansatz:
1. merken einiger Felder, die immer sichtbar sein sollen:
          v_currentblockp := 'BLOCK.';
          v_ausnahme_felder := v_currentblockp || 'ITEM12 ';
          v_ausnahme_felder := v_ausnahme_felder || v_currentblockp || 'ITEM13 ';

2. den Block durchgehen und alle Felder ausblenden und ggf mit COPY auf NULL setzen:
      LOOP
         v_currentitem2 := get_item_property(v_currentitem,nextitem);
         v_currentitem:= v_currentblockp || v_currentitem2;
         -- Ausstiegskriterium, wenn Current Item leer ist (also nur der Blockname)
         IF v_currentitem = v_currentblockp THEN
              EXIT;
         END IF;   
        
         -- Item darf nicht in der Ausnahmeliste sein(sonst wird es unsichtbar)
         IF INSTR(v_ausnahme_felder, v_currentitem ) = 0 THEN
           IF GET_ITEM_PROPERTY(v_currentitem,visible)= 'TRUE'  THEN
                  -- Felder leeren
                  IF GET_ITEM_PROPERTY(v_currentitem,ITEM_TYPE) IN
                       ('TEXT ITEM', 'LIST',  'DISPLAY_ITEM') THEN
                       COPY(NULL, v_currentitem);
                  END IF;  
                 
                 -- Felder verstecken (unsichtbar machen)                 
              pkg_item.verstecken(v_currentitem);
           END IF;         
         END IF;
      END LOOP;

3. das Sichtbar machen funktioniert ähnlich mit einer Besonderheit: der Block hat auch Felder, die sollen gar nicht sichtbar werden (Control-Items usw.). Um das Ganze mit einer Logik zu versehen, habe ich mir beim Start der Maske alle Felder gemerkt, die dann auch sichtbar sind und nicht zu meinen o.g. Ausnahmen gehören. Danach stehen in der Variable v_filter_items alle Felder, die ich nach einem Ausblenden auch wieder sichtbar machen will.

         IF INSTR(v_ausnahme_felder, v_currentitem ) = 0 THEN
           IF GET_ITEM_PROPERTY(v_currentitem,visible)= 'TRUE'  THEN
                 v_filter_items := v_filter_items || v_currentitem || ' ';
           END IF;         
         END IF;

Jetzt noch der Loop zum Sichtbar machen mit dem Zusatz auch die Felder wieder zu enablen:
     v_currentblockp := 'BLOCK.';
     LOOP
          v_currentitem2 := get_item_property(v_currentitem,nextitem);
         v_currentitem:= v_currentblockp || v_currentitem2;
         -- Ausstiegskriterium, wenn Current Item leer ist (also nur der Blockname)
         IF v_currentitem = v_currentblockp THEN
              EXIT;
         END IF;   
        
         -- Item muss aber in der Liste der sichtbaren Felder sein und nicht in der Ausnahmeliste
         IF  (INSTR(v_filter_items, v_currentitem ) != 0 AND INSTR(v_ausnahme_felder, v_currentitem ) = 0) THEN
           IF GET_ITEM_PROPERTY(v_currentitem,visible)= 'FALSE'  THEN
                  -- Felder wieder anzeigen und enablen
                  pkg_item.zeigen(v_currentitem);
                 
                  IF GET_ITEM_PROPERTY(v_currentitem,ITEM_TYPE) != 'DISPLAY ITEM' THEN
                       pkg_item.enable(v_currentitem);
                  END IF;  
           END IF;         
         END IF;
      END LOOP;

Ein Screenshot von der Maske mit den ausgeblendeten Feldern (diese ist nicht mehr schön, weil sie auch Frames enthält, die aber sichtbar bleiben sollen). Die Schaltflächen und die 4 Eingabefelder (weiß) sind in meinem Beispiel die Ausnahmefelder und von der Logik ausgenommen. Diese layouttechnisch unschöne Lösung war aber kostengünstiger als eine neue Version der Filtermaske.


Wie man erahnen kann, ist diese Lösung universell einsetzbar und auch noch weiter auszubauen. Ich denke daran, z.B. diese Felder konfigurierbar in einem DB-Schema zu speichern vielleicht. Damit wären dann user-spezifische Varianten zu erreichen.

Viele Grüße
Holger