使用gtkmm时如何读取文件浮点数?及数据传递至绘图区问题
GTKmm浮点数读取异常修复及数据传递方案
一、修复文件读取浮点数的问题
问题根源
两次读取结果不一致,核心原因是GTK初始化会修改全局区域设置(locale):
main中先创建的C对象,此时GTK未启动,程序使用默认的Clocale,能正确解析.作为小数点的浮点数;- 调用
Gtk::Application::create后,GTK会将全局locale切换为系统默认值(比如部分欧洲地区用,做小数点分隔符),此时MyWindow里的C对象读取文件时,.会被当成分隔符,导致1.2345只能读到整数部分1,后续读取失败,double变量保留默认值0。
修复代码
在文件读取的代码块中,临时切换到C locale,避免GTK的locale干扰:
#include <locale> // 新增头文件 struct C { C(const char *s) { // 保存当前locale,读取完成后恢复 auto old_locale = std::locale::global(std::locale("C")); std::fstream f(s); if (!f.is_open()) { std::cerr << "文件打开失败!" << std::endl; std::locale::global(old_locale); return; } double d; if (f >> d) std::cout << d << std::endl; else std::cerr << "读取第一个浮点数失败!" << std::endl; if (f >> d) std::cout << d << std::endl; else std::cerr << "读取第二个浮点数失败!" << std::endl; // 恢复原来的locale,避免影响GTK界面显示 std::locale::global(old_locale); } };
二、数据传递到GTK窗口及绘图区
1. 定义数据存储结构
封装一个专门存储数据的结构体,把文件读取逻辑整合进去:
#include <vector> #include <string> struct DataStore { std::vector<double> values; bool load_from_file(const std::string& filename) { values.clear(); auto old_locale = std::locale::global(std::locale("C")); std::ifstream f(filename); if (!f) { std::locale::global(old_locale); return false; } double d; // 读取文件中所有浮点数 while (f >> d) { values.push_back(d); } std::locale::global(old_locale); return true; } };
2. 在窗口中集成数据与绘图区
让窗口类持有DataStore实例,同时添加Gtk::DrawingArea作为绘图区域,绑定绘图回调函数:
class MyWindow : public Gtk::Window { private: DataStore m_data; Gtk::DrawingArea m_drawing_area; // 绘图回调:使用m_data中的数据绘制内容 bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { if (m_data.values.empty()) return true; // 示例:绘制简单折线图 cr->set_line_width(2.0); cr->move_to(20, 180); // 起始坐标 for (size_t i = 0; i < m_data.values.size(); ++i) { // 将数据映射到窗口坐标范围 double x = 20 + i * 40; double y = 180 - m_data.values[i] * 30; cr->line_to(x, y); } cr->stroke(); // 绘制线条 return true; } public: MyWindow() { set_title("数据可视化"); set_default_size(480, 200); // 将绘图区添加到窗口 set_child(m_drawing_area); // 绑定绘图信号 m_drawing_area.signal_draw().connect(sigc::mem_fun(*this, &MyWindow::on_draw)); // 加载数据 if (!m_data.load_from_file("input")) { std::cerr << "数据加载失败!" << std::endl; } } // 提供外部重新加载数据的接口,加载后通知绘图区重绘 void reload_data(const std::string& filename) { if (m_data.load_from_file(filename)) { m_drawing_area.queue_draw(); } } };
3. 从main函数传递预加载数据(可选)
如果需要在程序启动时先加载数据再传递给窗口,可以修改窗口构造函数支持传入数据:
// 修改MyWindow的构造函数 MyWindow(DataStore data) : m_data(std::move(data)) { set_title("数据可视化"); set_default_size(480, 200); set_child(m_drawing_area); m_drawing_area.signal_draw().connect(sigc::mem_fun(*this, &MyWindow::on_draw)); } // main函数调整 int main(int argc, char *argv[]) { DataStore data; if (!data.load_from_file("input")) { std::cerr << "数据加载失败!" << std::endl; return 1; } auto app = Gtk::Application::create("org.gtkmm.data.viewer"); // 传递预加载的数据给窗口 return app->make_window_and_run<MyWindow>(argc, argv, std::move(data)); }
内容的提问来源于stack exchange,提问作者l1ivi1l
相关产品推荐
相关产品推荐

