6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Wano Group Advent Calendar2021Advent Calendar 2021

Day 13

RubyでWindowsのGUIアプリを作る

Last updated at Posted at 2021-12-13

この記事は、Wano Group Advent Calendar 2021 の記事です。

背景

何年かに一回WindowsのGUIアプリを作ることがありまして、その最初のバージョンをexerbを使ってRubyで作っていました。
長年それを使いまわしていたのですが、いい加減古すぎるので、新しいやり方で作ろうと探したら、libuiが見つかりましたので、それを使ってみた記録の記事です。

Rubyのコードをexeにするのには、ocraを使いました。

ちなみに筆者はRubyはほとんど書いたことありませんので、コードに変なところがあるかもしれませんが、ご容赦を。

libui

libui はポータブルなUIライブラリということで、Goにもバインディングがあります。

じゃぁ、Goで作ればいいやんという話もありますが、以前のコードを使いまわしたいところもあったので、Rubyのバインディングを使いました。ただ、ドキュメントは整備されていないので、結局Goのドキュメントを見るということにはなるのですが。

これの良いところは、普段どおり、Linuxで開発して、exeを作るときだけ、Windowsでやれば良いというところですね(ちょっとだけはまりどころがありましたが)。

作り方

Rubyのlibuiのドキュメントにもありますが、オブジェクト指向ではないので、基本的には、LibUIから生えているメソッドで各コンポーネントを作っていく感じで、それに対する操作も、LibUIのメソッドで行うと言った感じです。Goのドキュメントでは、型からメソッドが生えているので、若干読み替えが必要になります。

  • Goでは、type EntrySetTextがある
    • e := ui.NewEntry()
    • e.SetText("text")
  • Rubyでは、UI.entry_set_text(entry, 'text') となる
    • e = UI.new_entry
    • UI.entry_set_text(e, "text")

といった感じです。

GUIアプリ作るの久しぶりすぎて、何も覚えてなくいんですが、コンポーネントの大きさは勝手に調整される感じのようです。widthやheightと言った指定がないです(Gridを使えば自由に配置できるのかもしれません)。
Boxを入れ子にしていって、なんとなく配置する感じなのかなと思いました。

コード

試しに、テキストを正規表現で置換するものを作ってみます。

# coding: utf-8

require 'libui'

UI = LibUI

def main()
  
  UI.init

  # ウィンドウを作成
  main_window = UI.new_window('Sipmle Text Replace', 1000, 500, 0)
  # ×ボタンでウィンドウを消せるようにする
  UI.window_on_closing(main_window) do
    puts 'Close window'
    UI.control_destroy(main_window)
    UI.quit
    0
  end

  # 全体のbox
  box  = UI.new_vertical_box
  # 入力/結果用のbox
  box_inout = UI.new_vertical_box
  # 正規表現とボタン入れる用のbox
  box_regexp_button = UI.new_horizontal_box

  # 全体のboxに追加
  UI.box_append(box, box_regexp_button, 0)
  UI.box_append(box, box_inout, 1)

  # 全体のboxをウィンドウに追加
  UI.window_set_child(main_window, box)

  # 入力欄の作成
  entry_label = UI.new_label("テキスト")
  input_entry = UI.new_multiline_entry

  # 結果出力の領域
  result_label = UI.new_label("結果")
  result_entry  = UI.new_multiline_entry
  ## 結果なので入力できないようにする
  UI.multiline_entry_set_read_only(result_entry, 1)

  # 正規表現と置換文字列
  regexp_label = UI.new_label("正規表現")
  regexp_entry = UI.new_entry 
  replace_label = UI.new_label("置換文字列")
  replace_entry = UI.new_entry

  # 実行ボタン
  button = UI.new_button('実行')

  # クリアボタン
  clear_button = UI.new_button('クリア')

  # ボックスに追加
  UI.box_append(box_inout, entry_label, 0)
  UI.box_append(box_inout, input_entry, 1)
  UI.box_append(box_inout, result_label, 0)
  UI.box_append(box_inout, result_entry, 1)
  UI.box_append(box_regexp_button, regexp_label, 0)
  UI.box_append(box_regexp_button, regexp_entry, 1)
  UI.box_append(box_regexp_button, replace_label, 0)
  UI.box_append(box_regexp_button, replace_entry, 1)
  UI.box_append(box_regexp_button, button, 0)
  UI.box_append(box_regexp_button, clear_button, 0)

  # 実行ボタン押された
  UI.button_on_clicked(button) do
    text    = UI.multiline_entry_text(input_entry).to_s
    regexp  = UI.entry_text(regexp_entry).to_s
    replace = UI.entry_text(replace_entry).to_s
    if (text.empty? || regexp.empty? || replace.empty?)
      UI.msg_box(main_window, 'Error', "テキスト/正規表現/置換文字列のいずれかが入力されていません")
    else
      result  = replace(main_window, regexp, replace, text)
      UI.multiline_entry_set_text(result_entry, result)
    end
    0
  end

  # クリアボタン押された
  UI.button_on_clicked(clear_button) do
    UI.multiline_entry_set_text(input_entry, "")
    UI.entry_set_text(regexp_entry, "")
    UI.entry_set_text(replace_entry, "")
  end

  # ウインドウを表示
  UI.control_show(main_window)
  UI.main
  UI.quit
