Glade を使って、gtk3 でボタンを配置していきます。
 
参考)


1.ボタンの作成(Gtk::Button
Glade を起動し、GtkWindowを作り、GtkFixedコンテナを置き、その上に Buttonをドラッグします。

それぞれの設定は;
○GtkWindow
 ・ID: window_1 
 ・Title: button window
 ・デフォルトの幅: 300
 ・デフォルトの高さ: 200
 ・Signal: destroy, Handler: gtk_main_quit

○GtkFixed
 デフォルトのまま

○GtkButton
 ・ID: button1 
 ・Label: Button 1
 ・Packing;X位置: 10,Y位置: 10
 ・Common;要求する幅: 100,要求する高さ: 50


glade_button_1_glade


(license; public domain)
・glade_button_1.ui
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window_1">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">button window</property>
    <property name="default_width">300</property>
    <property name="default_height">200</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkFixed">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">Button 1</property>
            <property name="width_request">100</property>
            <property name="height_request">50</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
          </object>
          <packing>
            <property name="x">10</property>
            <property name="y">10</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

・glade_button_1.rb
require 'gtk3'

builder = Gtk::Builder.new
builder.add_from_file("glade_button_1.ui")

win = builder.get_object("window_1")

def gtk_main_quit
  Gtk.main_quit
end

builder.connect_signals {|handler| method(handler)}
win.show_all
Gtk.main

glade_button_1




2.ボタンの見た目を変える
Ruby のプログラム側で、CSS で設定します(Gtk::CssProvider)
 
○Gtk::CssProvider.new
 CSSオブジェクトを作成します

○Gtk::CssProvider#load(data: string)
 data: CSSの文字列 の形で読み込みます
 ・string;CSSの設定
 
○Gtk::CssProvider#load_from_path(filename)
 CSSファイルを読み込みます
 ・filename;CSSファイル

○Gtk::Window#style_context.add_provider(css_provider, Gtk::StyleProvider::PRIORITY_USER)
 ウィンドウにCSSの設定を加えます
 ・css_provider;Gtk::CssProviderクラス

○CSSの設定
a)ボタンの指定
・ボタン(通常時) button
・ボタン(マウスオーバー時) button:hove
・ボタン(押された時) button:active
button {
  color: green;
}

button:hover {
  color: #0000FF;
}

button:active {
  color: rgb(255,0,0);
}

button と書くと Gtk::Button 全体の設定になります。
また、色の指定の仕方もいろいろあります。


さらに、CSSで ID指定やクラス指定もできます。
その場合は XMLファイルも書き換えます。
Glade を起動して、
・スタイルID で指定する場合
「Common」>「Widget Attributes」>「ウィジェット名」
 自分で決めた ID を記入します
(「General」の「ID」ではないことに注意!)

・クラスで指定する場合
「Common」>「Widget Attributes」>「Style Classes」
の<Type Here> をクリックして、自分で決めたクラス名を記入します
(enterキーを押さないと確定しません)

その後、CSSファイルを設定します。
・スタイルID で指定する場合(button_widget とします)
 #を付けて指定します
#button_widget {
  color: cyan;
}

・スタイルクラスで指定する場合(button_style とします)
 .を付けて指定します
.button_style {
  color: #00FFFF;
}



b)設定項目
・背景色
 background-color:
 ※もし、背景色が変わらなかったら、background-image: none; という行を追加します。
  または、background-image: image(cyan); のように設定します。
→・[gtk3] Color setting of the Gtk/Button does not affect ・ Issue #1084 ・ ruby-gnome2/ruby-gnome2

・文字の色
 color:
・文字のサイズ
 font: 40 px;

・文字フォントの設定
 font-family: Serif;
 (フォントファミリーの設定;Serif,sans-serif など)

※ macOS では、以下のような警告が出ます;
Gtk-WARNING **: Theme parsing error: <data>:6:10: Not using units is deprecated. Assuming 'px'.
 24 px のように指定しているのですが、警告は消えません。また、他の単位 em,%,pt などだとエラーになります。


以上の設定をまとめた例です;
button {
  background-image: none;
  background-color: yellow;
  color: green;
  font: 40 px;
  font-family: sans-serif;
}

button:hover {
  background-image: none;
  background-color: #00FFFF;
  color: #0000FF;
  font-family: Serif;
}

button:active {
  background-image: none;
  background-color: rgb(0,255,0);
  color: rgb(255,0,0);
  font: 60 px;
}
 
・glade_button_2.ui
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window_1">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">button window</property>
    <property name="default_width">300</property>
    <property name="default_height">200</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkFixed">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">Button 1</property>
            <property name="width_request">100</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
          </object>
          <packing>
            <property name="x">10</property>
            <property name="y">10</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
 ・glade_button_2.rb
require 'gtk3'

builder = Gtk::Builder.new
builder.add_from_file("glade_button_2.ui")

win     = builder.get_object("window_1")
button1 = builder.get_object("button1")

