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.
- Transportaufträge zur Importqueue hinzufügen - 9. Juli 2025
- Auftragsbearbeitung: Schnellzugriffsdrucktasten - 9. Juli 2025
- Splitstorm – Splitterkonfiguration auslesen und wiederherstellen - 3. Juli 2025