BLOG main image
분류 전체보기 (239)
Rails (65)
Ruby (34)
이야기 (40)
스토리큐 (61)
그 밖에.. (30)
C# (6)
작은아이의 생각
agiletalk's me2DAY
[rails] Growl4Rails
美소년 ㅇㅅㅇ씨의 一日
마사키군의 생각
ayukawa's me2DAY
작은아이의 생각
agiletalk's me2DAY
[Google App Engine] 나의 첫번..
머드초보의 블로그
54,048 Visitors up to today!
Today 14 hit, Yesterday 47 hit

 SUBSCRIBE

2008/08/06 02:14

wxRubywxWidget을 ruby로 포팅한 ruby용 GUI 라이브러리다. 

 

wxRuby를 gem을 통해 설치한다.

  1. gem install wxruby

 

XRC(XML Resource) 를 생성하기

XRC 는 무엇인가?

XRC 는 wxWidget에 의해 사용되는 크로스 플랫폼 XML기반의 User Interface Markup Language 이다. 다시 말해 애플리케이션의 UI(User Interface) 정보를 가지고 있는 XML 이다. UI 정보가 모두 XML을 통해 표현되고 저장되어 있기에 애플리케이션을 구현하는 언어나 애플리케이션이 구동되는 플랫폼에 영향을 받지 않는다. ruby 같이 다이나믹 언어를 사용하는 애플리케이션은 실행하면서 XRC 를 읽어들여서 UI 를 생성할 수 있고, C++같이 컴파일이 필요한 언어는 XRC를 컴파일할 때 불러들여 UI 코드를 생성할 수 있다.

 

XRC 생성하기

UI 디자인을 간편하게 수행하고 그로부터 XRC를 생성해 주는 많은 디자인 툴들이 있다. 그 중 무료 툴인 wxFormBuilder를 사용해 보자.

 

간단한 목표를 가지고 시작하자.

여기서는 개인 PC에서 스토리큐에 파일을 업로드하는 애플리케이션 storyq_uploader을 만들 것이다.

 

wxFormBuilder에서 project생성

storyq_uploader라는 디렉토리를 하나 만들어서 애플리케이션의 기본 디렉토리로 삼자.

wxFormBuilder를 실행시키고, 프로젝트를 생성하자. 그러면 오른쪽에 Object Properties라는 창이 보이는데 프로젝트 이름을 sq_uploader 라고 하자. path와 file은 프로젝트의 결과(XRC) 가 생설될 디렉토리와 파일이름이다. path를 storyq_uploader 디렉토리로, 그리고 file을 uploader_frame이라고 해 주자. code_generation은 Generate Code 명령을 수행했을 때 어떤 결과가 생길지를 지정하는 것이다. XRC로 하자.  relative_path는 디자인 내부에서 사용하는 이미지 같은 외부 파일들에 대한 경로를 상대적으로 할 것인지를 말한다. 체크를 해 두자.

01_new.jpg

 

기본 frame 만들기

이제 업로드를 위한 간단한 frame을 만들자. UI 프로그램을 해본 개발자는 편안함을 느낄지도 모르겠다. 나는 경험이 별로 없는지라 약간 불편하다.

Component Palette 창에 Forms라는 탭을 누르면 아래에 Frame, Panel, Dialog 아이콘이 보인다. Frame을 눌러 기본 윈도우 프래임을 하나 만들자. 그리고 Object Properties에서 tiltle, name을 적당히 써 주고, 맨 밑에 subclass에 UploaderFrameBase 라고 써주자. 나중에 ruby code에서 이 클래스를 상속 받아서 이벤트 같은 것을 처리할 것이다.

02.jpg

 

layout 생성

그 다음은 frame안에 layout을 넣어주자. 레이아웃은 위젯들의 배치에 대한 것이다. 예를 들어, wxBoxSizer 레이아웃은 가로 방향 혹은 세로 방향으로 위젯들이 줄지어 들어가게 된다. uploader는 이것으로 충분할 것 같다.

