Chapter 7. コンテナウィジット

Table of Contents

全てのコンテナウィジットはGtk::Containerから派生しています(直接に、とは限りません)。いくつかのコンテナウィジット、Gtk::Tableなどは多数の子ウィジットを保持することができますから、ふつう、複雑なインターフェイスを持っています。一方、Gtk::Frameなどはただ一つの子ウィジットしか持てません。

単一アイテムコンテナ

単一アイテムコンテナウィジットはGtk::Binから派生しています。Gtk::Binadd()remove()メソッドを子ウィジットに対して提供しています。Gtk::ButtonGtk::Windowは、技術的には単一アイテムコンテナであることに注意してください。このことはもう既に他のところで書いています。

Gtk::Panedウィジットについても説明します。これはウィンドウを区切って二つの“ペーン”に分割するものです。ウィジットは実際には二つの子ウィジットを持っているわけですが、数が固定されているのでここで説明するのがいいでしょう。

フレーム

フレームは、一つまたは一グループのウィジットを箱の中に納めることができます(オプションでタイトルを付けることもできます)。例えば、RadioButtonCheckButtonFrameに置くことができます。

Reference

Figure 7.1. Frame

Frame

Source Code

File: examplewindow.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:

  //Child widgets:
  Gtk::Frame m_Frame;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc

#include <gtkmm/main.h>
#include "examplewindow.h"

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}

File: examplewindow.cc

#include "examplewindow.h"

ExampleWindow::ExampleWindow()
{
 /* Set some window properties */
  set_title("Frame Example");
  set_size_request(300, 300);

  /* Sets the border width of the window. */
  set_border_width(10);

  add(m_Frame);

  /* Set the frames label */
  m_Frame.set_label("Gtk::Frame Widget");

  /* Align the label at the right of the frame */
  //m_Frame.set_label_align(Gtk::ALIGN_RIGHT, Gtk::ALIGN_TOP);

  /* Set the style of the frame */
  m_Frame.set_shadow_type(Gtk::SHADOW_ETCHED_OUT);

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

ペーン

ペーンは動かすことのできるで仕切りでウィジットを二つに分割します。ペーンウィジットは二つあります: Gtk::HPanedは水平の仕切りを、Gtk::VPanedは垂直の仕切りを加えます。名前と方向以外に二つのウィジットの違いはありません。

この章にある他ウィジットと違って、ペーンウィジットは一つではなく二つの子ウィジットを保持し、それぞれの枠の中に一つずつ入れます。ですから、add()メソッドではなくadd1()add2()を使ってください。

仕切りの位置はset_position()メソッドで調節することができます。そうする必要があるはずです。

Reference

Figure 7.2. Paned

Paned

Source Code

File: examplewindow.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include "messageslist.h"
#include "messagetext.h"
#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:

  //Child widgets:
  Gtk::VPaned m_VPaned;
  MessagesList m_MessagesList;
  MessageText m_MessageText;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: messageslist.h

#ifndef GTKMM_EXAMPLE_MESSAGESLIST_H
#define GTKMM_EXAMPLE_MESSAGESLIST_H

#include <gtkmm.h>

class MessagesList: public Gtk::ScrolledWindow
{
public:
  MessagesList();
  virtual ~MessagesList();

  class ModelColumns : public Gtk::TreeModel::ColumnRecord
  {
  public:

    ModelColumns()
    { add(m_col_text); }

    Gtk::TreeModelColumn<Glib::ustring> m_col_text;
  };

  ModelColumns m_Columns;

protected:
  Glib::RefPtr<Gtk::ListStore> m_refListStore; //The Tree Model.
  Gtk::TreeView m_TreeView; //The Tree View.
};
#endif //GTKMM_EXAMPLE_MESSAGESLIST_H

File: messagetext.h

#ifndef GTKMM_EXAMPLE_MESSAGETEXT_H
#define GTKMM_EXAMPLE_MESSAGETEXT_H

#include <gtkmm.h>

class MessageText : public Gtk::ScrolledWindow
{
public:
  MessageText();
  virtual ~MessageText();

  virtual void insert_text();

protected:
  Gtk::TextView m_TextView;
};

#endif //GTKMM_EXAMPLE_MESSAGETEXT_H

File: main.cc

#include <gtkmm/main.h>
#include "examplewindow.h"

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}

File: messageslist.cc

#include "messageslist.h"
#include <sstream>

