ComboBox με μια καταχώριση

Μια ComboBox μπορεί να περιέχει ένα γραφικό συστατικό Entry για εισαγωγή ελεύθερου κειμένου, ορίζοντας true για την παράμετρο του κατασκευαστή has_entry.

10.6.1. Η στήλη κειμένου

So that the Entry can interact with the drop-down list of choices, you must specify which of your model columns is the text column, with set_entry_text_column(). For instance:

m_combo.set_entry_text_column(m_columns.m_col_name);

Όταν διαλέγετε μια επιλογή από το πτυσσόμενο μενού, η τιμή από αυτήν τη στήλη θα τοποθετηθεί στην Entry.

10.6.2. Η καταχώριση

Επειδή ο χρήστης μπορεί να εισάγει ένα ελεύθερο κείμενο, μια ενεργή γραμμή προτύπου δεν είναι αρκετή για να πει ποιο κείμενο έχει εισάγει ο χρήστης. Συνεπώς, θα πρέπει να ανακτήσετε το γραφικό συστατικό Entry με τη μέθοδο ComboBox::get_entry() και να καλέσετε get_text() σε αυτό.

10.6.3. Απάντηση σε αλλαγές

When the user enters arbitrary text, it may not be enough to connect to the changed signal, which is emitted for every typed character. It is not emitted when the user presses the Enter key. Pressing the Enter key or moving the keyboard focus to another widget may signal that the user has finished entering text. To be notified of these events, connect to the Entry's activate and focus_out_event signals, like so

Gtk::Entry* entry = m_Combo.get_entry();
if (entry)
{
  // The Entry shall receive focus-out events.
  entry->add_events(Gdk::FOCUS_CHANGE_MASK);

  // Alternatively you can connect to m_Combo.signal_changed().
  entry->signal_changed().connect(sigc::mem_fun(*this,
    &ExampleWindow::on_entry_changed) );

  entry->signal_activate().connect(sigc::mem_fun(*this,
    &ExampleWindow::on_entry_activate) );

  entry->signal_focus_out_event().connect(sigc::mem_fun(*this,
    &ExampleWindow::on_entry_focus_out_event) );
}
The changed signals of ComboBox and Entry are both emitted for every change. It doesn't matter which one you connect to. But only Entry's focus_out_event signal is useful here.

Τα συμβάντα Χ περιγράφονται πιο λεπτομερώς στην ενότητα Σήματα συμβάντων Χ στο παράρτημα.

10.6.4. Πλήρες παράδειγμα

Φιγούρα 10-3ComboBox με καταχώριση

Source Code

File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm/window.h>
#include <gtkmm/combobox.h>
#include <gtkmm/liststore.h>

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

protected:
  //Signal handlers:
  void on_entry_changed();
  void on_entry_activate();
  bool on_entry_focus_out_event(GdkEventFocus* event);

  //Signal connection:
  sigc::connection m_ConnectionFocusOut;

  //Tree model columns:
  class ModelColumns : public Gtk::TreeModel::ColumnRecord
  {
  public:

    ModelColumns()
    { add(m_col_id); add(m_col_name); }

    Gtk::TreeModelColumn<Glib::ustring> m_col_id; //The data to choose - this must be text.
    Gtk::TreeModelColumn<Glib::ustring> m_col_name;
  };

  ModelColumns m_Columns;

  //Child widgets:
  Gtk::ComboBox m_Combo;
  Glib::RefPtr<Gtk::ListStore> m_refTreeModel;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)

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

ExampleWindow::ExampleWindow()
: m_Combo(true /* has_entry */)
{
  set_title("ComboBox example");

  //Create the Tree model:
  //m_refTreeModel = Gtk::TreeStore::create(m_Columns);
  m_refTreeModel = Gtk::ListStore::create(m_Columns);
  m_Combo.set_model(m_refTreeModel);

  //Fill the ComboBox's Tree Model:
  Gtk::TreeModel::Row row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = "1";
  row[m_Columns.m_col_name] = "Billy Bob";
  /*
  Gtk::TreeModel::Row childrow = *(m_refTreeModel->append(row.children()));
  childrow[m_Columns.m_col_id] = 11;
  childrow[m_Columns.m_col_name] = "Billy Bob Junior";

  childrow = *(m_refTreeModel->append(row.children()));
  childrow[m_Columns.m_col_id] = 12;
  childrow[m_Columns.m_col_name] = "Sue Bob";
  */

  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = "2";
  row[m_Columns.m_col_name] = "Joey Jojo";

  row = *(m_refTreeModel->append());
  row[m_Columns.m_col_id] = "3";
  row[m_Columns.m_col_name] = "Rob McRoberts";

  /*
  childrow = *(m_refTreeModel->append(row.children()));
  childrow[m_Columns.m_col_id] = 31;
  childrow[m_Columns.m_col_name] = "Xavier McRoberts";
  */

  //Add the model columns to the Combo (which is a kind of view),
  //rendering them in the default way:
  //This is automatically rendered when we use set_entry_text_column().
  //m_Combo.pack_start(m_Columns.m_col_id);
  m_Combo.pack_start(m_Columns.m_col_name);

  m_Combo.set_entry_text_column(m_Columns.m_col_id);
  m_Combo.set_active(1);

  //Add the ComboBox to the window.
  add(m_Combo);

  //Connect signal handlers:
  auto entry = m_Combo.get_entry();
  if (entry)
  {
    // The Entry shall receive focus-out events.
    entry->add_events(Gdk::FOCUS_CHANGE_MASK);
    // Alternatively you can connect to m_Combo.signal_changed().
    entry->signal_changed().connect(sigc::mem_fun(*this,
      &ExampleWindow::on_entry_changed) );
    entry->signal_activate().connect(sigc::mem_fun(*this,
      &ExampleWindow::on_entry_activate) );
    m_ConnectionFocusOut = entry->signal_focus_out_event().
      connect(sigc::mem_fun(*this, &ExampleWindow::on_entry_focus_out_event) );
  }
  else
    std::cout << "No Entry ???" << std::endl;

  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
  // The focus_out signal may be emitted while m_Combo is being destructed.
  // The signal handler can generate critical messages, if it's called when
  // m_Combo has been partly destructed.
  m_ConnectionFocusOut.disconnect();
}

