Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

Lua 게시판
Lua 스크립트 게시판입니다.
[21] 루아 메타 테이블 이야기... 01
오랑캐꽃 [oranke] 41126 읽음    2012-06-21 19:20
LuaStudy.7z 254.4KB 테이블로 전달된 함수 인자 다루기
이 글을 읽기 전에 먼저 조 밑에 올렸던 루아 예제를 한번씩 훑어보시구요...

루아는 사랑받는 언어입니다. 때문에 루아를 이용한 프로젝트도 참 많지요.
제 경우 가장 인상적이었던 루아 프로젝트는 TCL/TK 에 루아를 이식한 LUA/TK 였습니다.
TK 위젯을 다음과 같이 생성하고 조작하는 문법이 너무 신기하더라구요.

b = ltk.button { text="Ok" }
b.Left = 100
b.Top  = 100
b.Width = 200
b.Height = 25



당시 저는 저희가 쓰던 게임용 GUI를 어떻게하면 루아와 잘 버무릴수 있을까로 고민중이었습니다.
막연히 좋다고만 들었을 뿐 루아 자체가 생소했던 터라... 머리속에 떠오르는 방법이라고 해 봐야
윈도 API 처럼 컨트롤마다 하나 하나 글루 라이브러리를 만들고 이벤트를 설정하는 정도밖에 없었습니다.
하지만 솔직히 그렇게 만들어봐야... 나오는 거라곤 쓰는 사람도 만드는 사람도 괴로운 결과물 뿐이죠.

그러다 저런 문법을 보니 눈이 번쩍! 뜨이더라구요.

하나씩 들여다봅니다. ltk.button 은 일반적인 글루 라이브러리를 호출하는 것과 같은데
인자를 적는 방식이 좀 신기합니다. 괄호가 없어요!!

알고보니 루아함수의 인자값이 테이블 하나일 경우는 괄호를 생략할 수 있다는군요.
다음과 같이 테이블 내의 값들을 모두 더해주는 함수가 있을 때

function SumTable(aTable)
  local RetValue = 0;
  for i=1, #aTable, 1 do
    RetValue = RetValue + aTable[i];
  end;
  return RetValue;
end;



이 함수를 호출할 때는 원래 다음과 같이 적어줘야 하지만

a = SumTable({1, 2, 3, 4, 5});



괄호를 생략해 아래와 같이 바꿔줄 수 있습니다.

a = SumTable{1, 2, 3, 4, 5};



즉 Gui 라는 라이브러리를 만들고 CreateButton 함수를 추가한 뒤 이 함수의 인자로 버튼의 모양을
지정하는 테이블값을 넘겨준다면, 사용자는 다음과 같이 쓸 수 있게 되지요.

b = Gui.CreateButton{
  Left = 10,
  Top = 10,
  Width = 100,
  Height = 50,
}



첫번째 언덕은 넘었습니다.
델파이에서 Gui.CreateButton 이라는 글루 라이브러리를 등록하고, 넘겨받은 테이블 정보를 표시해 봅시다.

function Gui_CreateButton(L: lua_State): Integer; cdecl;
var
  PropName: AnsiString;
begin
  Result := 0;
  
  // 파라미터가 테이블 한개일 때만 처리.
  if not (lua_gettop(L) = 1) and (lua_type(L, -1) = LUA_TTABLE) then Exit;

  // 첫번째 키부터 추적하도록 한다.
  lua_pushnil(L); //이 동작에 의해 테이블 스텍은 하나 아래로 내려가 -2가 된다.
  while (lua_next(L, -2) <> 0) do // 다시 테이블 스텍은 하나 아래로 내려가 -3이 된다.
  begin
    // 키는 stack[-2]에 있고 value는 stack[-1]에 있다.
    // 키가 문자열일 때만..
    if lua_type(L, -2) = LUA_TSTRING then
      WriteLn(lua_tostring(L, -2), ', ', lua_tostring(L, -1));

    // 키의 쌍이되는 값만 제거하고 다음 추적을 위해 현재 키값은 남겨둔다.
    lua_pop(L, 1);
  end;
end;

