如何在Gtkmm中持续检测Gtk::Calendar选中日期的变化?
实现Gtk::Calendar选中日期变化的事件监听与事件排序
嗨,我来帮你搞定这个需求!其实你完全不需要写后台持续检测的逻辑——GTK本身就是事件驱动的框架,Gtk::Calendar自带了专门的信号来监听选中日期的变化,用这个比后台轮询高效太多了。
下面是具体的实现步骤和代码示例:
核心思路:利用GTK的信号机制
Gtk::Calendar提供了day_selected信号,每当用户选中新的日期(不管是点击日期、切换月份还是年份),这个信号就会自动触发。我们只需要把这个信号和自定义的回调函数绑定,在回调里完成日期获取和事件排序的操作就行。
完整代码示例
#include <gtkmm.h> #include <vector> #include <iostream> class MyWindow : public Gtk::Window { public: MyWindow() { // 设置窗口布局(用水平Box放置日历和列表) set_title("日期事件管理器"); set_default_size(600, 400); m_main_box.set_orientation(Gtk::ORIENTATION_HORIZONTAL); add(m_main_box); // 初始化日历组件 m_main_box.pack_start(m_calendar, Gtk::PACK_SHRINK); // 初始化列表存储与树视图 m_event_columns.add(m_col_name); m_event_columns.add(m_col_deadline); m_list_store = Gtk::ListStore::create(m_event_columns); m_tree_view.set_model(m_list_store); m_tree_view.append_column("事件名称", m_col_name); m_tree_view.append_column("截止日期", m_col_deadline); m_main_box.pack_start(m_tree_view, Gtk::PACK_EXPAND_WIDGET); // 绑定日历的日期选中信号到回调函数 m_calendar.signal_day_selected().connect( sigc::mem_fun(*this, &MyWindow::on_date_selected_changed) ); // 模拟添加一些测试事件 add_test_events(); show_all_children(); } private: // 定义列表存储的列结构 class EventColumns : public Gtk::TreeModel::ColumnRecord { public: EventColumns() { add(name); add(deadline); } Gtk::TreeModelColumn<Glib::ustring> name; Gtk::TreeModelColumn<Glib::Date> deadline; // 用Glib::Date做精确日期比较 }; EventColumns m_event_columns; Gtk::TreeModelColumn<Glib::ustring> m_col_name = m_event_columns.name; Gtk::TreeModelColumn<Glib::Date> m_col_deadline = m_event_columns.deadline; Gtk::Box m_main_box; Gtk::Calendar m_calendar; Glib::RefPtr<Gtk::ListStore> m_list_store; Gtk::TreeView m_tree_view; std::vector<std::pair<Glib::ustring, Glib::Date>> m_all_events; // 存储所有事件的数据源 // 添加测试事件 void add_test_events() { Glib::Date date1(20, 5, 2024); // 日、月、年(月份从1开始) Glib::Date date2(21, 5, 2024); Glib::Date date3(21, 5, 2024); m_all_events.emplace_back("完成项目报告", date1); m_all_events.emplace_back("部门周会", date2); m_all_events.emplace_back("提交代码版本", date3); } // 日期变化时的回调函数 void on_date_selected_changed() { // 获取当前选中的日期 unsigned int year, month, day; m_calendar.get_date(year, month, day); // 注意:GTK的calendar.get_date返回的月份是从0开始的,需要转成1-based Glib::Date selected_date(day, month + 1, year); // 对事件进行筛选+排序:筛选出截止日期等于选中日期的事件,按名称排序 m_list_store->clear(); for (const auto& event : m_all_events) { if (event.second == selected_date) { Gtk::TreeModel::Row row = *(m_list_store->append()); row[m_col_name] = event.first; row[m_col_deadline] = event.second; } } // 如果需要更复杂的排序(比如按截止日期远近),可以用TreeModelSort // auto sort_model = Gtk::TreeModelSort::create(m_list_store); // sort_model->set_sort_func(m_col_deadline, sigc::ptr_fun(sort_by_deadline)); // m_tree_view.set_model(sort_model); } // 可选:自定义排序函数示例 static int sort_by_deadline(const Gtk::TreeModel::iterator& a, const Gtk::TreeModel::iterator& b) { Glib::Date date_a, date_b; *a >> date_a; *b >> date_b; return date_a.compare(date_b); } }; int main(int argc, char* argv[]) { auto app = Gtk::Application::create(argc, argv, "org.example.calendar_event_sorter"); MyWindow window; return app->run(window); }
关键细节说明
- 信号选择:除了
day_selected,还有month_changed(切换月份时触发)、day_selected_double_clicked(双击日期触发)等信号,可根据需求灵活选用。 - 日期处理:示例中用
Glib::Date存储截止日期,相比字符串能更精准地进行日期比较,避免格式不一致的问题。 - 排序优化:如果事件数量较多,建议使用
Gtk::TreeModelSort来实现内置排序,无需手动清空列表再重新添加,性能更优。
这样一来,每当用户改变日历的选中日期,回调函数就会自动执行,完成事件的筛选或排序操作,完全不需要后台循环检测,既高效又符合GTK的设计理念。
内容的提问来源于stack exchange,提问作者KJ465
相关产品推荐
相关产品推荐

