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

求助:基于GTK+与Cairo实现多页打印的技术问题

我来帮你搞定GTK+多页打印的问题!要实现带统一标题的多页内容打印,核心是用好GtkPrintOperation的分页机制,在对应的信号回调里处理页数计算和每页内容绘制。下面是完整的思路和可直接运行的代码示例:

核心实现思路
  • 用GtkPrintOperation作为打印核心组件,它会自动处理打印对话框、分页逻辑和渲染流程。
  • 在begin-print信号中计算总页数:根据每页能容纳的条目数和你的vector总长度,向上取整确定总页数。
  • 在draw-page信号中绘制单页内容:根据当前页码,计算该页要打印的内容范围,然后统一绘制标题和对应条目。
完整代码示例(以gtkmm 3.x为例)

假设你使用的是gtkmm(GTK+的C++绑定),代码如下:

#include <gtkmm.h>
#include <vector>
#include <string>
#include <cmath>

class MultiPagePrintWindow : public Gtk::Window {
public:
    MultiPagePrintWindow() {
        set_title("GTK+ 多页打印演示");
        set_default_size(300, 200);
        set_border_width(10);

        // 创建打印按钮并绑定点击事件
        m_print_btn.set_label("开始打印");
        m_print_btn.signal_clicked().connect(sigc::mem_fun(*this, &MultiPagePrintWindow::on_print_button_clicked));

        // 布局窗口内容
        m_vbox.pack_start(m_print_btn, Gtk::PACK_SHRINK);
        add(m_vbox);
        show_all_children();

        // 初始化数据:0到50的数字字符串
        for (int i = 0; i <= 50; ++i) {
            m_number_list.push_back(std::to_string(i));
        }
    }

private:
    void on_print_button_clicked() {
        auto print_op = Gtk::PrintOperation::create();
        print_op->set_job_name("数字列表打印任务");

        // 绑定打印相关信号
        print_op->signal_begin_print().connect(sigc::mem_fun(*this, &MultiPagePrintWindow::on_begin_print));
        print_op->signal_draw_page().connect(sigc::mem_fun(*this, &MultiPagePrintWindow::on_draw_page));

        // 弹出打印对话框并执行打印
        auto result = print_op->run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, *this);
        if (result != Gtk::PRINT_OPERATION_RESULT_SUCCESS) {
            std::cerr << "打印被取消或执行失败" << std::endl;
        }
    }

    void on_begin_print(const Glib::RefPtr<Gtk::PrintContext>& print_ctx) {
        const int items_per_page = 31; // 按你的需求,每页放31条(0-30为第一页)
        // 向上取整计算总页数
        m_total_pages = static_cast<int>(std::ceil(static_cast<double>(m_number_list.size()) / items_per_page));
        print_ctx->get_print_operation()->set_n_pages(m_total_pages);
    }

    void on_draw_page(const Glib::RefPtr<Gtk::PrintContext>& print_ctx, int page_num) {
        cairo_t* cr = print_ctx->get_cairo_context();
        const double page_width = print_ctx->get_width();
        const double page_height = print_ctx->get_height();
        const double margin = 25; // 页面边距
        double current_y = margin;

        // 1. 绘制每页统一的标题(居中显示)
        auto title_layout = Pango::Layout::create(cr);
        Pango::FontDescription title_font("Sans 16 Bold");
        title_layout->set_font_description(title_font);
        title_layout->set_text("数字列表打印");
        int title_width, title_height;
        title_layout->get_pixel_size(title_width, title_height);
        double title_x = (page_width - title_width) / 2;
        cairo_move_to(cr, title_x, current_y);
        title_layout->show_in_cairo_context(cr);
        current_y += title_height + 20; // 标题后留间距

        // 2. 计算当前页要打印的条目范围
        const int items_per_page = 31;
        int start_idx = page_num * items_per_page;
        int end_idx = std::min(start_idx + items_per_page, static_cast<int>(m_number_list.size()));

        // 3. 绘制当前页的数字条目
        auto content_layout = Pango::Layout::create(cr);
        Pango::FontDescription content_font("Sans 12");
        content_layout->set_font_description(content_font);
        int item_height;
        for (int i = start_idx; i < end_idx; ++i) {
            content_layout->set_text(m_number_list[i]);
            content_layout->get_pixel_size(title_width, item_height);
            cairo_move_to(cr, margin, current_y);
            content_layout->show_in_cairo_context(cr);
            current_y += item_height + 8; // 条目间留小间距
        }
    }

    Gtk::Box m_vbox{Gtk::ORIENTATION_VERTICAL, 10};
    Gtk::Button m_print_btn;
    std::vector<std::string> m_number_list;
    int m_total_pages = 0;
};

int main(int argc, char* argv[]) {
    auto app = Gtk::Application::create(argc, argv, "com.example.multipageprint");
    MultiPagePrintWindow window;
    return app->run(window);
}
关键细节说明
  • 页数计算:在begin-print中通过向上取整的方式,确保所有内容都能被分配到对应页面,不会遗漏条目。
  • 页面绘制:draw-page信号会为每一页触发一次,通过page_num(从0开始)定位当前页的内容范围,再用Pango处理文本排版,保证标题居中、条目整齐。
  • 边距与间距:设置页面边距和内容间距,避免内容紧贴页面边缘,提升打印可读性。
编译运行(Linux环境)

如果在Linux系统上,使用g++编译时需要链接gtkmm库:

g++ multi_page_print.cpp -o multi_page_print `pkg-config --cflags --libs gtkmm-3.0`

运行编译后的程序,点击按钮就能打开打印对话框,预览或打印多页内容了。

内容的提问来源于stack exchange,提问作者fik236

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:11:01