You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用gtkmm时如何读取文件浮点数?及数据传递至绘图区问题

GTKmm浮点数读取异常修复及数据传递方案

一、修复文件读取浮点数的问题

问题根源

两次读取结果不一致,核心原因是GTK初始化会修改全局区域设置(locale):

  • main中先创建的C对象,此时GTK未启动,程序使用默认的C locale,能正确解析.作为小数点的浮点数;
  • 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:43:12