单项容器

大多数单项容器部件具有其子部件的set_child()unset_child()方法。Gtk::ButtonGtk::Window从技术上来说是单项容器,但是我们已经在其他地方讨论过它们。

我们还讨论了Gtk::Paned部件,它允许你将窗口分为两个单独的"窗格",这个部件实际上可以包含两个子部件,但是他只能包含固定数量的部件,因此也将其称为单项容器。

9.1.1. 框架(Frame)

框架可以将一个或一组部件封装在一个框内,还可以为他们选择标题。例如你可以将一组ToggleButton或者CheckButton放入一个Frame中。

参考

9.1.1.1. 示例

Figure 9-1框架(Frame)

源代码

File: examplewindow.h (For use with gtkmm 4)

#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 (For use with gtkmm 4)

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

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<ExampleWindow>(argc, argv);
}

File: examplewindow.cc (For use with gtkmm 4)

#include "examplewindow.h"

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

  /* Sets the margin around the frame. */
  m_Frame.set_margin(10);

  set_child(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::END);
}

ExampleWindow::~ExampleWindow()
{
}

9.1.2. 窗格(Paned)

窗格用一个可移动的分隔符将一个部件一分为二。其可以水平(使两个窗格并排)也可以竖直(使两个窗格一个在另一个之上)的分隔部件。

与本小节的其他小部件不一样的是,窗格部件包含两个子部件而不是一个部件(每个窗格中一个)。因此你应该用set_start_child()set_end_child()替代set_child()方法。

如果你需要,你可以使用set_position()调整分割线的位置。

参考

9.1.2.1. 示例

Figure 9-2窗格(Paned)

源代码

File: examplewindow.h (For use with gtkmm 4)

#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::Paned m_VPaned;
  MessagesList m_MessagesList;
  MessageText m_MessageText;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: messageslist.h (For use with gtkmm 4)

#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 (For use with gtkmm 4)

#ifndef GTKMM_EXAMPLE_MESSAGETEXT_H
#define GTKMM_EXAMPLE_MESSAGETEXT_H

#include <gtkmm.h>

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

  void insert_text();

protected:
  Gtk::TextView m_TextView;
};

#endif //GTKMM_EXAMPLE_MESSAGETEXT_H

File: main.cc (For use with gtkmm 4)

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

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<ExampleWindow>(argc, argv);
}

File: examplewindow.cc (For use with gtkmm 4)

#include "examplewindow.h"

ExampleWindow::ExampleWindow()
: m_VPaned(Gtk::Orientation::VERTICAL)
{
  set_title ("Paned Windows");
  set_default_size(450, 400);
  m_VPaned.set_margin(10);

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

  /* Now add the contents of the two halves of the window */
  m_VPaned.set_start_child(m_MessagesList);
  m_VPaned.set_end_child(m_MessageText);
}

ExampleWindow::~ExampleWindow()
{
}

File: messageslist.cc (For use with gtkmm 4)

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

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

  set_child(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;

    auto 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);
}

MessagesList::~MessagesList()
{
}

File: messagetext.cc (For use with gtkmm 4)

#include "messagetext.h"

MessageText::MessageText()
{
  set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);

  set_child(m_TextView);
  insert_text();
}

MessageText::~MessageText()
{
}

void MessageText::insert_text()
{
  auto refTextBuffer = m_TextView.get_buffer();

  auto 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");
}

9.1.3. 滚动窗口

ScrolledWindow部件会创建一个可以滚动的区域。你可以将任何类型的部件插入到ScrolledWindow中,无论该部件有多大你都可以通过滚动条来访问它。请注意虽然ScrolledWindow的名称像是Gtk::Window的衍生部件,但其实不是。

