Controls stapeln

Heute ist mir wieder eine kleine Spielerei unter die Finger gekommen, die einerseits wichtige Grundlagen zeigt und andererseits eine nette Spielerei ist, die durchaus einen Nutzwert hat. Es geht um die Anzeige und Steuerung von Controls.

Um ein Control anzeigen zu können, benötigt man einen Container. In diesem Beispiel verwende ich einen Docking-Container.

go_dock = NEW #( side = cl_gui_docking_container=>dock_at_right ratio = 80 ).

In diesen Container hänge ich ein Text-Control.

go_text = NEW #( parent = go_dock ).

Allerdings ist das noch nichts Besonderes.

Controls stapeln

Besonders wird es, wenn ich noch ein ALV-Grid und noch ein Picture-Control in den gleichen Container packe.

" ALV-Grid
go_grid = NEW #( i_parent = go_dock ).
go_grid->set_table_for_first_display(
  EXPORTING i_structure_name = 'T000'
  CHANGING it_outtab = gt_data_alv ).

" Picture
go_pic = NEW cl_gui_picture( parent = go_dock ).

Die Controls sind nun gewissermaßen gestapelt. Sie liegen übereinander in dem Container. Das zuletzt instantiierte Control wird angezeigt. Die anderen Controls sind jedoch noch da! Und sie sind auch nutzbar. Man muss lediglich die jeweils darüber liegenden Controls auf “nicht sichtbar” stellen.

Jedes Control hat die Methode SET_VISIBLE mit der man die Sichtbarkeit eines Controls steuern kann (Vererbung von CL_GUI_CONTROL). Jeder Container hat übrigens ebenfalls diese Eigenschaft (denn auch diese erben von CL_GUI_CONTROL)! Das heißt, es kann auch ein Docking-Container komplett ausgeblendet werden, ohne dass er wirklich “weg” ist.

In seltenen Fällen kann man sich diesen Umstand zu Nutze machen. Bei diesem Trick verwende ich ein ähnliches Verfahren: Werte aus Excel per DOI (unsichtbar). Hier wird nur nicht der Container unsichtbar geschaltet, sondern das Control wird an ein Standard-Dynpro gehängt, dass nicht angezeigt wird.

Man kann also dadurch, dass man nur das gewünschte Control auf “sichtbar” und alle anderen auf “unsichtbar” stellt, zwischen den einzelnen Control hin- und her schalten. Es ist dementsprechend nicht notwendig, das im Container befindliche Control zu zerstören und das neue aufzubauen um einen Wechsel zu realisieren.

Beliebter Fehler

Den Zustand, den ich hier bewusst und mit voller Absicht herbei führe, ist wahrscheinlich schon häufig die Ursache vieler verzweifelter Stunden im Debugger und einiger grauer Haare gewesen. Häufig passiert es nämlich (nicht nur Anfängern, sondern auch Profis!), dass man ein und dasselbe Control mehrfach instantiiert und dem gleichen Container zuordnet. Das macht SAP auch klaglos mit und stellt die neuen Control-Instanzen immer wieder in den Container hinein. Sichtbar ist einzig und allein das zuerst erzeugte Control.

Das ist genau das tückische daran, denn durch diesen Umstand ergeben sich eine Vielzahl von Symptomen, die man sich auch nach stundenlangem Debugging häufig nicht erklären kann:

  • Geänderte Daten werden nicht im ALV-Grid angezeigt
  • Datenänderungen werden vom ALV nicht in die interne Tabelle übernommen
  • Doppelklick funktioniert nicht mehr
  • Änderungen am Control werden nicht sichtbar (geändertes Bild, Icon, aktualisierte Website, …)

Sofern man daran denkt, dass der Fehler einer Mehrfach-Instantiierung vielleicht vorliegen könnte, kann man sehr leicht prüfen, ob das wirklich der Fall ist. Jeder Container hat das Attribut CHILDREN. In dieser Tabelle werden die dem Container zugeordneten Controls verwaltet:

Wenn man in seinem Programm zwar den Container nur einmal erzeugt, aber bei jedem Tastendruck (PAI) eventuell ein neues Control, dann könnte es so aussehen, wie hier:

[notice type=’info’]TIPP
In den meisten Fällen ist es sinnvoll und ausreichend, wenn man abfragt, ob der Container bereits erzeugt wurde. Falls er noch nicht erzeugt wurde (Programmstart etc.), dann erzeugt man den Container und auch gleich das Control.[/notice]

Häufig treten solche Fehler auf, wenn man Codezeilen von einer Routine oder Methode in ein Programm-Ereignis kopiert oder umgekehrt. Auf einmal befindet sich der Codeabschnitt, der vorher nur einmal aufgerufen wurde, an einer Stelle im Programm, die mehrmals durchlaufen wird.

Screenshots

Die Anzeige wird über die entsprechenden Radiobuttons gesteuert.

Code

REPORT zz_switch_controls.


*== Data
DATA gt_data_alv TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.
DATA go_dock TYPE REF TO cl_gui_docking_container.
DATA go_text TYPE REF TO cl_gui_textedit.
DATA go_grid TYPE REF TO cl_gui_alv_grid.
DATA go_pic TYPE REF TO cl_gui_picture.

*== Selektionsbild
PARAMETERS: rb_text RADIOBUTTON GROUP rb1 DEFAULT 'X' USER-COMMAND space,
 rb_grid RADIOBUTTON GROUP rb1,
 rb_pic RADIOBUTTON GROUP rb1.

AT SELECTION-SCREEN.
 "steuern der controls
  CASE 'X'.
    WHEN rb_grid. 
      go_text->set_visible( space ).
      go_pic->set_visible( space ).
      go_grid->set_visible( 'X' ).
    WHEN rb_text.
      go_text->set_visible( 'X' ).
      go_pic->set_visible( space ).
      go_grid->set_visible( space ).
    WHEN rb_pic.
      go_text->set_visible( space ).
      go_pic->set_visible( 'X' ).
      go_grid->set_visible( space ).
  ENDCASE.

INITIALIZATION.

*== Docker
 go_dock = NEW #( side = cl_gui_docking_container=>dock_at_right ratio = 80 ).

*== Textedit
 go_text = NEW #( parent = go_dock ).

*== ALV-Grid
 SELECT *
 INTO TABLE gt_data_alv
 FROM t000.

 go_grid = NEW #( i_parent = go_dock ).
 go_grid->set_table_for_first_display(
     EXPORTING i_structure_name = 'T000'
     CHANGING it_outtab = gt_data_alv ).

*== Picture
 go_pic = NEW cl_gui_picture( parent = go_dock ).
 go_pic->load_picture_from_sap_icons( icon_booking_ok ).
 go_pic->set_display_mode( cl_gui_picture=>display_mode_fit ).

 

Enno Wulff
Letzte Artikel von Enno Wulff (Alle anzeigen)