SAP 화면에서 사용자가 여러 줄의 자유 텍스트를 입력·편집할 수 있는 메모장 같은 컨트롤이 필요할 때가 있습니다. 기안 내용, 비고, 처리 의견처럼 길이가 정해지지 않은 텍스트를 받는 화면이 대표적입니다. 이때 쓰는 것이 CL_GUI_TEXTEDIT — 흔히 "텍스트 그리드" 또는 "텍스트 에디터" 라고 부르는 컨트롤입니다.
ALV 그리드가 표 형태의 정형 데이터를 보여준다면, TextEdit 은 줄바꿈·잘라내기·붙여넣기가 되는 편집 가능한 텍스트 영역입니다. 여기에 SAPscript 텍스트 저장소(READ_TEXT/SAVE_TEXT) 를 연동하면 입력한 텍스트를 영구 저장하고 다시 불러올 수 있습니다.
이 글에서는 TextEdit 컨트롤 생성 → 텍스트 표시/가져오기 → 편집/조회 모드 제어 → SAPscript 저장소 연동(저장·조회) 까지 정리합니다. 핵심은 세 가지 텍스트 형태(화면 stream ↔ SAPscript ITF ↔ 저장소) 사이의 변환 입니다.
핵심 — 텍스트의 3가지 형태와 변환
TextEdit 으로 입력한 텍스트를 저장하려면 형태를 두 번 변환해야 합니다.
| 형태 | 타입 | 용도 |
|---|---|---|
| Stream | TLINE-TDLINE 테이블 |
TextEdit 화면에 표시되는 텍스트 줄 |
| ITF | TLINE 테이블 |
SAPscript 내부 포맷 (포맷 코드 + 텍스트) |
| 저장소 | STXH / STXL (THEAD 키) |
DB 영구 저장 (READ_TEXT/SAVE_TEXT 로 접근) |
변환 흐름은 다음과 같습니다.
[저장]
TextEdit 화면 ──get_text_as_stream──▶ Stream
Stream ──CONVERT_STREAM_TO_ITF_TEXT──▶ ITF
ITF ──SAVE_TEXT(+THEAD 키)──▶ 저장소(STXH/STXL)
[조회]
저장소 ──READ_TEXT(THEAD 키)──▶ ITF
ITF ──CONVERT_ITF_TO_STREAM_TEXT──▶ Stream
Stream ──set_text_as_stream──▶ TextEdit 화면
저장과 조회는 정확히 대칭 구조입니다. 화면용 stream 과 저장용 ITF 사이를 변환 함수가 이어줍니다.
1단계 — DATA 선언 + 화면 준비
TextEdit 컨테이너·에디터 참조와, 텍스트를 담을 stream/ITF 테이블, 저장소 키(THEAD) 를 선언합니다.
DATA: ok_code TYPE sy-ucomm.
DATA: g_textcontainer TYPE REF TO cl_gui_custom_container, " 텍스트 컨테이너
g_editor TYPE REF TO cl_gui_textedit, " 텍스트 그리드
g_header LIKE thead, " 저장소 키(헤더)
gt_text TYPE TABLE OF tline-tdline, " 화면 stream
gt_itftext TYPE TABLE OF tline. " SAPscript ITF
* 생성/편집 vs 조회 모드 선택
PARAMETERS: r_edit RADIOBUTTON GROUP gr1 DEFAULT 'X', " 편집
r_disp RADIOBUTTON GROUP gr1. " 조회
화면(Screen 100) 에는 Custom Control 을 하나 그리고 이름을 C_TEXT_100_01 로 지정합니다. Flow Logic 의 PBO 에 컨테이너/에디터 생성 모듈과 텍스트 표시 모듈을, PAI 에 저장 처리 모듈을 연결합니다.
2단계 — PBO: 컨테이너 + TextEdit 생성 + 모드 제어
PBO 에서 컨테이너와 TextEdit 을 생성합니다. 생성 시 줄바꿈 방식(wordwrap_mode) 과 최대 글자 수(max_number_chars) 를 지정합니다.
MODULE set_text_100_01 OUTPUT.
IF g_textcontainer IS INITIAL.
* 텍스트 컨테이너 생성 (SE51 Custom Control 'C_TEXT_100_01')
g_textcontainer = NEW #( container_name = 'C_TEXT_100_01' ).
* 텍스트 그리드 생성
g_editor = NEW #(
parent = g_textcontainer
wordwrap_mode = cl_gui_textedit=>wordwrap_at_fixed_position " 고정 위치 줄바꿈
wordwrap_position = 80 " 80번째 칸에서 줄바꿈
max_number_chars = 1000 ). " 최대 1000자
* 편집 모드 vs 조회 모드
IF r_edit = 'X'.
g_editor->set_readonly_mode( readonly_mode = 0 ). " 0 = 편집 가능
g_editor->set_statusbar_mode( statusbar_mode = 1 ). " 상태바 표시
g_editor->set_toolbar_mode( toolbar_mode = 1 ). " 툴바 표시
ELSE.
g_editor->set_readonly_mode( readonly_mode = 1 ). " 1 = 읽기 전용
g_editor->set_toolbar_mode( toolbar_mode = 0 ).
g_editor->set_statusbar_mode( statusbar_mode = 0 ).
ENDIF.
ENDIF.
ENDMODULE.
wordwrap_mode 의 줄바꿈 옵션은 다음과 같습니다.
| 상수 | 값 | 동작 |
|---|---|---|
wordwrap_off |
0 | 자동 줄바꿈 없음 (가로 스크롤) |
wordwrap_at_windowborder |
1 | 창 너비에 맞춰 자동 줄바꿈 |
wordwrap_at_fixed_position |
2 | wordwrap_position 칸에서 줄바꿈 |
모드 제어 메소드의 값은 직관과 반대로 헷갈리기 쉬우니 주의합니다.
| 메소드 | 0 | 1 |
|---|---|---|
set_readonly_mode |
편집 가능 | 읽기 전용 |
set_toolbar_mode |
숨김 | 표시 |
set_statusbar_mode |
숨김 | 표시 |
set_readonly_mode 만 0 이 "활성(편집 가능)" 이라 다른 두 메소드와 의미 방향이 반대입니다.
3단계 — 텍스트 표시: set_text_as_stream
내부 테이블(stream) 의 텍스트를 화면에 뿌립니다.
MODULE set_text_editor OUTPUT.
g_editor->set_text_as_stream( text = gt_text ).
ENDMODULE.
set_text_as_stream 은 TLINE-TDLINE 타입의 줄 테이블을 받아 TextEdit 화면에 표시합니다. 조회 모드라면 5단계에서 읽어온 텍스트가 여기서 화면에 나타납니다.
4단계 — 저장: 화면 → stream → ITF → 저장소
PAI 에서 SAVE 명령 시, 화면의 텍스트를 가져와(stream) ITF 로 변환하고 SAPscript 저장소에 저장합니다.
MODULE user_command_0100 INPUT.
CASE ok_code.
WHEN 'BACK' OR 'EXIT' OR 'CANC'.
LEAVE TO SCREEN 0.
WHEN 'SAVE'.
* 1) 화면 텍스트 가져오기 (화면 → stream)
g_editor->get_text_as_stream( IMPORTING text = gt_text ).
CHECK gt_text IS NOT INITIAL.
* 2) stream → ITF 변환
CALL FUNCTION 'CONVERT_STREAM_TO_ITF_TEXT'
TABLES
text_stream = gt_text
itf_text = gt_itftext.
* 3) 저장소 키(THEAD) 세팅
g_header-tdname = 'DEMO_KEY_001'. " 텍스트 이름(키)
g_header-tdobject = 'ZXX_TEXT'. " 텍스트 오브젝트 (SE75 커스텀)
g_header-tdid = 'ZX01'. " 텍스트 ID
g_header-tdspras = '3'. " 언어 (3 = 한국어)
* 4) 저장
CALL FUNCTION 'SAVE_TEXT'
EXPORTING
header = g_header
insert = ' '
savemode_direct = 'X'
TABLES
lines = gt_itftext
EXCEPTIONS
id = 1
language = 2
name = 3
object = 4
OTHERS = 5.
ENDCASE.
ENDMODULE.
THEAD 의 4가지 키 — tdname(텍스트 이름)·tdobject(텍스트 오브젝트)·tdid(텍스트 ID)·tdspras(언어) — 가 저장소에서 텍스트를 식별하는 복합 키입니다. savemode_direct = 'X' 는 즉시 DB 저장(COMMIT 대기 없이) 을 의미합니다.
5단계 — 조회: 저장소 → ITF → stream → 화면
조회 모드(r_disp) 로 실행하면 START-OF-SELECTION 에서 저장된 텍스트를 읽어 stream 으로 변환합니다.
START-OF-SELECTION.
IF r_disp = 'X'.
CLEAR g_header.
g_header-tdobject = 'ZXX_TEXT'.
g_header-tdid = 'ZX01'.
* 1) 저장소에서 ITF 읽기
CALL FUNCTION 'READ_TEXT'
EXPORTING
client = sy-mandt
id = g_header-tdid
language = '3'
name = 'DEMO_KEY_001' " 텍스트 이름(키)
object = g_header-tdobject
TABLES
lines = gt_itftext
EXCEPTIONS
id = 1
language = 2
name = 3
not_found = 4
object = 5
OTHERS = 8.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
* 2) ITF → stream 변환 (화면 표시용)
CALL FUNCTION 'CONVERT_ITF_TO_STREAM_TEXT'
TABLES
itf_text = gt_itftext
text_stream = gt_text.
ENDIF.
CALL SCREEN 100.
READ_TEXT 의 키(id·language·name·object) 는 저장할 때 쓴 SAVE_TEXT 의 키와 정확히 같아야 같은 텍스트를 찾아옵니다.
자주 빠뜨리는 함정
저장/조회 키 불일치
SAVE_TEXT 와 READ_TEXT 의 4가지 키(name·object·id·language) 중 하나라도 다르면 텍스트를 못 찾습니다. 텍스트 그리드가 화면에 여러 개일 때는 특히 name 을 그리드마다 다르게 줘서 구분해야 합니다.
텍스트 오브젝트/ID 미등록
tdobject·tdid 는 SE75 에 미리 등록된 값이어야 합니다. 커스텀 텍스트 오브젝트(ZXX_TEXT 등) 를 쓰려면 SE75 에서 먼저 만들어야 SAVE_TEXT 가 동작합니다.
stream ↔ ITF 변환 누락
TextEdit 은 stream(TDLINE) 을 다루고 저장소는 ITF(TLINE) 를 다룹니다. 변환 함수(CONVERT_STREAM_TO_ITF_TEXT / CONVERT_ITF_TO_STREAM_TEXT) 를 빼먹으면 타입이 안 맞아 저장/표시가 깨집니다.
readonly_mode 값 혼동
set_readonly_mode 는 0 이 "편집 가능", 1 이 "읽기 전용" 입니다. 반면 set_toolbar_mode·set_statusbar_mode 는 1 이 "표시" 입니다. 방향이 달라 헷갈리기 쉽습니다.
컨테이너 생성 가드
PBO 의 IF g_textcontainer IS INITIAL 가드 없이 매번 생성하면 컨트롤이 중복 생성됩니다.
Background 실행 시 덤프
TextEdit 도 SAP GUI 전용입니다. 배치 잡에서는 컨트롤 생성 시점에 덤프가 납니다.
전체 코드 — 복사용 통합본
아래 통합본은 SE38 에 붙여 활성화 가능. SE51 에서 Screen 100 에 Custom Control 'C_TEXT_100_01' 을 그리고, Flow Logic 에 status_0100 · set_text_100_01 · set_text_editor (PBO) · user_command_0100 (PAI) 를 연결합니다. 텍스트 오브젝트/ID 는 SE75 에 등록된 값으로 교체하세요.
*&---------------------------------------------------------------------*
*& Report ZRXX_TEXTEDIT_GRID (예시)
*&---------------------------------------------------------------------*
*& CL_GUI_TEXTEDIT 텍스트 그리드 — 입력 / 저장 / 조회
*&---------------------------------------------------------------------*
REPORT zrxx_textedit_grid.
DATA: ok_code TYPE sy-ucomm.
DATA: g_textcontainer TYPE REF TO cl_gui_custom_container,
g_editor TYPE REF TO cl_gui_textedit,
g_header LIKE thead,
gt_text TYPE TABLE OF tline-tdline,
gt_itftext TYPE TABLE OF tline.
PARAMETERS: r_edit RADIOBUTTON GROUP gr1 DEFAULT 'X', " 편집/저장
r_disp RADIOBUTTON GROUP gr1. " 조회
* ── 조회 모드: 저장된 텍스트 읽기 ──
START-OF-SELECTION.
IF r_disp = 'X'.
CLEAR g_header.
g_header-tdobject = 'ZXX_TEXT'.
g_header-tdid = 'ZX01'.
CALL FUNCTION 'READ_TEXT'
EXPORTING
client = sy-mandt
id = g_header-tdid
language = '3'
name = 'DEMO_KEY_001'
object = g_header-tdobject
TABLES
lines = gt_itftext
EXCEPTIONS
id = 1 language = 2 name = 3 not_found = 4
object = 5 reference_check = 6
wrong_access_to_archive = 7 OTHERS = 8.
IF sy-subrc = 0.
CALL FUNCTION 'CONVERT_ITF_TO_STREAM_TEXT'
TABLES
itf_text = gt_itftext
text_stream = gt_text.
ENDIF.
ENDIF.
CALL SCREEN 100.
* ── PBO: GUI Status ──
MODULE status_0100 OUTPUT.
SET PF-STATUS 'S100'.
ENDMODULE.
* ── PBO: ★ 컨테이너 + TextEdit 생성 + 모드 제어 ──
MODULE set_text_100_01 OUTPUT.
IF g_textcontainer IS INITIAL.
g_textcontainer = NEW #( container_name = 'C_TEXT_100_01' ).
g_editor = NEW #(
parent = g_textcontainer
wordwrap_mode = cl_gui_textedit=>wordwrap_at_fixed_position
wordwrap_position = 80
max_number_chars = 1000 ).
IF r_edit = 'X'.
g_editor->set_readonly_mode( readonly_mode = 0 ).
g_editor->set_statusbar_mode( statusbar_mode = 1 ).
g_editor->set_toolbar_mode( toolbar_mode = 1 ).
ELSE.
g_editor->set_readonly_mode( readonly_mode = 1 ).
g_editor->set_toolbar_mode( toolbar_mode = 0 ).
g_editor->set_statusbar_mode( statusbar_mode = 0 ).
ENDIF.
ENDIF.
ENDMODULE.
* ── PBO: ★ 텍스트 화면 표시 ──
MODULE set_text_editor OUTPUT.
g_editor->set_text_as_stream( text = gt_text ).
ENDMODULE.
* ── PAI: 저장 처리 ──
MODULE user_command_0100 INPUT.
CASE ok_code.
WHEN 'BACK' OR 'EXIT' OR 'CANC'.
LEAVE TO SCREEN 0.
WHEN 'SAVE'.
* 화면 → stream
g_editor->get_text_as_stream( IMPORTING text = gt_text ).
CHECK gt_text IS NOT INITIAL.
* stream → ITF
CALL FUNCTION 'CONVERT_STREAM_TO_ITF_TEXT'
TABLES
text_stream = gt_text
itf_text = gt_itftext.
* THEAD 키 세팅
g_header-tdname = 'DEMO_KEY_001'.
g_header-tdobject = 'ZXX_TEXT'.
g_header-tdid = 'ZX01'.
g_header-tdspras = '3'.
* 저장
CALL FUNCTION 'SAVE_TEXT'
EXPORTING
header = g_header
insert = ' '
savemode_direct = 'X'
TABLES
lines = gt_itftext
EXCEPTIONS
id = 1 language = 2 name = 3 object = 4 OTHERS = 5.
ENDCASE.
ENDMODULE.
요약
| 동작 | 핵심 호출 | 변환 |
|---|---|---|
| 생성 | NEW cl_gui_textedit( wordwrap_mode... ) |
컨테이너 → 에디터 |
| 표시 | set_text_as_stream |
stream → 화면 |
| 저장 | get_text_as_stream → SAVE_TEXT |
화면 → stream → ITF → 저장소 |
| 조회 | READ_TEXT → set_text_as_stream |
저장소 → ITF → stream → 화면 |
| 모드 | set_readonly_mode / set_toolbar_mode |
편집(0) / 조회(1) 전환 |
TextEdit 그리드의 본질은 "화면용 stream 과 저장용 ITF 사이를 변환 함수로 잇고, THEAD 키로 SAPscript 저장소에 영구 보관". set_text_as_stream/get_text_as_stream 으로 화면과 내부 테이블을 오가고, CONVERT_* 함수로 형태를 바꾼 뒤 READ_TEXT/SAVE_TEXT 로 저장·조회합니다. 저장/조회 키만 정확히 맞추면 기안 내용·비고 같은 자유 텍스트 입력 화면을 안정적으로 만들 수 있습니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.
CL_GUI_TEXTEDIT 의 set_text_as_stream·get_text_as_stream·모드 제어 메소드와 wordwrap 상수(at_fixed_position=2 등), READ_TEXT/SAVE_TEXT 시그니처는 NetWeaver 표준 정의(ECC 6.0 / S/4HANA on-premise 기준) 입니다. 적용 환경 버전에 따라 일부 차이가 있을 수 있으니 실제 적용 시 SE24 의 클래스 정의를 확인하시기 바랍니다. 텍스트 오브젝트·ID·키 값은 모두 가상 예시값이며, 실제 적용 시 SE75 에 등록된 값으로 교체해야 합니다.