滚动窗口具有用于确定是否要显示Scrollbar(滚动条)scrollbar policies(滚动条策略)。你可以使用set_policy()方法来设置策略。例如设置策略为Gtk::PolicyType::AUTOMATIC或是Gtk::PolicyType::ALWAYS。当策略为Gtk::PolicyType::AUTOMATIC的时候,只有在被包含的部件大于可见区域的时候滚动条才会被显示出来。而Gtk::PolicyType::ALWAYS将使滚动条始终显示。

参考

9.1.3.1. 示例

这是一个简单的示例,其将100个开关按钮放入滚动窗口中。你可以尝试调整窗口的大小,以查看滚动条的反应。

Figure 9-3滚动窗口

源代码

File: examplewindow.h (For use with gtkmm 4)

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm.h>

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

protected:
  //Signal handlers:
  void on_dialog_response(int response_id);

  //Child widgets:
  Gtk::ScrolledWindow m_ScrolledWindow;
  Gtk::Grid m_Grid;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc (For use with gtkmm 4)

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

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<ExampleWindow>(argc, argv);
}

File: examplewindow.cc (For use with gtkmm 4)

#include "examplewindow.h"
#include <iostream>

ExampleWindow::ExampleWindow()
{
  set_title("Gtk::ScrolledWindow example");
  set_size_request(300, 300);

  m_ScrolledWindow.set_margin(10);

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

  get_content_area()->append(m_ScrolledWindow);

  /* set the spacing to 10 on x and 10 on y */
  m_Grid.set_row_spacing(10);
  m_Grid.set_column_spacing(10);

  /* pack the grid into the scrolled window */
  m_ScrolledWindow.set_child(m_Grid);

  /* this simply creates a grid of toggle buttons
   * 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);
        auto pButton = Gtk::make_managed<Gtk::ToggleButton>(buffer);
        m_Grid.attach(*pButton, i, j, 1, 1);
     }
  }

  /* Add a "close" button to the bottom of the dialog */
  add_button("_Close", Gtk::ResponseType::CLOSE);
  signal_response().connect(sigc::mem_fun(*this, &ExampleWindow::on_dialog_response));

  /* This makes it so the button is the default.
   * Simply hitting the "Enter" key will cause this button to activate. */
  set_default_response(Gtk::ResponseType::CLOSE);
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_dialog_response(int response_id)
{
  switch (response_id)
  {
  case Gtk::ResponseType::CLOSE:
  case Gtk::ResponseType::DELETE_EVENT:
    hide();
    break;
  default:
    std::cout << "Unexpected response_id=" << response_id << std::endl;
    break;
  }
}

9.1.4. 定比框架(AspectFrame)

AspectFrame部件和Frame部件类似,但它强制子部件的aspect ratio(长宽比)(长与宽的比例)保持不变。并在有必要的时候添加额外的空间。例如,这将允许你显示照片并且无需在用户调整窗口大小的时候对照片进行水平/垂直变形。

参考

9.1.4.1. 示例

下面的程序使用Gtk::AspectFrame显示一个绘图区域,无论用户如何调整顶层窗口大小宽高比依旧保持2:1。

Figure 9-4定比框架(AspectFrame)

源代码

File: examplewindow.h (For use with gtkmm 4)

#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::Frame m_Frame;
  Gtk::DrawingArea m_DrawingArea;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: main.cc (For use with gtkmm 4)

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

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<ExampleWindow>(argc, argv);
}

File: examplewindow.cc (For use with gtkmm 4)

#include "examplewindow.h"

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

  // Set 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_content_width(200);
  m_DrawingArea.set_content_height(200);
  m_Frame.set_child(m_DrawingArea);
  m_AspectFrame.set_child(m_Frame);
  m_AspectFrame.set_margin(10);

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

ExampleWindow::~ExampleWindow()
{
}

9.1.5. 其他单项容器

还有其他的单项容器。请参阅参考文档获取完整列表。这里是一些本教程其他地方未曾提及的显示容器的示例程序的链接。

扩展器(Expander)源代码

气泡(Popover)源代码