void ExampleWindow::on_entry_changed()
{
  auto entry = m_Combo.get_entry();
  if (entry)
  {
    std::cout << "on_entry_changed(): Row=" << m_Combo.get_active_row_number()
      << ", ID=" << entry->get_text() << std::endl;
  }
}

void ExampleWindow::on_entry_activate()
{
  auto entry = m_Combo.get_entry();
  if (entry)
  {
    std::cout << "on_entry_activate(): Row=" << m_Combo.get_active_row_number()
      << ", ID=" << entry->get_text() << std::endl;
  }
}

bool ExampleWindow::on_entry_focus_out_event(GdkEventFocus* /* event */)
{
  auto entry = m_Combo.get_entry();
  if (entry)
  {
    std::cout << "on_entry_focus_out_event(): Row=" << m_Combo.get_active_row_number()
      << ", ID=" << entry->get_text() << std::endl;
    return true;
  }
  return false;
}

File: main.cc (For use with gtkmm 3, not gtkmm 2)

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

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

  ExampleWindow window;

  //Shows the window and returns when it is closed.
  return app->run(window);
}

10.6.5. Απλό παράδειγμα κειμένου

Φιγούρα 10-4ComboBoxText με καταχώριση

Source Code

File: examplewindow.h (For use with gtkmm 3, not gtkmm 2)

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include <gtkmm/window.h>
#include <gtkmm/comboboxtext.h>

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

protected:
  //Signal handlers:
  void on_combo_changed();
  void on_entry_activate();
  bool on_entry_focus_out_event(GdkEventFocus* event);

  //Signal connection:
  sigc::connection m_ConnectionFocusOut;

  //Child widgets:
  Gtk::ComboBoxText m_Combo;
};

#endif //GTKMM_EXAMPLEWINDOW_H

File: examplewindow.cc (For use with gtkmm 3, not gtkmm 2)

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

ExampleWindow::ExampleWindow()
: m_Combo(true /* has_entry */)
{
  set_title("ComboBoxText example");

  //Fill the combo:
  m_Combo.append("something");
  m_Combo.append("something else");
  m_Combo.append("something or other");
  m_Combo.set_active(0);

  add(m_Combo);

  //Connect signal handlers:
  auto entry = m_Combo.get_entry();
  // Alternatively you can connect to entry->signal_changed().
  m_Combo.signal_changed().connect(sigc::mem_fun(*this,
    &ExampleWindow::on_combo_changed) );
  if (entry)
  {
    // The Entry shall receive focus-out events.
    entry->add_events(Gdk::FOCUS_CHANGE_MASK);
    entry->signal_activate().connect(sigc::mem_fun(*this,
      &ExampleWindow::on_entry_activate) );
    m_ConnectionFocusOut = entry->signal_focus_out_event().
      connect(sigc::mem_fun(*this, &ExampleWindow::on_entry_focus_out_event) );
  }
  else
    std::cout << "No Entry ???" << std::endl;

  m_Combo.property_has_frame() = false;
  show_all_children();
}

ExampleWindow::~ExampleWindow()
{
  // The focus_out signal may be emitted while m_Combo is being destructed.
  // The signal handler can generate critical messages, if it's called when
  // m_Combo has been partly destructed.
  m_ConnectionFocusOut.disconnect();
}

void ExampleWindow::on_combo_changed()
{
  std::cout << "on_combo_changed(): Row=" << m_Combo.get_active_row_number()
    << ", Text=" << m_Combo.get_active_text() << std::endl;
}

void ExampleWindow::on_entry_activate()
{
  std::cout << "on_entry_activate(): Row=" << m_Combo.get_active_row_number()
    << ", Text=" << m_Combo.get_active_text() << std::endl;
}

bool ExampleWindow::on_entry_focus_out_event(GdkEventFocus* /* event */)
{
  std::cout << "on_entry_focus_out_event(): Row=" << m_Combo.get_active_row_number()
    << ", Text=" << m_Combo.get_active_text() << std::endl;
  return true;
}

File: main.cc (For use with gtkmm 3, not gtkmm 2)

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

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

  ExampleWindow window;

  //Shows the window and returns when it is closed.
  return app->run(window);
}