Learning
레슨 7 / 8·25분

실전: 비주얼 프로그래밍 에디터

프로젝트 개요 — 미니 코딩 에디터

지금까지 배운 Blockly 지식을 활용하여 커스텀 블록이 포함된 미니 비주얼 프로그래밍 에디터를 구현합니다. HTML 페이지에 Blockly 워크스페이스를 배치하고, 코드 생성 및 실행까지 가능한 완전한 에디터를 만듭니다.

HTML 레이아웃 구성

javascript
// HTML 구조 (코드로 표현)
// <div id="app">
//   <div id="toolbar">
//     <button id="runBtn">실행</button>
//     <button id="saveBtn">저장</button>
//     <button id="loadBtn">불러오기</button>
//     <button id="clearBtn">초기화</button>
//   </div>
//   <div id="content">
//     <div id="blocklyDiv"></div>  <!-- 블록 에디터 -->
//     <div id="codeOutput"></div>  <!-- 코드 미리보기 -->
//   </div>
//   <div id="consoleOutput"></div>  <!-- 실행 결과 -->
// </div>

// 레이아웃 초기화
var layout = {
  toolbar: ["실행", "저장", "불러오기", "초기화"],
  editor: "blocklyDiv",
  codePreview: "codeOutput",
  console: "consoleOutput"
};

window.alert("에디터 레이아웃: " + JSON.stringify(layout));

커스텀 블록 정의 — 캐릭터 제어

javascript
// 커스텀 블록 정의: 캐릭터 이동
// Blockly.Blocks["character_move"] = {
//   init: function() {
//     this.appendDummyInput()
//         .appendField("캐릭터를")
//         .appendField(new Blockly.FieldDropdown([
//           ["위로", "UP"],
//           ["아래로", "DOWN"],
//           ["왼쪽으로", "LEFT"],
//           ["오른쪽으로", "RIGHT"]
//         ]), "DIRECTION")
//         .appendField("이동");
//     this.appendValueInput("STEPS")
//         .setCheck("Number")
//         .appendField("");
//     this.appendDummyInput()
//         .appendField("칸");
//     this.setPreviousStatement(true, null);
//     this.setNextStatement(true, null);
//     this.setColour(160);
//     this.setTooltip("캐릭터를 지정 방향으로 이동합니다");
//   }
// };

// 커스텀 블록의 코드 생성기
// javascriptGenerator.forBlock["character_move"] = function(block) {
//   var direction = block.getFieldValue("DIRECTION");
//   var steps = javascriptGenerator.valueToCode(
//     block, "STEPS", javascriptGenerator.ORDER_ATOMIC
//   ) || "1";
//   return "moveCharacter(" + JSON.stringify(direction) + ", " + steps + ");\n";
// };

// 캐릭터 이동 실행 함수
var characterX = 0;
var characterY = 0;

function moveCharacter(direction, steps) {
  if (direction === "UP") characterY -= steps;
  if (direction === "DOWN") characterY += steps;
  if (direction === "LEFT") characterX -= steps;
  if (direction === "RIGHT") characterX += steps;
  window.alert("캐릭터 위치: (" + characterX + ", " + characterY + ")");
}

에디터 핵심 기능 구현

javascript
// 코드 생성 및 미리보기 업데이트
function updateCodePreview(workspace) {
  // var code = javascriptGenerator.workspaceToCode(workspace);
  // document.getElementById("codeOutput").textContent = code;
  var code = "// 블록에서 생성된 코드가 여기에 표시됩니다";
  window.alert("코드 미리보기 업데이트: " + code);
}

// 실행 버튼
function runCode(workspace) {
  // var code = javascriptGenerator.workspaceToCode(workspace);
  var output = [];

  // console.log를 캡처하여 출력 영역에 표시
  var originalAlert = window.alert;
  window.alert = function(msg) {
    output.push(String(msg));
  };

  try {
    // new Function(code)();
    window.alert("실행 성공!");
  } catch (error) {
    output.push("오류: " + error.message);
  }

  window.alert = originalAlert;
  window.alert("실행 결과:\n" + output.join("\n"));
}

// 워크스페이스 저장
function saveWorkspace(workspace) {
  // var state = Blockly.serialization.workspaces.save(workspace);
  // localStorage.setItem("blocklyWorkspace", JSON.stringify(state));
  window.alert("워크스페이스 저장 완료!");
}

// 워크스페이스 불러오기
function loadWorkspace(workspace) {
  // var stateJson = localStorage.getItem("blocklyWorkspace");
  // if (stateJson) {
  //   var state = JSON.parse(stateJson);
  //   Blockly.serialization.workspaces.load(state, workspace);
  // }
  window.alert("워크스페이스 불러오기!");
}

이벤트 리스너와 실시간 업데이트

javascript
// 워크스페이스 변경 이벤트 감지
// workspace.addChangeListener(function(event) {
//   // 블록 변경 시 코드 자동 업데이트
//   if (event.type === Blockly.Events.BLOCK_CHANGE ||
//       event.type === Blockly.Events.BLOCK_MOVE ||
//       event.type === Blockly.Events.BLOCK_DELETE) {
//     updateCodePreview(workspace);
//   }
// });

// 버튼 이벤트 연결
function setupButtons() {
  // document.getElementById("runBtn").onclick = function() {
  //   runCode(workspace);
  // };
  // document.getElementById("saveBtn").onclick = function() {
  //   saveWorkspace(workspace);
  // };
  // document.getElementById("loadBtn").onclick = function() {
  //   loadWorkspace(workspace);
  // };
  // document.getElementById("clearBtn").onclick = function() {
  //   workspace.clear();
  //   updateCodePreview(workspace);
  // };

  window.alert("버튼 이벤트 연결 완료!");
}

// 윈도우 리사이즈 대응
// window.addEventListener("resize", function() {
//   Blockly.svgResize(workspace);
// });

// 초기화 실행
setupButtons();
window.alert("에디터 초기화 완료!");
  • Blockly.inject() — 워크스페이스를 DOM 요소에 주입
  • workspaceToCode() — 블록을 코드 문자열로 변환
  • addChangeListener() — 블록 변경 이벤트 감지
  • serialization.workspaces.save/load — 워크스페이스 직렬화
  • 커스텀 블록 — 도메인 특화 블록을 정의하여 교육/업무 활용
  • localStorage — 브라우저에 작업 내용 저장
💡

이 프로젝트를 확장해 보세요: 블록으로 그림 그리기(Canvas 활용), 게임 캐릭터 제어, 로봇 시뮬레이터, 음악 만들기 등 다양한 도메인에 Blockly를 적용할 수 있습니다. 대상 사용자에 맞는 커스텀 블록을 설계하는 것이 핵심입니다.