MessagesList::MessagesList()
{
  /* Create a new scrolled window, with scrollbars only if needed */
  set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

  add(m_TreeView);

  /* create list store */
  m_refListStore = Gtk::ListStore::create(m_Columns);

  m_TreeView.set_model(m_refListStore);

  /* Add some messages to the window */
  for(int i = 0; i < 10; ++i)
  {
    std::ostringstream text;
    text << "message #" << i;

    Gtk::TreeModel::Row row = *(m_refListStore->append());
    row[m_Columns.m_col_text] = text.str();
  }

  //Add the Model's column to the View's columns:
  m_TreeView.append_column("Messages", m_Columns.m_col_text);

  show_all_children();
}

MessagesList::~MessagesList()
{
}

File: messagetext.cc

#include "messagetext.h"

MessageText::MessageText()
{
  set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

  add(m_TextView);
  insert_text();

  show_all_children();
}

MessageText::~MessageText()
{
}

void MessageText::insert_text()
{
  Glib::RefPtr<Gtk::TextBuffer> refTextBuffer = m_TextView.get_buffer();

  Gtk::TextBuffer::iterator iter = refTextBuffer->get_iter_at_offset(0);
  refTextBuffer->insert(iter,
    "From: pathfinder@nasa.gov\n"
    "To: mom@nasa.gov\n"
    "Subject: Made it!\n"
    "\n"
    "We just got in this morning. The weather has been\n"
    "great - clear but cold, and there are lots of fun sights.\n"
    "Sojourner says hi. See you soon.\n"
    " -Path\n");
}

File: examplewindow.cc

#include "examplewindow.h"

ExampleWindow::ExampleWindow()
{
  set_title ("Paned Windows");
  set_border_width(10);
  set_default_size(450, 400);

  /* Add a vpaned widget to our toplevel window */
  add(m_VPaned);

  /* Now add the contents of the two halves of the window */
  m_VPaned.add1(m_MessagesList);
  m_VPaned.add2(m_MessageText);

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

スクロールドウィンドウ

ScrolledWindowウィジットはスクロールできる領域を生成するのに使われます。ScrolledWindowウィンドウなかにはどんな型のウィジットでも挿入でき、スクロールバーを使ってそのサイズに関わらずアクセスできるようにできます。注意してください、ScrolledWindowは名前が似ていますがGtk::Windowとは違います。

スクロールドウィンドウにはスクロールバーポリシーという、どのScrollbarが表示されるか決定するための方針があります。これはset_policy()メソッドによって設定することができます。ポリシーはGtk::POLICY_AUTOMATICGtk::POLICY_ALWAYSのどちらかです。Gtk::POLICY_AUTOMATICを設定すると、スクロールドウィンドウに、その内蔵するウィジットが表示領域より大きくなった時のみスクロールバーを表示するようになります。Gtk::POLICY_ALWAYSではスクロールバーを常に表示するようになります。

Reference

次の簡単な例が、100個のトグルボタンをスクロールドウィンドウに詰めたものです。ウィンドウをリサイズしてスクロールバーがどうなるか試してください。

Figure 7.3. ScrolledWindow

ScrolledWindow

Source Code

File: examplewindow.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow : public Gtk::Dialog
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  //Signal handlers:
  virtual void on_button_close();

  //Child widgets:
  Gtk::ScrolledWindow m_ScrolledWindow;
  Gtk::Table m_Table;
  Gtk::Button m_Button_Close;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc

#include <gtkmm/main.h>
#include "examplewindow.h"

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}

File: examplewindow.cc

#include "examplewindow.h"
#include <stdio.h> //For sprintf()

