带有条目的组合框
通过指定ComboBox构造函数的has_entry参数为true,可以令其包含一个Entry部件用以输入任意文本。
11.6.1. 文本列
为了使Entry可以与下拉列表的选项进行交互,你必须使用set_entry_text_column()指定哪些模型列是文本列。例如:
m_combo.set_entry_text_column(m_columns.m_col_name);
当你从下拉菜单中选择一个选项的时候,该列的值将被放于Entry中。
11.6.2. 条目
由于用户可以输入任意文本,被使用中的模型行可能不足以告诉我们用户输入了什么,因此,你应该使用ComboBox::get_entry()方法检索组合框中的Entry部件并在其上调用get_text()。
11.6.3. 响应变更
当用户输入任意文本时,只连接到为每个键入字符而发出的changed信号可能是不够的。当用户按下Enter键的时候,这个信号不会被发出。而按下Enter或是键盘焦点被移动到另一个部件的时候,可以表示用户已经完成了输入。为了收到这些事件的通知,你需要连接到Entry的activate和focus_out_event信号像是这样
auto entry = m_Combo.get_entry(); if (entry) { // 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) ); }
X事件在附录的X事件信号小节有更详细的描述。
11.6.4. 完整例子
File: examplewindow.h (For use with gtkmm 4)
#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_combo_changed(); void on_entry_changed(); void on_entry_has_focus_changed(); //Signal connection: sigc::connection m_ConnectionHasFocusChanged; bool m_entry_had_focus {false}; //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: 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() : 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: auto row = *(m_refTreeModel->append()); row[m_Columns.m_col_id] = "1"; row[m_Columns.m_col_name] = "Billy Bob"; /* auto 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, Gtk::PackOptions::EXPAND_WIDGET); 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. set_child(m_Combo); //Connect signal handlers: m_Combo.signal_changed().connect(sigc::mem_fun(*this, &ExampleWindow::on_combo_changed)); auto entry = m_Combo.get_entry(); if (entry) { entry->signal_changed().connect(sigc::mem_fun(*this, &ExampleWindow::on_entry_changed) ); m_ConnectionHasFocusChanged = entry->property_has_focus().signal_changed(). connect(sigc::mem_fun(*this, &ExampleWindow::on_entry_has_focus_changed)); } else std::cout << "No Entry ???" << std::endl; } ExampleWindow::~ExampleWindow() { // The has_focus changed 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_ConnectionHasFocusChanged.disconnect(); } void ExampleWindow::on_combo_changed() { auto entry = m_Combo.get_entry(); if (entry) { std::cout << "on_combo_changed(): Row=" << m_Combo.get_active_row_number() << ", ID=" << entry->get_text() << std::endl; } } 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_has_focus_changed() { auto entry = m_Combo.get_entry(); if (entry) { const bool entry_has_focus = entry->has_focus(); if (m_entry_had_focus && !entry_has_focus) { // entry->has_focus() has changed from true to false; entry has lost focus. std::cout << "on_entry_has_focus_changed() to not focused: Row=" << m_Combo.get_active_row_number() << ", ID=" << entry->get_text() << std::endl; } m_entry_had_focus = entry_has_focus; } }
11.6.5. 简单文字示例
File: examplewindow.h (For use with gtkmm 4)
#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_changed(); void on_entry_has_focus_changed(); //Signal connection: sigc::connection m_ConnectionHasFocusChanged; bool m_entry_had_focus {false}; //Child widgets: Gtk::ComboBoxText m_Combo; }; #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() : 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); set_child(m_Combo); //Connect signal handlers: m_Combo.signal_changed().connect(sigc::mem_fun(*this, &ExampleWindow::on_combo_changed) ); auto entry = m_Combo.get_entry(); if (entry) { entry->signal_changed().connect(sigc::mem_fun(*this, &ExampleWindow::on_entry_changed)); m_ConnectionHasFocusChanged = entry->property_has_focus().signal_changed(). connect(sigc::mem_fun(*this, &ExampleWindow::on_entry_has_focus_changed)); } else std::cout << "No Entry ???" << std::endl; m_Combo.property_has_frame() = false; } ExampleWindow::~ExampleWindow() { // The has_focus changed 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_ConnectionHasFocusChanged.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_changed() { std::cout << "on_entry_changed(): Row=" << m_Combo.get_active_row_number() << ", Text=" << m_Combo.get_active_text() << std::endl; } void ExampleWindow::on_entry_has_focus_changed() { auto entry = m_Combo.get_entry(); if (entry) { const bool entry_has_focus = entry->has_focus(); if (m_entry_had_focus && !entry_has_focus) { // entry->has_focus() has changed from true to false; entry has lost focus. std::cout << "on_entry_has_focus_changed() to not focused: Row=" << m_Combo.get_active_row_number() << ", ID=" << entry->get_text() << std::endl; } m_entry_had_focus = entry_has_focus; } }