求助:基于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
相关产品推荐
相关产品推荐