xwBoxSizer를 uploader_frame 안에 하나 만든다. 세로방향(Vertical)의 BoxSizer가 생긴다. Sizer 밑에 다시 wxBoxSizer를 만든다. 이번에는 Object Properties에서 orient를 Horizontal로 변경시켜 가로 방향으로 위젯이 들어가게 하자. 이 layout 에 file 선택하는 버튼을 넣을 것이다.

 

참고로 최상단의 메뉴바를 보면 정렬 아이콘과 Expand, Strech 아이콘이 있는데, 이것들을 적당히 이용해서 위젯들의 배치를 원하는 형태로 할 수 있다. Expand는 위젯을 좌우로 꽉 차게 만들어 주고, Strech는 상하로 꽉차게 만들어 준다. 난 layout에 대한 개념들이 꽤 혼동스러웠는데, 사실 처음 기대는 마우스 드래그 드롭으로 위젯들을 위치시키는 것이었다.

03.jpg

 

위젯들을 이용해 모양 꾸미기

Additional을 보면 File Picker가 있는데, wxRuby API 에는 wxFilePickerCtrl이 없다. 아마 Additional에 있는 위젯들은 사용할 수 없나보다. 그냥 Common 탭의 TextCtrl과 Button을 사용해서 파일을 선택하는 UI를 만들자.

TextCtrl 위젯을 만들어 넣고, file_text라고 이름을 적어주자.

Button 위젯을 만들어 넣고, label을 Browse, 이름을 browse_btn라고 해 주자.

다시 Button 위젯을 하나 넣고, label을 Upload, 이름을 upload_btn이라고 해 주자. 참고로 button style의 wxBU_EXACTFIT를 선택하면 label의 크기에 맞게 버튼의 크기가 변경된다.

04.jpg

 

이제 하단에는 업로드 목록을 보여주는 list를 만들자. wxBoxSizer를 하나 더 추가해서 ListCtrl을 추가한다. ListCtrl의 Expand와 Strech를 모두 눌러서 layout에 리스트 위젯이 꽉 차도록 한다. 리스트 위젯의 이름을 item_list로 하고 subclass를 ItemListCtrl로 하자.

05.jpg

 

애플리케이션의 디자인을 대강 마쳤으니 이 디자인을 XRC 파일로 저장하자. 그것은 File > Generate를 이용하거나 단축키 F8을 눌러도 된다. storyq_uploader/uploader_frame.xrc가 생성된다.

 

XRC 로 ruby code 생성하기

wx_suger는 wxWiget를 좀더 Ruby 스럽게 사용할 수 있게 해 준다고 한다. 여기에서는 XRCise를 사용하기 위해 wx_sugar를 설치한다.

  1. gem install wx_sugar

 

XRCise 는 XRC를 Ruby code로 손쉽게 변경시켜 준다. uploader_frame.xrc가 있는 디렉토리로 이동해서 다음 명령을 수행한다.

  1. xrcise -o uploader_frame.rb uploader_frame.xrc

위 명령은 uploader_frame.rb라는 ruby 파일을 생성시킨다. 파일을 열어보면 내가 만든 wxRuby 위젯 클래스들이 선언되어 있다. 좋구나~~

 

Evnet 엮어주기

main.rb 파일을 storyq_uploader 폴더에 생성해서 다음과 같이 만들자.

  1. require "rubygems"
  2. require "storyq_client"
    require "wx"
    require "uploader_frame"
    require "iconv"
      
    module ItemListCtrl
      def add_box(box)
        item = Wx::ListItem.new
        item.set_data(box)
        item.set_text(box.title || "")
        insert_item(item)
      end
    end

    class UploaderFrame < UploaderFrameBase
      attr_accessor :storyq
     
      def initialize
        super
        @storyq = StoryQ(:consumer_token => "un2BidBxRoNQEGsyRFCHcA",
          :consumer_secret => "To6CrYQTMYtxBeQJGn3W9CIBoWAdasoxmpe09w5xE",
          :site => "http://www.storyq.com")   
        evt_button(browse_btn) { |event| choose_file(event) }
        evt_button(upload_btn) { |event| upload_file(event) }
      end
     
      def show_upload_dialog
        @upload_dialog = UploadFormDialog.new(self)
        @upload_dialog.show_modal
        @upload_dialog.destroy
        show_my_boxes
      end
     
      def choose_file(event)
        file_dialog = Wx::FileDialog.new(self, "업로드할 파일을 선택하세요" )
        if file_dialog.show_modal == Wx::ID_OK
          file_text.value = file_dialog.get_path
        end
      end 
     
      def upload_file(event)
        return show_message("파일을 선택하지 않았네요~~") if file_text.is_empty
       
        box = @storyq.slide_boxes.create("filename" => Iconv.iconv("EUC-KR", "UTF-8", file_text.value).to_s)
        item_list.add_box(box)
      end 
    end

    Wx::App.run do
      UploaderFrame.new.show
    end

 