ExampleWindow::ExampleWindow()
: m_Table(10, 10),
  m_Button_Close("Close")
{
  set_title("Gtk::ScrolledWindow example");
  set_border_width(0);
  set_size_request(300, 300);

  m_ScrolledWindow.set_border_width(10);

  /* the policy is one of Gtk::POLICY AUTOMATIC, or Gtk::POLICY_ALWAYS.
   * Gtk::POLICY_AUTOMATIC will automatically decide whether you need
   * scrollbars, whereas Gtk::POLICY_ALWAYS will always leave the scrollbars
   * there.  The first one is the horizontal scrollbar, the second,
   * the vertical. */
  m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);

  get_vbox()->pack_start(m_ScrolledWindow);

  /* set the spacing to 10 on x and 10 on y */
  m_Table.set_row_spacings(10);
  m_Table.set_col_spacings(10);

  /* pack the table into the scrolled window */
  m_ScrolledWindow.add(m_Table);

  /* this simply creates a grid of toggle buttons on the table
   * to demonstrate the scrolled window. */
  for(int i = 0; i < 10; i++)
  {
     for(int j = 0; j < 10; j++)
     {
        char buffer[32];
        sprintf(buffer, "button (%d,%d)\n", i, j);
        Gtk::Button* pButton = Gtk::manage(new Gtk::ToggleButton(buffer));
        m_Table.attach(*pButton, i, i + 1, j, j + 1);
     }
  }

  /* Add a "close" button to the bottom of the dialog */
  m_Button_Close.signal_clicked().connect( sigc::mem_fun(*this,
              &ExampleWindow::on_button_close));

  /* this makes it so the button is the default. */
  m_Button_Close.set_flags(Gtk::CAN_DEFAULT);

  Gtk::Box* pBox = get_action_area();
  if(pBox)
    pBox->pack_start(m_Button_Close);

  /* This grabs this button to be the default button. Simply hitting
   * the "Enter" key will cause this button to activate. */
  m_Button_Close.grab_default();

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_button_close()
{
  hide();
}

アスペクトフレーム

AspectFrameウィジットはFrameとよく似ています。しかし、このウィジットは子ウィジットのアスペクト比(高さと幅の比)を設定することができます(足りないところには空白が追加されます)。これを使えば、例えば写真を表示するときに、ユーザーがウィジットをリサイズしても写真を歪めてしまわないようにすることができます。

Reference

以下のプログラムはAspectFrameを使い、描画領域をアスペクト比が常に 2:1 になるように表示します。ユーザーがどれほどトップレベルにあるウィンドウをリサイズしても変わりません。

Figure 7.4. AspectFrame

AspectFrame

Source Code

File: examplewindow.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:

  //Child widgets:
  Gtk::AspectFrame m_AspectFrame;
  Gtk::DrawingArea m_DrawingArea;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc

#include <gtkmm/main.h>
#include "examplewindow.h"

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}

File: examplewindow.cc

#include "examplewindow.h"

ExampleWindow::ExampleWindow()
: m_AspectFrame("2x1", /* label */
    Gtk::ALIGN_CENTER, /* center x */
    Gtk::ALIGN_CENTER, /* center y */
    2.0, /* xsize/ysize = 2 */
    false /* ignore child's aspect */)
{
  set_title("Aspect Frame");
  set_border_width(10);

  // Add a child widget to the aspect frame */
  // Ask for a 200x200 window, but the AspectFrame will give us a 200x100
  // window since we are forcing a 2x1 aspect ratio */
  m_DrawingArea.set_size_request(200, 200);
  m_AspectFrame.add(m_DrawingArea);

  // Add the aspect frame to our toplevel window:
  add(m_AspectFrame);

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

アライメント

Alignmentウィジットを使えば、あるウィジットの位置とサイズを決めるのに、Alignmentのサイズに対して相対的に行うことができます。これは、例えば、ウィジットを中央配置する場合に使えます。

Alignmentの特性を設定するにはコンストラクタで行うか、set()メソッドを使ってください。ここで、パラメタxscaleyscaleに1.0以外を設定しないと、何の変化も観察できないはずです。なぜなら、1.0が意味するのは単に子ウィジットを利用可能な最大のスペースにまで広げることだからです。

Reference

この例ではボタンをウィンドウの中で右揃えにしています。Alignmentをウィジットに対して使っています。

Figure 7.5. Alignment

Alignment

Source Code

File: examplewindow.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  //Signal handlers:
  virtual void on_button_clicked();

  //Child widgets:
  Gtk::Alignment m_Alignment;
  Gtk::Button m_Button;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc

#include <gtkmm/main.h>
#include "examplewindow.h"

int main(int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  ExampleWindow window;
  //Shows the window and returns when it is closed.
  Gtk::Main::run(window);

  return 0;
}

File: examplewindow.cc

#include "examplewindow.h"

ExampleWindow::ExampleWindow()
: m_Alignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, 0.0, 0.0),
  m_Button("Close")
{
  set_title("Gtk::Alignement");
  set_border_width(10);
  set_default_size(200, 50);

  add(m_Alignment);

  m_Alignment.add(m_Button);

  m_Button.signal_clicked().connect( sigc::mem_fun(*this,
              &ExampleWindow::on_button_clicked) );

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_button_clicked()
{
  hide();
}

Alignmentを使う別の例はプログレスバーのセクションを見てください。