改变节点在 ALV 树中的位置
Changing a node's site in ALV tree
我有一个 ALV 树,基本上我需要做的是将特定节点滑动(拖动)到顶部或底部或 ALV 树中的特定位置。
这是如何实现的?
例如,在这里我想将 IF 节点滑动到 AFFECTATIONS 节点之前的位置:
预期节点排列:
TL;DR: cl_gui_alv_tree
不能像你希望的那样去做。
由于 ALV Control Framework 中拖放实现的具体细节,树中的节点可以 可拖动(来源)或 droppable (target), 不是两者。因此,将一个节点拖到另一个节点的位置 在层次结构的同一级别 上是不可能的,因此也不可能在运行时(相互)更改与其兄弟节点的节点。
不过,我想向您推荐一段有用的代码,它展示了如何通过将节点拖动到层次结构的父级来实现接近问题的效果。
在 SAP ALV Framework 中实现免打扰功能的步骤:
- 创建事件 class,其中实现
ondrag
和 ondrop
事件的处理程序。
- 创建 DND 存储对象
lcl_dragdropobj
,一个空的 class,您可以通过它传递内存中的网格对象(叶、节点)。
- 为源对象和目标对象创建 behavior definition。
- 借助上述行为对象,通过
is_node_layout
参数为每个 node/leaf 分配布局。该布局将定义节点行为:可拖动或可放置。
这里是示例代码,建立在 spfli/sflight 数据库上:
REPORT zyyz.
DATA: g_alv_tree TYPE REF TO cl_gui_alv_tree,
g_custom_container TYPE REF TO cl_gui_custom_container,
g_drag_behaviour TYPE REF TO cl_dragdrop,
g_drop_behaviour TYPE REF TO cl_dragdrop.
DATA: gt_sflight TYPE TABLE OF sflight INITIAL SIZE 0, "Output-Table
gt_fieldcatalog TYPE lvc_t_fcat,
g_top_key TYPE lvc_nkey,
ok_code LIKE sy-ucomm,
save_ok LIKE sy-ucomm, "OK-Code
g_max TYPE i VALUE 255.
CLASS lcl_dragdropobj DEFINITION.
PUBLIC SECTION.
DATA: cp_sflight_root TYPE sflight,
cp_sflights TYPE TABLE OF sflight,
cp_node_text_root TYPE lvc_value,
cp_node_texts TYPE salv_t_value,
lt_selected_carrids TYPE lvc_t_nkey,
lt_selected_leafs TYPE lvc_t_nkey.
ENDCLASS.
CLASS lcl_event_receiver DEFINITION.
PUBLIC SECTION. .
METHODS:
on_drag
FOR EVENT on_drag
OF cl_gui_alv_tree
IMPORTING sender node_key drag_drop_object,
on_drop
FOR EVENT on_drop
OF cl_gui_alv_tree
IMPORTING drag_drop_object.
ENDCLASS.
*---------------------------------------------------------------------*
* CLASS lcl_toolbar_event_receiver IMPLEMENTATION
*---------------------------------------------------------------------*
CLASS lcl_event_receiver IMPLEMENTATION.
METHOD on_drag.
DATA: dataobj TYPE REF TO lcl_dragdropobj,
l_sflight TYPE sflight,
l_node_text TYPE lvc_value.
* create and fill dataobject for event ON_DROP.
CREATE OBJECT dataobj.
* Get dragged month
CALL METHOD sender->get_outtab_line
EXPORTING
i_node_key = node_key
IMPORTING
e_outtab_line = dataobj->cp_sflight_root
e_node_text = dataobj->cp_node_text_root.
CALL METHOD g_alv_tree->get_children
EXPORTING
i_node_key = node_key
IMPORTING
et_children = dataobj->lt_selected_carrids.
LOOP AT dataobj->lt_selected_carrids ASSIGNING FIELD-SYMBOL(<carrid>).
CLEAR: l_sflight, l_node_text.
CALL METHOD sender->get_outtab_line
EXPORTING
i_node_key = <carrid>
IMPORTING
e_outtab_line = l_sflight
e_node_text = l_node_text.
APPEND l_node_text TO dataobj->cp_node_texts.
CALL METHOD g_alv_tree->get_children
EXPORTING
i_node_key = <carrid>
IMPORTING
et_children = dataobj->lt_selected_leafs.
LOOP AT dataobj->lt_selected_leafs ASSIGNING FIELD-SYMBOL(<node>).
CLEAR: l_sflight, l_node_text.
CALL METHOD sender->get_outtab_line
EXPORTING
i_node_key = <node>
IMPORTING
e_outtab_line = l_sflight
e_node_text = l_node_text.
APPEND l_sflight TO dataobj->cp_sflights.
ENDLOOP.
ENDLOOP.
drag_drop_object->object = dataobj.
ENDMETHOD.
METHOD on_drop.
DATA: dataobj TYPE REF TO lcl_dragdropobj,
l_root_key TYPE lvc_nkey,
l_carrid_key TYPE lvc_nkey,
l_new_key TYPE lvc_nkey,
lt_sflights TYPE TABLE OF sflight.
CATCH SYSTEM-EXCEPTIONS move_cast_error = 1.
dataobj ?= drag_drop_object->object.
PERFORM add_month USING dataobj->cp_node_text_root
g_top_key
cl_gui_column_tree=>relat_first_child
CHANGING l_root_key.
*
LOOP AT dataobj->lt_selected_carrids ASSIGNING FIELD-SYMBOL(<node>).
READ TABLE dataobj->cp_node_texts ASSIGNING FIELD-SYMBOL(<text>) INDEX sy-tabix.
DATA(sflight) = VALUE sflight( carrid = <text> ).
PERFORM add_carrid_line USING sflight
l_root_key
cl_gui_column_tree=>relat_last_child
CHANGING l_carrid_key.
CLEAR lt_sflights.
INSERT LINES OF dataobj->cp_sflights INTO TABLE lt_sflights.
DELETE lt_sflights WHERE carrid NE <text>.
LOOP AT lt_sflights ASSIGNING FIELD-SYMBOL(<flight>).
PERFORM add_complete_line USING <flight>
l_carrid_key
CHANGING l_new_key.
ENDLOOP.
ENDLOOP.
PERFORM delete_node.
ENDCATCH.
IF sy-subrc <> 0.
CALL METHOD drag_drop_object->abort.
ENDIF.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
END-OF-SELECTION.
CALL SCREEN 100.
*&---------------------------------------------------------------------*
*& Module PBO OUTPUT
*&---------------------------------------------------------------------*
MODULE pbo OUTPUT.
SET PF-STATUS 'MAIN100'.
SET TITLEBAR 'MAINTITLE'.
IF g_alv_tree IS INITIAL.
PERFORM init_tree.
CALL METHOD cl_gui_cfw=>flush
EXCEPTIONS
cntl_system_error = 1
cntl_error = 2.
ENDIF.
ENDMODULE. " PBO OUTPUT
*&---------------------------------------------------------------------*
*& Module PAI INPUT
*&---------------------------------------------------------------------*
* process after input
*----------------------------------------------------------------------*
MODULE pai INPUT.
save_ok = ok_code.
CLEAR ok_code.
CASE save_ok.
WHEN 'EXIT' OR 'BACK' OR 'CANC'.
PERFORM exit_program.
WHEN OTHERS.
CALL METHOD cl_gui_cfw=>dispatch.
ENDCASE.
CALL METHOD cl_gui_cfw=>flush.
ENDMODULE. " PAI INPUT
*&---------------------------------------------------------------------*
*& Form init_tree
*&---------------------------------------------------------------------*
FORM init_tree.
* create container for alv-tree
DATA: l_tree_container_name(30) TYPE c.
l_tree_container_name = 'CCONTAINER1'.
CREATE OBJECT g_custom_container
EXPORTING
container_name = l_tree_container_name.
IF sy-subrc <> 0.
MESSAGE x208(00) WITH 'ERROR'(100).
ENDIF.
* create tree control
CREATE OBJECT g_alv_tree
EXPORTING
parent = g_custom_container
node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
item_selection = ' '
no_html_header = 'X'
no_toolbar = ''.
IF sy-subrc <> 0.
MESSAGE x208(00) WITH 'ERROR'. "#EC NOTEXT
ENDIF.
DATA l_hierarchy_header TYPE treev_hhdr.
l_hierarchy_header-width = 35.
PERFORM build_fieldcatalog.
CALL METHOD g_alv_tree->set_table_for_first_display
EXPORTING
is_hierarchy_header = l_hierarchy_header
CHANGING
it_fieldcatalog = gt_fieldcatalog
it_outtab = gt_sflight.
PERFORM define_dnd_behaviour.
PERFORM create_hierarchy.
PERFORM register_events.
CALL METHOD g_alv_tree->update_calculations.
CALL METHOD g_alv_tree->frontend_update.
ENDFORM. " init_tree
FORM register_events.
DATA: lt_events TYPE cntl_simple_events,
l_event_receiver TYPE REF TO lcl_event_receiver.
CALL METHOD g_alv_tree->get_registered_events
IMPORTING
events = lt_events.
CALL METHOD g_alv_tree->set_registered_events
EXPORTING
events = lt_events.
IF sy-subrc <> 0.
MESSAGE x208(00) WITH 'ERROR'. "#EC NOTEXT
ENDIF.
CREATE OBJECT l_event_receiver.
SET HANDLER l_event_receiver->on_drop FOR g_alv_tree.
SET HANDLER l_event_receiver->on_drag FOR g_alv_tree.
ENDFORM. " register_events
*&---------------------------------------------------------------------*
*& Form exit_program
*&---------------------------------------------------------------------*
* free object and leave program
*----------------------------------------------------------------------*
FORM exit_program.
CALL METHOD g_custom_container->free.
LEAVE PROGRAM.
ENDFORM. " exit_program
*--------------------------------------------------------------------
FORM build_fieldcatalog.
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'SFLIGHT'
CHANGING
ct_fieldcat = gt_fieldcatalog.
ENDFORM. " build_fieldcatalog
*&---------------------------------------------------------------------*
*& Form create_hierarchy
*&---------------------------------------------------------------------*
FORM create_hierarchy.
DATA: ls_sflight TYPE sflight,
lt_sflight TYPE TABLE OF sflight INITIAL SIZE 0,
l_yyyymm TYPE c LENGTH 8, "year and month of sflight-fldate
l_yyyymm_last(6) TYPE c,
l_carrid LIKE sflight-carrid,
l_carrid_last LIKE sflight-carrid.
DATA: l_month_key TYPE lvc_nkey,
l_carrid_key TYPE lvc_nkey,
l_last_key TYPE lvc_nkey,
l_top_key TYPE lvc_nkey,
l_layout_node TYPE lvc_s_layn.
* Select data
SELECT * FROM sflight INTO TABLE lt_sflight UP TO g_max ROWS.
* sort table according to conceived hierarchy
SORT lt_sflight BY fldate+0(6) carrid fldate+6(2).
PERFORM make_drop CHANGING l_layout_node.
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = ''
i_relationship = cl_gui_column_tree=>relat_last_child
i_node_text = text-050
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = l_top_key.
g_top_key = l_top_key.
LOOP AT lt_sflight INTO ls_sflight.
l_yyyymm = ls_sflight-fldate+0(6).
l_carrid = ls_sflight-carrid.
IF l_yyyymm <> l_yyyymm_last. "on change of l_yyyymm
l_yyyymm_last = l_yyyymm.
* month nodes
PERFORM add_month USING l_yyyymm
l_top_key
cl_gui_column_tree=>relat_last_child
CHANGING l_month_key.
* The month changed, thus, there is no predecessor carrier
CLEAR l_carrid_last.
ENDIF.
* Carrier nodes:
IF l_carrid <> l_carrid_last. "on change of l_carrid
l_carrid_last = l_carrid.
PERFORM add_carrid_line USING ls_sflight
l_month_key
cl_gui_column_tree=>relat_last_child
CHANGING l_carrid_key.
ENDIF.
* Leaf:
PERFORM add_complete_line USING ls_sflight
l_carrid_key
CHANGING l_last_key.
ENDLOOP.
CALL METHOD g_alv_tree->expand_node
EXPORTING
i_node_key = l_top_key.
ENDFORM. " create_hierarchy
*&---------------------------------------------------------------------*
*& Form add_month
*&---------------------------------------------------------------------*
FORM add_month USING p_yyyymm TYPE clike
p_relat_key TYPE lvc_nkey
p_relationship TYPE int4
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value,
ls_sflight TYPE sflight,
l_month TYPE c LENGTH 25,
l_layout_node TYPE lvc_s_layn.
IF p_yyyymm CO ' 0123456789'.
p_yyyymm = p_yyyymm && '01'.
CALL FUNCTION 'CONVERSION_EXIT_LDATE_OUTPUT'
EXPORTING
input = p_yyyymm
IMPORTING
output = l_month.
REPLACE REGEX `(\d\d\.\s)([[:alpha:]]*)(\s\d{4})` IN l_month WITH ''.
l_node_text = p_yyyymm(4) && `/` && l_month.
ELSE.
l_node_text = p_yyyymm.
ENDIF.
PERFORM make_drag CHANGING l_layout_node.
* add node
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = p_relationship
i_node_text = l_node_text
is_outtab_line = ls_sflight
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_month
*-----------------------------------------------------------------------
FORM add_carrid_line USING ps_sflight TYPE sflight
p_relat_key TYPE lvc_nkey
p_relationship TYPE int4
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value,
ls_sflight TYPE sflight,
l_layout_node TYPE lvc_s_layn.
l_node_text = ps_sflight-carrid.
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = p_relationship
i_node_text = l_node_text
is_outtab_line = ls_sflight
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_carrid_line
*&---------------------------------------------------------------------*
*& Form add_complete_line
*&---------------------------------------------------------------------*
FORM add_complete_line USING ps_sflight TYPE sflight
p_relat_key TYPE lvc_nkey
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value,
l_layout_node TYPE lvc_s_layn.
WRITE ps_sflight-fldate TO l_node_text MM/DD/YYYY.
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = cl_gui_column_tree=>relat_last_child
is_outtab_line = ps_sflight
i_node_text = l_node_text
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_complete_line
FORM define_dnd_behaviour.
DATA: effect TYPE i.
CREATE OBJECT g_drag_behaviour.
effect = cl_dragdrop=>move.
CALL METHOD g_drag_behaviour->add
EXPORTING
flavor = 'default' "#EC NOTEXT
dragsrc = 'X'
droptarget = ' '
effect = effect.
CREATE OBJECT g_drop_behaviour.
effect = cl_dragdrop=>move.
CALL METHOD g_drop_behaviour->add
EXPORTING
flavor = 'default' "#EC NOTEXT
dragsrc = ' '
droptarget = 'X'
effect = effect.
ENDFORM. " DEFINE_DND_BEHAVIOUR
FORM delete_node.
DATA: lt_selected_nodes TYPE lvc_t_nkey,
l_selected_node TYPE lvc_nkey.
CALL METHOD g_alv_tree->get_selected_nodes
CHANGING
ct_selected_nodes = lt_selected_nodes.
CALL METHOD cl_gui_cfw=>flush.
READ TABLE lt_selected_nodes INTO l_selected_node INDEX 1.
IF sy-subrc EQ 0.
CALL METHOD g_alv_tree->delete_subtree
EXPORTING
i_node_key = l_selected_node.
CALL METHOD g_alv_tree->frontend_update.
ELSE. "sy-subrc EQ 0
MESSAGE i000(0k) WITH 'Please select a node.'(900).
ENDIF.
ENDFORM.
FORM make_drag CHANGING p_layout_node TYPE lvc_s_layn.
DATA l_handle_line TYPE i.
CALL METHOD g_drag_behaviour->get_handle
IMPORTING
handle = l_handle_line.
p_layout_node-dragdropid = l_handle_line.
ENDFORM.
FORM make_drop CHANGING p_layout_node TYPE lvc_s_layn.
DATA l_handle_line TYPE i.
CALL METHOD g_drop_behaviour->get_handle
IMPORTING
handle = l_handle_line.
p_layout_node-dragdropid = l_handle_line.
ENDFORM.
在上面的示例中,月份可以拖动到根 Flights 节点上。当它们被拖动到它上面时,被拖动节点在层次结构中的位置成为第一位。这不完全是您要求的行为,但是!通过一组 N 拖动,您可以将 any 节点放置到该层级中的 any 位置上。
可以通过 BCALV_TREE_* 模式找到更多有用的免打扰示例。
CL_GUI_ALV_TREE
实现了经典的控制框架拖放功能(参见 concept in the SAP Library)。
它允许将任何节点放在任何其他节点上,无论级别如何,除了不能将节点放在其自身上。这是通过为每个节点提供允许拖放的行为来实现的。
以下是最小程序,以便快速了解实现基本拖放操作所需的内容。我不移动节点,因为它不是特定于拖放的(例如使用方法 MOVE_NODE
)。 SFLIGHT table 必须由 运行 程序 SAPBC_DATA_GENERATOR
填写。注意:我不建议像我那样编写它,它只是一个演示程序,而是更像@Suncatcher 的程序。
REPORT.
CLASS lcl_app DEFINITION.
PUBLIC SECTION.
METHODS at_selection_screen_output.
METHODS at_selection_screen_exit.
PRIVATE SECTION.
METHODS on_drag FOR EVENT on_drag OF cl_gui_alv_tree
IMPORTING sender node_key drag_drop_object.
METHODS on_drop FOR EVENT on_drop OF cl_gui_alv_tree
IMPORTING sender node_key drag_drop_object.
DATA: g_alv_tree TYPE REF TO cl_gui_alv_tree,
gt_sflight TYPE TABLE OF sflight,
dragged TYPE sflight.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD at_selection_screen_output.
DATA lt_fieldcatalog TYPE lvc_t_fcat.
IF g_alv_tree IS INITIAL.
g_alv_tree = NEW #( parent = cl_gui_container=>screen0
node_selection_mode = cl_gui_column_tree=>node_sel_mode_single ).
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'SFLIGHT'
CHANGING
ct_fieldcat = lt_fieldcatalog.
g_alv_tree->set_table_for_first_display(
EXPORTING is_hierarchy_header = VALUE #( width = 35 )
CHANGING it_fieldcatalog = lt_fieldcatalog
it_outtab = gt_sflight ).
SET HANDLER on_drop FOR g_alv_tree.
SET HANDLER on_drag FOR g_alv_tree.
DATA(dnd_move_source_target) = NEW cl_dragdrop( ).
dnd_move_source_target->add(
flavor = 'SINGLE'
dragsrc = abap_true
droptarget = abap_true
effect = cl_dragdrop=>move ).
dnd_move_source_target->get_handle( IMPORTING handle = DATA(dnd_move_source_target_id) ).
SELECT * FROM sflight INTO TABLE @DATA(lt_sflight).
LOOP AT lt_sflight ASSIGNING FIELD-SYMBOL(<ls_sflight>).
g_alv_tree->add_node(
EXPORTING i_relat_node_key = ''
i_relationship = cl_gui_column_tree=>relat_last_child
i_node_text = |{ <ls_sflight>-carrid }-{ <ls_sflight>-connid }-{ <ls_sflight>-fldate }|
is_outtab_line = <ls_sflight>
is_node_layout = VALUE #( dragdropid = dnd_move_source_target_id ) ).
ENDLOOP.
g_alv_tree->frontend_update( ).
ENDIF.
ENDMETHOD.
METHOD at_selection_screen_exit.
cl_gui_container=>screen0->free( ).
ENDMETHOD.
METHOD on_drag.
sender->get_outtab_line(
EXPORTING i_node_key = node_key
IMPORTING e_outtab_line = dragged ).
drag_drop_object->object = me. " must be bound to trigger drop event when user drops
ENDMETHOD.
METHOD on_drop.
DATA dropped TYPE sflight.
sender->get_outtab_line(
EXPORTING i_node_key = node_key
IMPORTING e_outtab_line = dropped ).
MESSAGE |{ dragged-carrid }-{ dragged-connid }-{ dragged-fldate
} dropped on { dropped-carrid }-{ dropped-connid }-{ dropped-fldate }| TYPE 'I'.
ENDMETHOD.
ENDCLASS.
PARAMETERS dummy.
DATA go_app TYPE REF TO lcl_app.
LOAD-OF-PROGRAM.
CREATE OBJECT go_app.
AT SELECTION-SCREEN OUTPUT.
go_app->at_selection_screen_output( ).
AT SELECTION-SCREEN ON EXIT-COMMAND.
go_app->at_selection_screen_exit( ).
我有一个 ALV 树,基本上我需要做的是将特定节点滑动(拖动)到顶部或底部或 ALV 树中的特定位置。
这是如何实现的?
例如,在这里我想将 IF 节点滑动到 AFFECTATIONS 节点之前的位置:
预期节点排列:
TL;DR: cl_gui_alv_tree
不能像你希望的那样去做。
由于 ALV Control Framework 中拖放实现的具体细节,树中的节点可以 可拖动(来源)或 droppable (target), 不是两者。因此,将一个节点拖到另一个节点的位置 在层次结构的同一级别 上是不可能的,因此也不可能在运行时(相互)更改与其兄弟节点的节点。
不过,我想向您推荐一段有用的代码,它展示了如何通过将节点拖动到层次结构的父级来实现接近问题的效果。
在 SAP ALV Framework 中实现免打扰功能的步骤:
- 创建事件 class,其中实现
ondrag
和ondrop
事件的处理程序。 - 创建 DND 存储对象
lcl_dragdropobj
,一个空的 class,您可以通过它传递内存中的网格对象(叶、节点)。 - 为源对象和目标对象创建 behavior definition。
- 借助上述行为对象,通过
is_node_layout
参数为每个 node/leaf 分配布局。该布局将定义节点行为:可拖动或可放置。
这里是示例代码,建立在 spfli/sflight 数据库上:
REPORT zyyz.
DATA: g_alv_tree TYPE REF TO cl_gui_alv_tree,
g_custom_container TYPE REF TO cl_gui_custom_container,
g_drag_behaviour TYPE REF TO cl_dragdrop,
g_drop_behaviour TYPE REF TO cl_dragdrop.
DATA: gt_sflight TYPE TABLE OF sflight INITIAL SIZE 0, "Output-Table
gt_fieldcatalog TYPE lvc_t_fcat,
g_top_key TYPE lvc_nkey,
ok_code LIKE sy-ucomm,
save_ok LIKE sy-ucomm, "OK-Code
g_max TYPE i VALUE 255.
CLASS lcl_dragdropobj DEFINITION.
PUBLIC SECTION.
DATA: cp_sflight_root TYPE sflight,
cp_sflights TYPE TABLE OF sflight,
cp_node_text_root TYPE lvc_value,
cp_node_texts TYPE salv_t_value,
lt_selected_carrids TYPE lvc_t_nkey,
lt_selected_leafs TYPE lvc_t_nkey.
ENDCLASS.
CLASS lcl_event_receiver DEFINITION.
PUBLIC SECTION. .
METHODS:
on_drag
FOR EVENT on_drag
OF cl_gui_alv_tree
IMPORTING sender node_key drag_drop_object,
on_drop
FOR EVENT on_drop
OF cl_gui_alv_tree
IMPORTING drag_drop_object.
ENDCLASS.
*---------------------------------------------------------------------*
* CLASS lcl_toolbar_event_receiver IMPLEMENTATION
*---------------------------------------------------------------------*
CLASS lcl_event_receiver IMPLEMENTATION.
METHOD on_drag.
DATA: dataobj TYPE REF TO lcl_dragdropobj,
l_sflight TYPE sflight,
l_node_text TYPE lvc_value.
* create and fill dataobject for event ON_DROP.
CREATE OBJECT dataobj.
* Get dragged month
CALL METHOD sender->get_outtab_line
EXPORTING
i_node_key = node_key
IMPORTING
e_outtab_line = dataobj->cp_sflight_root
e_node_text = dataobj->cp_node_text_root.
CALL METHOD g_alv_tree->get_children
EXPORTING
i_node_key = node_key
IMPORTING
et_children = dataobj->lt_selected_carrids.
LOOP AT dataobj->lt_selected_carrids ASSIGNING FIELD-SYMBOL(<carrid>).
CLEAR: l_sflight, l_node_text.
CALL METHOD sender->get_outtab_line
EXPORTING
i_node_key = <carrid>
IMPORTING
e_outtab_line = l_sflight
e_node_text = l_node_text.
APPEND l_node_text TO dataobj->cp_node_texts.
CALL METHOD g_alv_tree->get_children
EXPORTING
i_node_key = <carrid>
IMPORTING
et_children = dataobj->lt_selected_leafs.
LOOP AT dataobj->lt_selected_leafs ASSIGNING FIELD-SYMBOL(<node>).
CLEAR: l_sflight, l_node_text.
CALL METHOD sender->get_outtab_line
EXPORTING
i_node_key = <node>
IMPORTING
e_outtab_line = l_sflight
e_node_text = l_node_text.
APPEND l_sflight TO dataobj->cp_sflights.
ENDLOOP.
ENDLOOP.
drag_drop_object->object = dataobj.
ENDMETHOD.
METHOD on_drop.
DATA: dataobj TYPE REF TO lcl_dragdropobj,
l_root_key TYPE lvc_nkey,
l_carrid_key TYPE lvc_nkey,
l_new_key TYPE lvc_nkey,
lt_sflights TYPE TABLE OF sflight.
CATCH SYSTEM-EXCEPTIONS move_cast_error = 1.
dataobj ?= drag_drop_object->object.
PERFORM add_month USING dataobj->cp_node_text_root
g_top_key
cl_gui_column_tree=>relat_first_child
CHANGING l_root_key.
*
LOOP AT dataobj->lt_selected_carrids ASSIGNING FIELD-SYMBOL(<node>).
READ TABLE dataobj->cp_node_texts ASSIGNING FIELD-SYMBOL(<text>) INDEX sy-tabix.
DATA(sflight) = VALUE sflight( carrid = <text> ).
PERFORM add_carrid_line USING sflight
l_root_key
cl_gui_column_tree=>relat_last_child
CHANGING l_carrid_key.
CLEAR lt_sflights.
INSERT LINES OF dataobj->cp_sflights INTO TABLE lt_sflights.
DELETE lt_sflights WHERE carrid NE <text>.
LOOP AT lt_sflights ASSIGNING FIELD-SYMBOL(<flight>).
PERFORM add_complete_line USING <flight>
l_carrid_key
CHANGING l_new_key.
ENDLOOP.
ENDLOOP.
PERFORM delete_node.
ENDCATCH.
IF sy-subrc <> 0.
CALL METHOD drag_drop_object->abort.
ENDIF.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
END-OF-SELECTION.
CALL SCREEN 100.
*&---------------------------------------------------------------------*
*& Module PBO OUTPUT
*&---------------------------------------------------------------------*
MODULE pbo OUTPUT.
SET PF-STATUS 'MAIN100'.
SET TITLEBAR 'MAINTITLE'.
IF g_alv_tree IS INITIAL.
PERFORM init_tree.
CALL METHOD cl_gui_cfw=>flush
EXCEPTIONS
cntl_system_error = 1
cntl_error = 2.
ENDIF.
ENDMODULE. " PBO OUTPUT
*&---------------------------------------------------------------------*
*& Module PAI INPUT
*&---------------------------------------------------------------------*
* process after input
*----------------------------------------------------------------------*
MODULE pai INPUT.
save_ok = ok_code.
CLEAR ok_code.
CASE save_ok.
WHEN 'EXIT' OR 'BACK' OR 'CANC'.
PERFORM exit_program.
WHEN OTHERS.
CALL METHOD cl_gui_cfw=>dispatch.
ENDCASE.
CALL METHOD cl_gui_cfw=>flush.
ENDMODULE. " PAI INPUT
*&---------------------------------------------------------------------*
*& Form init_tree
*&---------------------------------------------------------------------*
FORM init_tree.
* create container for alv-tree
DATA: l_tree_container_name(30) TYPE c.
l_tree_container_name = 'CCONTAINER1'.
CREATE OBJECT g_custom_container
EXPORTING
container_name = l_tree_container_name.
IF sy-subrc <> 0.
MESSAGE x208(00) WITH 'ERROR'(100).
ENDIF.
* create tree control
CREATE OBJECT g_alv_tree
EXPORTING
parent = g_custom_container
node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
item_selection = ' '
no_html_header = 'X'
no_toolbar = ''.
IF sy-subrc <> 0.
MESSAGE x208(00) WITH 'ERROR'. "#EC NOTEXT
ENDIF.
DATA l_hierarchy_header TYPE treev_hhdr.
l_hierarchy_header-width = 35.
PERFORM build_fieldcatalog.
CALL METHOD g_alv_tree->set_table_for_first_display
EXPORTING
is_hierarchy_header = l_hierarchy_header
CHANGING
it_fieldcatalog = gt_fieldcatalog
it_outtab = gt_sflight.
PERFORM define_dnd_behaviour.
PERFORM create_hierarchy.
PERFORM register_events.
CALL METHOD g_alv_tree->update_calculations.
CALL METHOD g_alv_tree->frontend_update.
ENDFORM. " init_tree
FORM register_events.
DATA: lt_events TYPE cntl_simple_events,
l_event_receiver TYPE REF TO lcl_event_receiver.
CALL METHOD g_alv_tree->get_registered_events
IMPORTING
events = lt_events.
CALL METHOD g_alv_tree->set_registered_events
EXPORTING
events = lt_events.
IF sy-subrc <> 0.
MESSAGE x208(00) WITH 'ERROR'. "#EC NOTEXT
ENDIF.
CREATE OBJECT l_event_receiver.
SET HANDLER l_event_receiver->on_drop FOR g_alv_tree.
SET HANDLER l_event_receiver->on_drag FOR g_alv_tree.
ENDFORM. " register_events
*&---------------------------------------------------------------------*
*& Form exit_program
*&---------------------------------------------------------------------*
* free object and leave program
*----------------------------------------------------------------------*
FORM exit_program.
CALL METHOD g_custom_container->free.
LEAVE PROGRAM.
ENDFORM. " exit_program
*--------------------------------------------------------------------
FORM build_fieldcatalog.
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'SFLIGHT'
CHANGING
ct_fieldcat = gt_fieldcatalog.
ENDFORM. " build_fieldcatalog
*&---------------------------------------------------------------------*
*& Form create_hierarchy
*&---------------------------------------------------------------------*
FORM create_hierarchy.
DATA: ls_sflight TYPE sflight,
lt_sflight TYPE TABLE OF sflight INITIAL SIZE 0,
l_yyyymm TYPE c LENGTH 8, "year and month of sflight-fldate
l_yyyymm_last(6) TYPE c,
l_carrid LIKE sflight-carrid,
l_carrid_last LIKE sflight-carrid.
DATA: l_month_key TYPE lvc_nkey,
l_carrid_key TYPE lvc_nkey,
l_last_key TYPE lvc_nkey,
l_top_key TYPE lvc_nkey,
l_layout_node TYPE lvc_s_layn.
* Select data
SELECT * FROM sflight INTO TABLE lt_sflight UP TO g_max ROWS.
* sort table according to conceived hierarchy
SORT lt_sflight BY fldate+0(6) carrid fldate+6(2).
PERFORM make_drop CHANGING l_layout_node.
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = ''
i_relationship = cl_gui_column_tree=>relat_last_child
i_node_text = text-050
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = l_top_key.
g_top_key = l_top_key.
LOOP AT lt_sflight INTO ls_sflight.
l_yyyymm = ls_sflight-fldate+0(6).
l_carrid = ls_sflight-carrid.
IF l_yyyymm <> l_yyyymm_last. "on change of l_yyyymm
l_yyyymm_last = l_yyyymm.
* month nodes
PERFORM add_month USING l_yyyymm
l_top_key
cl_gui_column_tree=>relat_last_child
CHANGING l_month_key.
* The month changed, thus, there is no predecessor carrier
CLEAR l_carrid_last.
ENDIF.
* Carrier nodes:
IF l_carrid <> l_carrid_last. "on change of l_carrid
l_carrid_last = l_carrid.
PERFORM add_carrid_line USING ls_sflight
l_month_key
cl_gui_column_tree=>relat_last_child
CHANGING l_carrid_key.
ENDIF.
* Leaf:
PERFORM add_complete_line USING ls_sflight
l_carrid_key
CHANGING l_last_key.
ENDLOOP.
CALL METHOD g_alv_tree->expand_node
EXPORTING
i_node_key = l_top_key.
ENDFORM. " create_hierarchy
*&---------------------------------------------------------------------*
*& Form add_month
*&---------------------------------------------------------------------*
FORM add_month USING p_yyyymm TYPE clike
p_relat_key TYPE lvc_nkey
p_relationship TYPE int4
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value,
ls_sflight TYPE sflight,
l_month TYPE c LENGTH 25,
l_layout_node TYPE lvc_s_layn.
IF p_yyyymm CO ' 0123456789'.
p_yyyymm = p_yyyymm && '01'.
CALL FUNCTION 'CONVERSION_EXIT_LDATE_OUTPUT'
EXPORTING
input = p_yyyymm
IMPORTING
output = l_month.
REPLACE REGEX `(\d\d\.\s)([[:alpha:]]*)(\s\d{4})` IN l_month WITH ''.
l_node_text = p_yyyymm(4) && `/` && l_month.
ELSE.
l_node_text = p_yyyymm.
ENDIF.
PERFORM make_drag CHANGING l_layout_node.
* add node
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = p_relationship
i_node_text = l_node_text
is_outtab_line = ls_sflight
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_month
*-----------------------------------------------------------------------
FORM add_carrid_line USING ps_sflight TYPE sflight
p_relat_key TYPE lvc_nkey
p_relationship TYPE int4
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value,
ls_sflight TYPE sflight,
l_layout_node TYPE lvc_s_layn.
l_node_text = ps_sflight-carrid.
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = p_relationship
i_node_text = l_node_text
is_outtab_line = ls_sflight
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_carrid_line
*&---------------------------------------------------------------------*
*& Form add_complete_line
*&---------------------------------------------------------------------*
FORM add_complete_line USING ps_sflight TYPE sflight
p_relat_key TYPE lvc_nkey
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value,
l_layout_node TYPE lvc_s_layn.
WRITE ps_sflight-fldate TO l_node_text MM/DD/YYYY.
CALL METHOD g_alv_tree->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = cl_gui_column_tree=>relat_last_child
is_outtab_line = ps_sflight
i_node_text = l_node_text
is_node_layout = l_layout_node
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_complete_line
FORM define_dnd_behaviour.
DATA: effect TYPE i.
CREATE OBJECT g_drag_behaviour.
effect = cl_dragdrop=>move.
CALL METHOD g_drag_behaviour->add
EXPORTING
flavor = 'default' "#EC NOTEXT
dragsrc = 'X'
droptarget = ' '
effect = effect.
CREATE OBJECT g_drop_behaviour.
effect = cl_dragdrop=>move.
CALL METHOD g_drop_behaviour->add
EXPORTING
flavor = 'default' "#EC NOTEXT
dragsrc = ' '
droptarget = 'X'
effect = effect.
ENDFORM. " DEFINE_DND_BEHAVIOUR
FORM delete_node.
DATA: lt_selected_nodes TYPE lvc_t_nkey,
l_selected_node TYPE lvc_nkey.
CALL METHOD g_alv_tree->get_selected_nodes
CHANGING
ct_selected_nodes = lt_selected_nodes.
CALL METHOD cl_gui_cfw=>flush.
READ TABLE lt_selected_nodes INTO l_selected_node INDEX 1.
IF sy-subrc EQ 0.
CALL METHOD g_alv_tree->delete_subtree
EXPORTING
i_node_key = l_selected_node.
CALL METHOD g_alv_tree->frontend_update.
ELSE. "sy-subrc EQ 0
MESSAGE i000(0k) WITH 'Please select a node.'(900).
ENDIF.
ENDFORM.
FORM make_drag CHANGING p_layout_node TYPE lvc_s_layn.
DATA l_handle_line TYPE i.
CALL METHOD g_drag_behaviour->get_handle
IMPORTING
handle = l_handle_line.
p_layout_node-dragdropid = l_handle_line.
ENDFORM.
FORM make_drop CHANGING p_layout_node TYPE lvc_s_layn.
DATA l_handle_line TYPE i.
CALL METHOD g_drop_behaviour->get_handle
IMPORTING
handle = l_handle_line.
p_layout_node-dragdropid = l_handle_line.
ENDFORM.
在上面的示例中,月份可以拖动到根 Flights 节点上。当它们被拖动到它上面时,被拖动节点在层次结构中的位置成为第一位。这不完全是您要求的行为,但是!通过一组 N 拖动,您可以将 any 节点放置到该层级中的 any 位置上。
可以通过 BCALV_TREE_* 模式找到更多有用的免打扰示例。
CL_GUI_ALV_TREE
实现了经典的控制框架拖放功能(参见 concept in the SAP Library)。
它允许将任何节点放在任何其他节点上,无论级别如何,除了不能将节点放在其自身上。这是通过为每个节点提供允许拖放的行为来实现的。
以下是最小程序,以便快速了解实现基本拖放操作所需的内容。我不移动节点,因为它不是特定于拖放的(例如使用方法 MOVE_NODE
)。 SFLIGHT table 必须由 运行 程序 SAPBC_DATA_GENERATOR
填写。注意:我不建议像我那样编写它,它只是一个演示程序,而是更像@Suncatcher 的程序。
REPORT.
CLASS lcl_app DEFINITION.
PUBLIC SECTION.
METHODS at_selection_screen_output.
METHODS at_selection_screen_exit.
PRIVATE SECTION.
METHODS on_drag FOR EVENT on_drag OF cl_gui_alv_tree
IMPORTING sender node_key drag_drop_object.
METHODS on_drop FOR EVENT on_drop OF cl_gui_alv_tree
IMPORTING sender node_key drag_drop_object.
DATA: g_alv_tree TYPE REF TO cl_gui_alv_tree,
gt_sflight TYPE TABLE OF sflight,
dragged TYPE sflight.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD at_selection_screen_output.
DATA lt_fieldcatalog TYPE lvc_t_fcat.
IF g_alv_tree IS INITIAL.
g_alv_tree = NEW #( parent = cl_gui_container=>screen0
node_selection_mode = cl_gui_column_tree=>node_sel_mode_single ).
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'SFLIGHT'
CHANGING
ct_fieldcat = lt_fieldcatalog.
g_alv_tree->set_table_for_first_display(
EXPORTING is_hierarchy_header = VALUE #( width = 35 )
CHANGING it_fieldcatalog = lt_fieldcatalog
it_outtab = gt_sflight ).
SET HANDLER on_drop FOR g_alv_tree.
SET HANDLER on_drag FOR g_alv_tree.
DATA(dnd_move_source_target) = NEW cl_dragdrop( ).
dnd_move_source_target->add(
flavor = 'SINGLE'
dragsrc = abap_true
droptarget = abap_true
effect = cl_dragdrop=>move ).
dnd_move_source_target->get_handle( IMPORTING handle = DATA(dnd_move_source_target_id) ).
SELECT * FROM sflight INTO TABLE @DATA(lt_sflight).
LOOP AT lt_sflight ASSIGNING FIELD-SYMBOL(<ls_sflight>).
g_alv_tree->add_node(
EXPORTING i_relat_node_key = ''
i_relationship = cl_gui_column_tree=>relat_last_child
i_node_text = |{ <ls_sflight>-carrid }-{ <ls_sflight>-connid }-{ <ls_sflight>-fldate }|
is_outtab_line = <ls_sflight>
is_node_layout = VALUE #( dragdropid = dnd_move_source_target_id ) ).
ENDLOOP.
g_alv_tree->frontend_update( ).
ENDIF.
ENDMETHOD.
METHOD at_selection_screen_exit.
cl_gui_container=>screen0->free( ).
ENDMETHOD.
METHOD on_drag.
sender->get_outtab_line(
EXPORTING i_node_key = node_key
IMPORTING e_outtab_line = dragged ).
drag_drop_object->object = me. " must be bound to trigger drop event when user drops
ENDMETHOD.
METHOD on_drop.
DATA dropped TYPE sflight.
sender->get_outtab_line(
EXPORTING i_node_key = node_key
IMPORTING e_outtab_line = dropped ).
MESSAGE |{ dragged-carrid }-{ dragged-connid }-{ dragged-fldate
} dropped on { dropped-carrid }-{ dropped-connid }-{ dropped-fldate }| TYPE 'I'.
ENDMETHOD.
ENDCLASS.
PARAMETERS dummy.
DATA go_app TYPE REF TO lcl_app.
LOAD-OF-PROGRAM.
CREATE OBJECT go_app.
AT SELECTION-SCREEN OUTPUT.
go_app->at_selection_screen_output( ).
AT SELECTION-SCREEN ON EXIT-COMMAND.
go_app->at_selection_screen_exit( ).