css_provider = Gtk::CssProvider.new
css_provider.load(data:
"
 button {
  background-image: none;
  background-color: yellow;
  color: green;
  font: 40 px;
  font-family: sans-serif;
}

button:hover {
  background-image: none;
  background-color: #00FFFF;
  color: #0000FF;
  font-family: Serif;
}

button:active {
  background-image: none;
  background-color: rgb(0,255,0);
  color: rgb(255,0,0);
  font: 60 px;
}
")
button1.style_context.add_provider(css_provider, Gtk::StyleProvider::PRIORITY_USER)

def gtk_main_quit
  Gtk.main_quit
end

builder.connect_signals {|handler| method(handler)}
win.show_all
Gtk.main

glade_button_2_normal
(通常時)

glade_button_2_hover(マウスが上にある時)

glade_button_2_active(ボタンを押した時)



3.ボタンの動作を設定する
○Glade側の設定
Glade を起動し、GtkButton(ID: button1)を選択し、「Signal」>「GtkButton」>「clicked」
を選びます。「Handler」名を入力します。(数文字入れて削除すると候補が出るのでその中から選んでもいいです)
ここでは、候補の中にあった「on_button1_clicked」にしました。

glade_button_3_glade

・glade_button_3.ui
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window_1">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">button window</property>
    <property name="default_width">300</property>
    <property name="default_height">200</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkFixed">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">Button 1</property>
            <property name="width_request">100</property>
            <property name="height_request">50</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <signal name="clicked" handler="on_button1_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="x">10</property>
            <property name="y">10</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>


○Ruby側の設定
ハンドラー名をメソッドとして記述します。
def on_button1_clicked
  puts 'clicked'
end
最後に、Glade で設定したハンドラーを全てメソッドとして登録します。
builder.connect_signals {|handler| method(handler)}


・glade_button_3.rb
require 'gtk3'

builder = Gtk::Builder.new
builder.add_from_file("glade_button_3.ui")

win = builder.get_object("window_1")

def gtk_main_quit
  Gtk.main_quit
end

def on_button1_clicked
  puts 'clicked'
end

builder.connect_signals {|handler| method(handler)}
win.show_all
Gtk.main

glade_button_3
glade_button_3_term2
ボタンをクリックすると、ターミナルに「clicked」と出力されます。
(Enterキーを押しても同じ動作をします)



4.Enterキーを押された時の設定
ボタンが複数ある場合、Enterキーを押された時にどのボタンがクリックされたことになるかを設定します。

ここでは、button1 と button2 があり、Enterキーを押された時に button2 がクリックされたことになるよう設定する例で説明します。

4-A. フォーカスを設定する
フォーカスは初期状態の設定をしますが、別のボタンにフォーカスが移ると、それ以降は戻ってきません。

Gladeを起動し、button2 の「Common」>「フォーカスあり」にチェックを入れます。
(ハンドラーは button1,button2 とも同じ名前で「on_button_clicked」にしました。)

glade_button_focus_glade


・glade_button_focus.ui
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window_1">
    <property name="can_focus">False</property>
    <property name="default_width">300</property>
    <property name="default_height">200</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkFixed">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">Button 1</property>
            <property name="width_request">100</property>
            <property name="height_request">50</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">False</property>
            <signal name="clicked" handler="on_button_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="x">10</property>
            <property name="y">10</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button2">
            <property name="label" translatable="yes">Button 2</property>
            <property name="width_request">150</property>
            <property name="height_request">80</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="has_focus">True</property>
            <property name="receives_default">False</property>
            <signal name="clicked" handler="on_button_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="x">80</property>
            <property name="y">100</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
・glade_button_focus.rb
require 'gtk3'

builder = Gtk::Builder.new
builder.add_from_file("glade_button_focus.ui")

win = builder.get_object("window_1")

def gtk_main_quit
  Gtk.main_quit
end

def on_button_clicked(widget)
  puts "#{widget.label} is clicked"
end

builder.connect_signals {|handler| method(handler)}
win.show_all
Gtk.main

glade_button_focus
glade_button_focus_glade_term
最初に Enterキーを押した時(3回)は「Button 2 is clicked.」と出力されます。
次に、「button1」をクリックすると、「Button 1 is clicked.」と出力され、
その後  Enterキーを押しても、「Button 1 is clicked.」のままで、「button 2」には戻りません。


4-B. デフォルトを設定する
デフォルトは常にそのボタンが Enterキーを押した時に選ばれ、別のボタンをクリックしても他に移りません。
 
Gladeを起動し、button2 の「Common」>「デフォルト可否」と「デフォルトあり」にチェックを入れます。
(ハンドラーは button1,button2 とも同じ名前で「on_button_clicked」です。)


glade_button_default_glade
 

・glade_button_default.ui
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window_1">
    <property name="can_focus">False</property>
    <property name="default_width">300</property>
    <property name="default_height">200</property>
    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
    <child>
      <object class="GtkFixed">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">Button 1</property>
            <property name="width_request">100</property>
            <property name="height_request">50</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">False</property>
            <signal name="clicked" handler="on_button_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="x">10</property>
            <property name="y">10</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button2">
            <property name="label" translatable="yes">Button 2</property>
            <property name="width_request">150</property>
            <property name="height_request">80</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="can_default">True</property>
            <property name="has_default">True</property>
            <property name="receives_default">False</property>
            <signal name="clicked" handler="on_button_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="x">80</property>
            <property name="y">100</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

・glade_button_default.rb
require 'gtk3'

builder = Gtk::Builder.new
builder.add_from_file("glade_button_default.ui")

win = builder.get_object("window_1")

def gtk_main_quit
  Gtk.main_quit
end

def on_button_clicked(widget)
  puts "#{widget.label} is clicked"
end

builder.connect_signals {|handler| method(handler)}
win.show_all
Gtk.main


glade_button_default

glade_button_default_term

最初に Enterキーを押した時(3回)は「Button 2 is clicked.」と出力されます。
次に、「button1」をクリックすると、「Button 1 is clicked.」と出力され、
その後  Enterキーを押すと、「Button 2 i clicked.」になり、「button 2」に戻ります。