Splitstorm – Splitterkonfiguration auslesen und wiederherstellen
Auch wenn SAPGUI-Applikationen inzwischen schon lange nicht mehr the latest-greatest stuff sind, gibt es immer noch Dinge, die ich ausprobieren kann. In diesem Fall wollte ich die Splitter-Konfiguration generisch auslesen, um die Größe der Splitter wiederherstellen zu können.
Aber von Anfang an…
SAPGUI-Splitter
Die Klasse CL_GUI_SPLITTER_CONTAINER bietet bei der Dynpro-Programmierung die Möglichkeit, mehrere Container zu definieren. Hierbei kann man festlegen, wie viele Spalten und Zeilen der Splitter haben soll. In folgendem Beispiel habe ich vier Splitter-Container verwendet:

- Der erste Splitter-Container teilt den gesamten Bildschirm in vier Container auf
- Der zweite Container teilt A1 in zwei Spalten
- Der dritte Container teilt A2 in zwei Zeilen
- Der vierte Container teilt die obere Zeile in zwei Spalten
- Der fünfte Container teilt die untere Zeile wiederum in zwei Zeilen
Das Problem bei bei den Splitter-Containern ist, dass der Anwender mit dem Layout leben muss, das einmal festgelegt wurde. Zugegeben, ein so verschachteltes Layout ist eher selten. Meistens hat man einen Splitter mit zwei Containern, deren Größe man dann verschieben kann. An dem Layout selbst kann man auch nur durch Programmierung noch etwas ändern. Allerdings kann man sich als Anwender die einzelnen Fenster so zurechtschieben, dass sie für das eingestellte Theme, Bildschirmauflösung und die speziellen Vorlieben besser passen.
Persönliche Einstellungen
Durch unterschiedliche Einstellungen im SAPGUI (Theme, Schriftgröße) und andere Bildschirmauflösungen kann die Darstellung deutlich von der abweichen, die der Entwickler vor Augen hatte. Das aktuelle Quartz-Theme zum Beispiel ist deutlich raumgreifender, als die immer noch beliebten Themes SAP-Signature und Blue-Chrystal. Dadurch kann es sein, dass bestimmte Container gerade um einen halben Zentimeter zu klein sind und deswegen wichtige Informationen nicht auf einen Blick erkennbar sind.
Splitstorm
Mit diesem Tool ist es nun einfach, für jede beliebige Transaktion, die mehrere Splitter beherbergt, die aktuelle Konfiguration benutzerspezifisch zu speichern und wieder abzurufen.
Known bugs
Ratio vs Pixel
Meine Programmierung geht davon aus, dass alle Splitter frei beweglich sind. Es gibt jedoch auch Splitter, die mit der Absicht programmiert wurden, nicht verschiebbar zu sein. Das ist häufig der Fall, wenn man über einem Control eine eigene Toolbar haben möchte. Eigentlich müsste beim Analysieren die korrekte Größe ermittelt und entsprechend wiederhergestellt werden. Allerdings arbeitet meine Klasse mit Prozentangaben. Dadurch kann es bei der Wiederherstellung zu Differenzen kommen, denn die besagte Toolbar wird in der Regel mit einer festen Pixelgröße definiert.
Änderung der Konfiguration
Das Programm erkennt keine Änderung der Konfiguration. Wenn sich die Darstellung ändert (mehr oder weniger Splitter, mehr oder weniger Splitter-Elemente), dann kann eine gespeicherte Konfiguration nicht mehr angewendet werden und es kommt eventuell zu merkwürdigen Nebeneffekten. In diesem Fall muss die persönliche Konfiguration einmal gelöscht und erneut gespeichert werden.
CL_GUI_EASY_SPLITTER_CONTAINER
Das Programm erkennt den CL_GUI_EASY_SPLITTER_CONTAINER nicht. Es werden ausschließlich CL_GUI_SPLITTER_CONTAINER erkannt und ausgewertet.
Sourcecode
Der komplette Sourcecode steht wie immer auf github “Splitstorm” zur Verfügung.
CLASS zt9r_splitstorm DEFINITION PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_splitter_info,
path TYPE string,
rows TYPE i,
columns TYPE i,
row_heights TYPE STANDARD TABLE OF i WITH DEFAULT KEY,
column_widths TYPE STANDARD TABLE OF i WITH DEFAULT KEY,
END OF ty_splitter_info.
TYPES ty_splitter_info_tab TYPE STANDARD TABLE OF ty_splitter_info WITH DEFAULT KEY.
METHODS delete.
METHODS load_and_restore
IMPORTING
i_container TYPE REF TO cl_gui_container.
METHODS analyze_and_save
IMPORTING
i_container TYPE REF TO cl_gui_container.
METHODS constructor
IMPORTING
repid TYPE clike.
PRIVATE SECTION.
METHODS save.
METHODS load.
CONSTANTS mc_root TYPE string VALUE `ROOT`.
METHODS analyze_recursive
IMPORTING
i_container TYPE REF TO cl_gui_control
i_path TYPE string
RETURNING
VALUE(result) TYPE abap_bool.
METHODS get_row_count
IMPORTING
i_splitter TYPE REF TO cl_gui_splitter_container
RETURNING
VALUE(result) TYPE i.
METHODS get_column_count
IMPORTING
i_splitter TYPE REF TO cl_gui_splitter_container
RETURNING
VALUE(result) TYPE i.
METHODS restore_recursive
IMPORTING
i_container TYPE REF TO cl_gui_control
i_path TYPE string.
METHODS get_splitter_row_height
IMPORTING
io_splitter TYPE REF TO cl_gui_splitter_container
RETURNING
VALUE(r_size) TYPE i.
METHODS get_splitter_col_width
IMPORTING
io_splitter TYPE REF TO cl_gui_splitter_container
RETURNING
VALUE(r_size) TYPE i.
METHODS analyze
IMPORTING
i_container TYPE REF TO cl_gui_container
RETURNING
VALUE(result) TYPE ty_splitter_info_tab.
METHODS restore_sizes
IMPORTING
i_container TYPE REF TO cl_gui_container.
METHODS get_id
RETURNING
VALUE(r_id) TYPE char20.
DATA size_info TYPE ty_splitter_info_tab.
DATA repid TYPE c LENGTH 40.
ENDCLASS.
CLASS ZT9R_SPLITSTORM IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->ANALYZE
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER
* | [<-()] RESULT TYPE TY_SPLITTER_INFO_TAB
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD analyze.
LOOP AT i_container->children INTO DATA(child).
analyze_recursive( i_container = child
i_path = mc_root ).
ENDLOOP.
result = size_info.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZT9R_SPLITSTORM->ANALYZE_AND_SAVE
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD analyze_and_save.
analyze( i_container = i_container ).
save( ).
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->ANALYZE_RECURSIVE
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_CONTAINER TYPE REF TO CL_GUI_CONTROL
* | [--->] I_PATH TYPE STRING
* | [<-()] RESULT TYPE ABAP_BOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD analyze_recursive.
TRY.
DATA(lo_splitter) = CAST cl_gui_splitter_container( i_container ).
result = abap_true.
CATCH cx_sy_move_cast_error.
result = abap_false.
RETURN.
ENDTRY.
DATA(lv_rows) = get_row_count( lo_splitter ).
DATA(lv_columns) = get_column_count( lo_splitter ).
DATA lt_row_heights TYPE STANDARD TABLE OF i WITH DEFAULT KEY.
DATA lt_col_widths TYPE STANDARD TABLE OF i WITH DEFAULT KEY.
DO lv_rows TIMES.
APPEND get_splitter_row_height( lo_splitter ) TO lt_row_heights.
ENDDO.
DO lv_columns TIMES.
APPEND get_splitter_col_width( lo_splitter ) TO lt_col_widths.
ENDDO.
APPEND VALUE ty_splitter_info( path = i_path
rows = lv_rows
columns = lv_columns
row_heights = lt_row_heights
column_widths = lt_col_widths )
TO size_info.
DATA(index_row) = 0.
DATA(index_col) = 0.
DO lv_rows TIMES.
index_col = 0.
index_row = index_row + 1.
DO lv_columns TIMES.
index_col = index_col + 1.
DATA(lo_container) = lo_splitter->get_container( row = index_row
column = index_col ).
LOOP AT lo_container->children INTO DATA(lo_child).
IF NOT analyze_recursive(
i_container = lo_child
i_path = |{ i_path }[{ index_row },{ index_col }]| ).
EXIT. " from do
ENDIF.
ENDLOOP.
ENDDO.
ENDDO.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZT9R_SPLITSTORM->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] REPID TYPE CLIKE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD constructor.
me->repid = repid.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZT9R_SPLITSTORM->DELETE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD delete.
DATA(id) = get_id( ).
DELETE FROM DATABASE indx(z1) ID id.
IF sy-subrc = 0 AND size_info IS NOT INITIAL.
MESSAGE 'Splitter configuration deleted' TYPE 'S'.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->GET_COLUMN_COUNT
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER
* | [<-()] RESULT TYPE I
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_column_count.
result = 0.
DO 20 TIMES.
DATA(container) = i_splitter->get_container( row = 1
column = sy-index ).
IF container IS INITIAL.
RETURN.
ELSE.
result = result + 1.
ENDIF.
ENDDO.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->GET_ID
* +-------------------------------------------------------------------------------------------------+
* | [<-()] R_ID TYPE CHAR20
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_id.
r_id = |SPLITTER-{ repid }-{ sy-uname }|.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->GET_ROW_COUNT
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER
* | [<-()] RESULT TYPE I
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_row_count.
result = 0.
DO 20 TIMES.
DATA(container) = i_splitter->get_container( row = sy-index
column = 1 ).
IF container IS INITIAL.
RETURN.
ELSE.
result = result + 1.
ENDIF.
ENDDO.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->GET_SPLITTER_COL_WIDTH
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER
* | [<-()] R_SIZE TYPE I
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_splitter_col_width.
io_splitter->get_column_width( EXPORTING
id = sy-index
IMPORTING
result = r_size ).
cl_gui_cfw=>flush( ).
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->GET_SPLITTER_ROW_HEIGHT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_SPLITTER TYPE REF TO CL_GUI_SPLITTER_CONTAINER
* | [<-()] R_SIZE TYPE I
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_splitter_row_height.
io_splitter->get_row_height( EXPORTING
id = sy-index
IMPORTING
result = r_size ).
cl_gui_cfw=>flush( ).
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->LOAD
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD load.
DATA(id) = get_id( ).
IMPORT splitter_info TO size_info FROM DATABASE indx(z1) ID id.
IF sy-subrc = 0 AND size_info IS NOT INITIAL.
MESSAGE 'Splitter configuration loaded' TYPE 'S'.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZT9R_SPLITSTORM->LOAD_AND_RESTORE
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD load_and_restore.
load( ).
restore_sizes( i_container = i_container ).
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->RESTORE_RECURSIVE
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_CONTAINER TYPE REF TO CL_GUI_CONTROL
* | [--->] I_PATH TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD restore_recursive.
TRY.
DATA(splitter) = CAST cl_gui_splitter_container( i_container ) ##NO_TEXT.
CATCH cx_sy_move_cast_error.
RETURN.
ENDTRY.
READ TABLE size_info INTO DATA(info) WITH KEY path = i_path.
IF sy-subrc <> 0 OR splitter IS INITIAL.
RETURN.
ENDIF.
DATA(idx) = 1.
LOOP AT info-row_heights INTO DATA(lv_r).
splitter->set_row_height( id = idx height = lv_r ).
idx = idx + 1.
ENDLOOP.
idx = 1.
LOOP AT info-column_widths INTO DATA(lv_c).
splitter->set_column_width( id = idx width = lv_c ).
idx = idx + 1.
ENDLOOP.
" Rekursiv weiter
DATA(index_row) = 0.
DATA(index_col) = 0.
DO info-rows TIMES.
index_col = 0.
index_row = index_row + 1.
DO info-columns TIMES.
index_col = index_col + 1.
DATA(lo_container) = splitter->get_container( row = index_row
column = index_col ).
DATA(lv_subpath) = |{ i_path }[{ index_row },{ index_col }]|.
LOOP AT lo_container->children INTO DATA(lo_child).
restore_recursive( i_container = lo_child
i_path = lv_subpath ).
ENDLOOP.
ENDDO.
ENDDO.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->RESTORE_SIZES
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_CONTAINER TYPE REF TO CL_GUI_CONTAINER
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD restore_sizes.
IF size_info IS INITIAL.
RETURN.
ENDIF.
LOOP AT i_container->children INTO DATA(child).
restore_recursive( i_container = child
i_path = mc_root ).
ENDLOOP.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZT9R_SPLITSTORM->SAVE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD save.
IF size_info IS INITIAL.
RETURN.
ENDIF.
DATA(id) = get_id( ).
EXPORT splitter_info FROM size_info TO DATABASE indx(z1) ID id.
MESSAGE 'Splitter configuration saved' TYPE 'S'.
ENDMETHOD.
ENDCLASS.
- Automatisches Eingabefeld [SAPGUI] - 9. Oktober 2025
- So verhinderst du Jobstarts zur falschen Zeit - 15. September 2025
- [apple] iCloud-Photos herunterladen - 21. Juli 2025