const
  GuiLibArr: Array [0..1] of TluaL_Reg = (
    (name: 'CreateButton';  func: Gui_CreateButton),
    (name: nil;             func: nil)
  );

......

  luaL_openlib(L, 'Gui', @GuiLibArr, 0);




루아에서 다음과 같이 글루함수를 호출해 보면

Gui.CreateButton{
  Left = 10,
  Top = 10,
  Width = 100,
  Height = 50,
  Caption = "Hahaha",
}



인자로 전달받은 테이블의 각 설정값들이 잘 넘어옵니다.




넘겨받은 값대로 적절한 버튼을 만들어주면 되겠죠??
다음과 같이 스크립트용 버튼 객체를 만들어봅시다.

type
  TScriptButton = class(TButton)
  private
  protected
    function SetLuaProperty(L: lua_State; const aPropName: AnsiString): Integer; virtual;
  public
  end;

{ TScriptButton }

function TScriptButton.SetLuaProperty(L: lua_State; const aPropName: AnsiString): Integer; 
begin
  Result := 0;

  if aPropName = 'Left' then Left := lua_tointeger(L, -1) else
  if aPropName = 'Top'  then Top := lua_tointeger(L, -1) else
  if aPropName = 'Width' then Width:= lua_tointeger(L, -1) else
  if aPropName = 'Height' then Height:= lua_tointeger(L, -1) else
  if aPropName = 'Caption' then Caption:= lua_tostring(L, -1) else
end;



Gui_CreateButton 함수를 버튼을 만들고 속성을 설정하도록 조금 손봅니다.

function Gui_CreateButton(L: lua_State): Integer; cdecl;
var
  Btn: TScriptButton;
  PropName: AnsiString;
begin
  Result := 0;

  // 파라미터가 테이블 한개일 때만 처리.
  if not (lua_gettop(L) = 1) and (lua_type(L, -1) = LUA_TTABLE) then Exit;

  // 버튼 생성
  Btn := TScriptButton.Create(Application.MainForm);
  Btn.Parent := Application.MainForm;

  // 첫번째 키부터 추적하도록 한다.
  lua_pushnil(L); //이 동작에 의해 테이블 스텍은 하나 아래로 내려가 -2가 된다.
  while (lua_next(L, -2) <> 0) do // 다시 테이블 스텍은 하나 아래로 내려가 -3이 된다.
  begin
    // 키는 stack[-2]에 있고 value는 stack[-1]에 있다.
    // 키가 문자열일 때만..
    if lua_type(L, -2) = LUA_TSTRING then
    begin
      PropName := lua_tostring(L, -2);
      Btn.SetLuaProperty(L, PropName);
    end;

    // 키의 쌍이되는 값만 제거하고 다음 추적을 위해 현재 키값은 남겨둔다.
    lua_pop(L, 1);
  end;
end;



루아코드를 실행시켜보면 원하는 대로 버튼이 만들어집니다.




이제 남은 문제는, 이렇게 생성한 버튼을 변수 "b" 에 담고 다음과 같이 제어할 수 있는 방법이 무엇인가 하는 것인데...

b = Gui.CreateButton{
  Left = 10,
  Top = 10,
  Width = 100,
  Height = 50,
  Caption = "Hahaha",
}

b.Left = b.Left + 10



이걸 가능하게 해주는 루아의 멋진 개념이 바로 "메타테이블" 입니다.
제가 루아를 사랑하는 이유이며, 이 글을 끄적거리는 목적이기도 하지요.
오늘은 일단 떡밥만 솔솔 뿌려놓고... 다음에 계속 하겠습니다.

임프님처럼 재미나게 글 쓰는 재주도 없고, 루아의 기본적인 개념은 알아서 공부하시라는
매우 불친절한 글이 될 예정입니다만...
그래도 제가 정말 간절하게 원했던 내용이고 한참을 해맸던 삽질이라 무리를 해 봅니다.

모쪼록 영양가 없는 글 속에서 건더기만 건져 드시는 지혜가 함께 하시길...

+ -

관련 글 리스트
21 루아 메타 테이블 이야기... 01 오랑캐꽃 41126 2012/06/21
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.