end

def replace(main_window, regexp, replace, text)
  result = ''
  begin
   result = text.gsub(/#{regexp}/, replace)
  rescue => e
   UI.msg_box(main_window, 'Error', e)
  end
  return result
end

main()

見た目

このコードを、ruby sample.rb のように実行すると、下記のように表示されます。

image.png

exeファイル化

ocra を使って、exe ファイルにします。WindowsにRubyを入れるのは、RubyInstallerを使います。

  1. Ruby 3.0.3-1(x64) を入れる
    • コマンドプロンプトで聞かれる選択肢には、1,2,3を入力
  2. インストール終わったら、コマンドプロンプトを立ち上げる
  3. gem install libui
  4. gem install ocra
  5. 下記を実行するとGUIが立ち上がるので、x ボタンで終了させる。その後、exeができあがります。
   ocra  sample.rb   ^
      --dll ruby_builtin_dlls/libssp-0.dll  ^
      --dll ruby_builtin_dlls/libgmp-10.dll  ^
      --dll ruby_builtin_dlls/libffi-7.dll ^
      --gem-all=fiddle ^
      --windows ^
      --icon  sample_icon.ico

^ はLinuxの \ と同じです。

sample_icon.ico は、Windowsのiconファイルです。
こちらの記事を参考にGimpで作成しました。

はまったところ

labelの使い方

Ubuntuで動かしていたときには、動いたのに、Windowsで実行すると動かない、というのがありました。
Labelなんですが、下記のような使い方なのかなと思っていたら、

label = UI.new_label
UI.label_set_text(label, 'text')

単純に、下記で良かったです。上で書くとWindowsではエラーになりました。

label = UI.new_label('text')

というか、Go のNewLabelstring引数に取るので、むしろ、Ubuntuで動いていたのがおかしいのかな...?

ocra で "openssl.so"が読み込めないというエラーが出る

今回あげたコードには含まれていませんが、実際作っていたものでは、opensslをrequireしていました。
その場合に、ocraでexeを作ることはできるのですが、実行時にエラーが発生します。

ちょっとぐぐってみると、twitterやブログにそういった記事が見つかったりました。

Goで書き直すかなーと思っていたのですが、下記のオプションを追加することでちゃんと動きました。

      --dll ruby_builtin_dlls/libcrypto-1_1-x64.dll
      --dll ruby_builtin_dlls/libssl-1_1-x64.dll

後、証明書関係でもエラーが出ることがあるらしいのですが、下記でいけるそうです(試してません)

  --gem-file C:\Ruby30-x64\ssl

終わり

若干はまりましたが、お手軽に作れてよかったです。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?