코드 설명

browse_btn이 클릭될 때 choose_file 메쏘드가 호출되어 FileDialog 위젯을 부르도록 한다. 다양한 event들을 다룰 수 있다.

  1. evt_button(browse_btn) { |event| choose_file(event) }

파일 선택이 제대로 이루어지면 file_text.value를 선택한 파일의 path로 채운다.

  1. file_text.value = file_dialog.get_path

 

upload_btn이 클릭될 때 upload_file 메쏘드가 호출되어 스토리큐에 선택한 파일을 업로드하도록 한다.

  1. evt_button(upload_btn) { |event| upload_file(event) }

참고로, storyq_client는 storyq에 upload를 수행할 수 있는 라이브러리다. 이것을 사용하면

  1. @storyq.slide_boxes.create("filename" => "file.ppt", "title"=>"hello") 

와 같은 식으로 스토리큐에 파일 업로드를 수행할 수 있다. 주의할 점은 선택한 파일에 한글에 한글이 포함되어 있는 경우 에러가 발생할 수 있다. 이것을 방지하기 위해 file_text.value를 Iconv를 이용해 UTF-8로 변경해 준다.

 

업로드를 마친 후 item_list 에 업로드한 box를 추가한다.

  1. item_list.add_box(box)

add_box를 ItemListCtrl에 구현한다. ItemListCtrl은 wxFormBuilder로 디자인을 할 때 item_list 위젯에서 subclass로 적어준 것이다. xrcise에 의해 생성된 uploader_frame.rb를 보면 item_list가 ItemListCtrl을 extend하고 있음을 알 수있다.

  1. # in uploader_frame.rb
  2. @item_list.extend(ItemListCtrl)

 

업로드할 파일을 드래그 앤 드롭으로 추가하기

좀 더 편리해지기 위해 업로드할 파일을 item_list 에 드래그 드롭하면 업로드가 되도록 해 보자. 이 기능을 위해서 set_drop_target 메쏘드를 이용할 수 있다.

UploaderFrame 의 initialize에 다음을 추가하자.

  1. item_list.set_drop_target(MyFileDropTarget.new(self))

 

그리고 MyFileDropTarget을 다음과 같이 만들자.

  1. class MyFileDropTarget < Wx::FileDropTarget
      def initialize(parent)
        super()
        @parent = parent
      end
     
      def on_drop_files(x, y, filename)
  2.   filename.each do |file|
  3.      box = @parent.storyq.slide_boxes.create("filename" => file)
         @parent.item_list.add_box(box)
  4.    end  
      end
    end

filename에는 드롭되는 파일들이 배열로 들어 있다.

 

exe로 만들기

rubyscript2exe 를 이용해서 exe로 만들 수 있다. 그런데 잘 안되는군.

 다음과 같은 에러 발생, gem 1.2에서는 안되는듯.

  1. c:/ruby/lib/ruby/site_ruby/1.8/rubygems/remote_fetcher.rb:19: uninitialized constant Gem::Exception (NameError)

 

다음에 설명이 있는데, 뭔소린지..

http://xslforum.com/29865-about-circular-dependencies-rubygems-library-about-theorder.html

 

써보니

즐겁기는 한데, 감탄할 만큼 멋지지는 않은듯.

 

 

 

이 글은 스프링노트에서 작성되었습니다.