Tables
This page explains how to create tables with rix/pdf.
The examples use the public Rix facade:
#include <rix.hpp>and access PDF through:
rix.pdfTables are useful for generated reports, summaries, invoices, exports, dashboards, and simple structured documents.
Basic table example
Create a file:
mkdir -p ~/rix-pdf-tables
cd ~/rix-pdf-tables
touch tables.cppAdd:
#include <rix.hpp>
int main()
{
auto doc = rix.pdf.document();
doc.set_title("Rix PDF Table Example");
auto &page = doc.add_page();
auto y = page.heading(
page.x_left(),
page.y_top(),
"Project table",
1);
y -= 20.0F;
rixlib::pdf::Table table;
table.set_column_widths({
160.0F,
160.0F,
160.0F});
table.add_header({
"Name",
"Language",
"Project"});
table.add_row({
"Ada",
"C++",
"Rix"});
table.add_row({
"Gaspard",
"C++",
"Vix.cpp"});
table.add_row({
"Grace",
"Systems",
"PDF"});
page.table(
page.x_left(),
y,
table);
auto saved = rix.pdf.save(doc, "table.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}
rix.debug.print("created:", "table.pdf");
return 0;
}Run it:
vix run tables.cppIf Rix is not available yet for single-file usage:
vix install -g rix/rix
vix run tables.cppThis creates:
table.pdfCreate a table
Use:
rixlib::pdf::Table table;A table stores rows, cells, column widths, and styling.
A table is drawn on a page with:
page.table(x, y, table);Set column widths
Use:
table.set_column_widths({
160.0F,
160.0F,
160.0F});Column widths are expressed in PDF points.
One point is 1/72 inch.
You can also use unit helpers:
table.set_column_widths({
rixlib::pdf::inches(2.0F),
rixlib::pdf::inches(2.0F),
rixlib::pdf::inches(2.0F)});Add a header row
Use:
table.add_header({
"Name",
"Language",
"Project"});A header row is marked as a header and uses header styling.
Add normal rows
Use:
table.add_row({
"Ada",
"C++",
"Rix"});Example:
table.add_row({
"Gaspard",
"C++",
"Vix.cpp"});
table.add_row({
"Grace",
"Systems",
"PDF"});Draw the table
Use:
page.table(
page.x_left(),
y,
table);The first argument is the X position.
The second argument is the starting Y position.
The third argument is the table.
The function returns the Y position below the table:
y = page.table(
page.x_left(),
y,
table);Use the returned Y position when you want to continue writing below the table.
Continue after a table
y = page.table(
page.x_left(),
y,
table);
y -= 20.0F;
page.paragraph(
page.x_left(),
y,
page.content_width(),
"This text appears below the table.");Table rows
For simple rows, use:
table.add_row({
"Ada",
"C++",
"Rix"});For more control, create a row manually:
rixlib::pdf::TableRow row;
row.add_cell("Ada");
row.add_cell("C++");
row.add_cell("Rix");
table.add_row(std::move(row));Header rows manually
You can also mark a row as a header manually:
rixlib::pdf::TableRow header;
header.set_header(true);
header.add_cell("Name");
header.add_cell("Language");
header.add_cell("Project");
table.add_row(std::move(header));For most cases, prefer:
table.add_header({
"Name",
"Language",
"Project"});Row height
Set a row height:
rixlib::pdf::TableRow row;
row.set_height(28.0F);
row.add_cell("Ada");
row.add_cell("C++");
row.add_cell("Rix");
table.add_row(std::move(row));If no row height is set, the table style row height is used.
Table cells
For simple cells, use strings:
row.add_cell("Ada");For more control, use TableCell:
rixlib::pdf::TableCell cell{"Ada"};
cell.set_align(rixlib::pdf::Align::Center);
cell.set_text_color(rixlib::pdf::Color::blue_color());
row.add_cell(std::move(cell));Cell alignment
A cell can be aligned:
rixlib::pdf::TableCell cell{"Ada"};
cell.set_align(rixlib::pdf::Align::Center);Available values:
rixlib::pdf::Align::Left
rixlib::pdf::Align::Center
rixlib::pdf::Align::Right
rixlib::pdf::Align::JustifyFor table cells, left, center, and right are the most common.
Cell text color
rixlib::pdf::TableCell cell{"Ready"};
cell.set_text_color(
rixlib::pdf::Color::green_color());Cell background color
rixlib::pdf::TableCell cell{"Header"};
cell.set_background_color(
rixlib::pdf::Color::light_gray());Remove the background:
cell.clear_background_color();Cell colspan
A cell can span multiple columns:
rixlib::pdf::TableCell cell{"Summary"};
cell.set_colspan(3);Use colspan for summary rows or section labels.
Complete custom cell example
#include <rix.hpp>
int main()
{
auto doc = rix.pdf.document();
auto &page = doc.add_page();
auto y = page.heading(
page.x_left(),
page.y_top(),
"Custom cells",
1);
y -= 20.0F;
rixlib::pdf::Table table;
table.set_column_widths({
160.0F,
160.0F,
160.0F});
table.add_header({
"Name",
"Status",
"Project"});
rixlib::pdf::TableRow row;
row.add_cell("Ada");
rixlib::pdf::TableCell status{"Ready"};
status.set_align(rixlib::pdf::Align::Center);
status.set_text_color(rixlib::pdf::Color::green_color());
status.set_background_color(rixlib::pdf::Color::light_gray());
row.add_cell(std::move(status));
row.add_cell("Rix");
table.add_row(std::move(row));
page.table(
page.x_left(),
y,
table);
auto saved = rix.pdf.save(doc, "custom-cells.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}
rix.debug.print("created:", "custom-cells.pdf");
return 0;
}Run:
vix run tables.cppTable style
A table has a style object:
auto &style = table.style();Use it to configure:
font
font size
header font
header size
row height
cell padding
border
stripe rows
stripe colorSet table font
table.style()
.set_font(rixlib::pdf::Font::Helvetica)
.set_font_size(10.0F);Set header font
table.style()
.set_header_font(rixlib::pdf::Font::HelveticaBold)
.set_header_size(10.0F);Set row height
table.style()
.set_row_height(24.0F);Set cell padding
table.style()
.set_cell_padding(6.0F);Stripe rows
Enable or disable row striping:
table.style()
.set_stripe_rows(true)
.set_stripe_color(rixlib::pdf::Color::light_gray());Stripe rows make longer tables easier to read.
Borders
Table borders use rixlib::pdf::BorderStyle.
Default borders are thin black lines.
Use no borders:
table.style()
.set_border(rixlib::pdf::BorderStyle::none());Use a custom border:
table.style()
.set_border(
rixlib::pdf::BorderStyle{
0.75F,
rixlib::pdf::Color::gray(),
rixlib::pdf::LineStyle::Solid});Border style helpers
Use:
rixlib::pdf::BorderStyle::thin()
rixlib::pdf::BorderStyle::none()You can also create copies with changes:
auto border =
rixlib::pdf::BorderStyle::thin()
.with_width(0.75F)
.with_color(rixlib::pdf::Color::gray());Disable border sides
auto border = rixlib::pdf::BorderStyle::thin();
border.set_left(false);
border.set_right(false);
table.style().set_border(border);You can control:
top
bottom
left
rightComplete styled table
#include <rix.hpp>
int main()
{
auto doc = rix.pdf.document();
doc.set_title("Styled Table");
auto &page = doc.add_page();
auto y = page.heading(
page.x_left(),
page.y_top(),
"Styled table",
1);
y -= 20.0F;
rixlib::pdf::Table table;
table.set_column_widths({
160.0F,
160.0F,
160.0F});
table.style()
.set_font(rixlib::pdf::Font::Helvetica)
.set_font_size(10.0F)
.set_header_font(rixlib::pdf::Font::HelveticaBold)
.set_header_size(10.0F)
.set_row_height(24.0F)
.set_cell_padding(6.0F)
.set_stripe_rows(true)
.set_stripe_color(rixlib::pdf::Color::light_gray())
.set_border(
rixlib::pdf::BorderStyle{
0.75F,
rixlib::pdf::Color::gray(),
rixlib::pdf::LineStyle::Solid});
table.add_header({
"Name",
"Language",
"Project"});
table.add_row({
"Ada",
"C++",
"Rix"});
table.add_row({
"Gaspard",
"C++",
"Vix.cpp"});
table.add_row({
"Grace",
"Systems",
"PDF"});
page.table(
page.x_left(),
y,
table);
auto saved = rix.pdf.save(doc, "styled-table.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}
rix.debug.print("created:", "styled-table.pdf");
return 0;
}Run:
vix run tables.cppRead table information
Get row count:
rix.debug.print("rows:", table.row_count());Get column count:
rix.debug.print("columns:", table.column_count());Check if a table is empty:
if (table.empty())
{
rix.debug.print("table is empty");
}Access rows:
for (const auto &row : table.rows())
{
rix.debug.print("cells:", row.cells().size());
}Generate table from CSV
You can use rix/csv and rix/pdf together.
#include <rix.hpp>
int main()
{
const auto csv = rix.csv.parse(
"Name,Language,Project\n"
"Ada,C++,Rix\n"
"Gaspard,C++,Vix.cpp\n"
"Grace,Systems,PDF\n");
auto doc = rix.pdf.document();
auto &page = doc.add_page();
auto y = page.heading(
page.x_left(),
page.y_top(),
"CSV table",
1);
y -= 20.0F;
rixlib::pdf::Table table;
table.set_column_widths({
160.0F,
160.0F,
160.0F});
for (std::size_t i = 0; i < csv.size(); ++i)
{
if (i == 0)
{
table.add_header(csv[i]);
}
else
{
table.add_row(csv[i]);
}
}
page.table(
page.x_left(),
y,
table);
auto saved = rix.pdf.save(doc, "csv-table.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}
rix.debug.print("created:", "csv-table.pdf");
return 0;
}Run:
vix run tables.cppMultiple tables
You can draw several tables on the same page by using the returned Y position.
y = page.table(
page.x_left(),
y,
first_table);
y -= 30.0F;
y = page.table(
page.x_left(),
y,
second_table);Make sure there is enough vertical space between tables.
Tables and page layout
page.table(...) draws the table at the given position.
For long tables, keep the layout simple.
Use:
page.x_left()
page.y_top()
page.content_width()
page.y_bottom()to stay inside the visible content area.
For larger reports, split content across multiple pages manually when needed.
Use in a Vix project
Create a Vix application:
vix new pdf-tables --app
cd pdf-tablesAdd Rix:
vix add rix/rix
vix installIn vix.app, make sure Rix is listed under deps:
deps = [
"rix/rix",
]A small vix.app can look like this:
name = "pdf-tables"
type = "executable"
standard = "c++20"
output_dir = "bin"
sources = [
"src/main.cpp",
]
include_dirs = [
"include",
"src",
]
deps = [
"rix/rix",
]
packages = [
"vix",
]
links = [
"vix::vix",
]Then use tables in src/main.cpp:
#include <rix.hpp>
int main()
{
auto doc = rix.pdf.document();
auto &page = doc.add_page();
rixlib::pdf::Table table;
table.set_column_widths({
160.0F,
160.0F,
160.0F});
table.add_header({
"Name",
"Language",
"Project"});
table.add_row({
"Ada",
"C++",
"Rix"});
page.table(
page.x_left(),
page.y_top(),
table);
auto saved = rix.pdf.save(doc, "table.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}
rix.debug.print("created:", "table.pdf");
return 0;
}Build and run:
vix build
vix runSingle-file usage
For small scripts, examples, and experiments:
vix run tables.cppIf Rix is installed globally for single-file usage:
vix install -g rix/rix
vix run tables.cppFor project usage, prefer:
vix add rix/rix
vix installand keep the dependency in vix.app:
deps = [
"rix/rix",
]Use only PDF with the facade
If you want the rix.* facade style but only want PDF mounted, define the feature macro before including rix.hpp:
#define RIX_ENABLE_PDF
#include <rix.hpp>
int main()
{
auto doc = rix.pdf.document();
auto &page = doc.add_page();
rixlib::pdf::Table table;
table.set_column_widths({
160.0F,
160.0F});
table.add_header({
"Name",
"Project"});
table.add_row({
"Ada",
"Rix"});
page.table(
page.x_left(),
page.y_top(),
table);
return rix.pdf.save(doc, "table.pdf").ok() ? 0 : 1;
}When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.
Use the independent package
For independent usage, install:
vix add rix/pdf
vix installIn vix.app:
deps = [
"rix/pdf",
]Then include:
#include <rix/pdf.hpp>Use this style when a project only needs PDF and does not need the full unified Rix facade.
For most application documentation, prefer:
#include <rix.hpp>Common mistakes
Forgetting column widths
Without useful column widths, a table may not layout the way you expect.
Prefer:
table.set_column_widths({
160.0F,
160.0F,
160.0F});Drawing the table too low
This can make the table appear outside the page:
page.table(page.x_left(), -50.0F, table);Start from:
page.y_top()or a Y position returned by a heading or paragraph.
Not using the returned Y position
If you draw text after a table, use the returned position:
y = page.table(page.x_left(), y, table);
y -= 20.0F;Using too many columns
If there are too many columns, they may not fit inside page.content_width().
Reduce column count or use a landscape page:
auto doc = rix.pdf.document(
rixlib::pdf::PageSize::A4().as_landscape());Not checking save errors
Wrong:
rix.pdf.save(doc, "table.pdf");Better:
auto saved = rix.pdf.save(doc, "table.pdf");
if (saved.failed())
{
rix.debug.eprint(
"pdf error:",
rix.pdf.error.to_string(saved.error()),
saved.error().message());
return 1;
}Confusing deps and packages
For a Vix project, do not put Rix packages in packages.
Wrong:
packages = [
"rix/rix",
]Correct:
deps = [
"rix/rix",
]deps is for Vix Registry packages.
packages is for CMake package discovery.
What you should remember
Create a table:
rixlib::pdf::Table table;Set widths:
table.set_column_widths({
160.0F,
160.0F,
160.0F});Add a header:
table.add_header({
"Name",
"Language",
"Project"});Add rows:
table.add_row({
"Ada",
"C++",
"Rix"});Draw the table:
auto y = page.table(
page.x_left(),
page.y_top(),
table);Style the table:
table.style()
.set_font(rixlib::pdf::Font::Helvetica)
.set_font_size(10.0F)
.set_row_height(24.0F)
.set_cell_padding(6.0F);For a Vix project, install Rix:
vix add rix/rix
vix installand use:
deps = [
"rix/rix",
]Next step
Learn drawing primitives.
Next: Drawing