Windows環境にて、C++からlibxlsxwriterを呼び出してExcelファイル(*.xlsx)を作成する方法を説明します。
開発環境 | Visual Studio 2022 |
---|---|
言語 | C++ |
ライブラリ | libxlsxwriter 1.1.5 zlib 1.3 |
動作確認 | Windows 11 Windows 10 Windows 7 |
準備
「libxlsxwriter」(https://github.com/jmcnamara/libxlsxwriter)は、Excelファイルを作成するための、WindowsやUNIX系OS等の複数のプラットフォームに対応するライブラリです。開発環境にも実行環境にもExcelは不要です。ただし、読み込み機能は、ありません。以下、libxlsxwriterをVisual Studio 2022にてビルドする手順です。
(1)
最初に、zlibを作成します。何故、zlibが必要かというと、Excelファイル(*.xlsx)の正体はzipファイルだからです。https://zlib.net/からソース(zlib13.zip)をダウンロードして、展開します。
(2)
ターミナルより、[Developer Command Prompt for VS 2022]を起動します(または、[スタート]-[すべてのアプリ]-[Visual Studio 2022]-[Developer Command Prompt for VS 2022])。仮に、ソースの展開先を「C:\temp\zlib13\zlib-1.3」、生成されるライブラリの出力先を「C:\temp\zlib13\zlib」とする場合、以下のコマンドを実行します。その際、-Aオプションは、組み込み先のソリューションプラットフォームに合わせます。x86の場合、「Win32」を指定します。
> cd C:\temp\zlib13\zlib-1.3
> mkdir build
> cd build
> cmake .. -G "Visual Studio 17 2022" -A x64 -D CMAKE_INSTALL_PREFIX:PATH="C:\temp\zlib13\zlib"
> cmake --build . --config Release --target install
(3)
次に、libxlsxwriterを作成します。https://github.com/jmcnamara/libxlsxwriterのReleasesからソース(libxlsxwriter-RELEASE_1.1.5.zip)をダウンロードして、展開します。
(4)
仮に、ソースの展開先を「C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter-RELEASE_1.1.5」、生成されるライブラリの出力先を「C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter」とする場合、以下のコマンドを実行します。その際、-Aオプションは、組み込み先のソリューションプラットフォームに合わせます。x86の場合、「Win32」を指定します。
> cd C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter-RELEASE_1.1.5
> mkdir build
> cd build
> cmake .. -G "Visual Studio 17 2022" -A x64 -D CMAKE_INSTALL_PREFIX:PATH="C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter" -D ZLIB_ROOT:STRING="C:\temp\zlib13\zlib"
> cmake --build . --config Release --target install
※「Could NOT find ZLIB (missing: 1.0) (found version "1.3")
」エラーが発生する場合、~\libxlsxwriter-RELEASE_1.1.5\CMakeLists.txtの222行目を以下の通りに修正して、cmakeを再実行してください。
# 修正前
find_package(ZLIB REQUIRED "1.0")
# 修正後
find_package(ZLIB "1.0" REQUIRED)
(5)
出力先より、必要なファイルは以下の通りです。任意の場所に移動することが可能です。
ファイル名 | 備考 |
---|---|
~\libxlsxwriter\include | フォルダー配下のファイル全部 |
~\libxlsxwriter\lib\xlsxwriter.lib | |
~\zlib\lib\zlibstatic.lib | zlibをスタティックリンクする場合、ビルド時に必要 |
~\zlib\lib\zlib.lib | zlibをダイナミックリンクする場合、ビルド時に必要 |
~\zlib\bin\zlib.dll | zlibをダイナミックリンクする場合、実行時に必要。 アプリケーションと同じ、または、パスが通ったフォルダーに配置 |
(6)
プロジェクトのプロパティに以下の設定を追加します。仮の出力先をそのまま使用する例です。任意の場所に移動した場合は、そちらに合わせてください。
[C/C++]-[全般]-[追加のインクルードディレクトリ] |
---|
C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter\include; |
[リンカー]-[全般]-[追加のライブラリディレクトリ] |
C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter\lib;C:\temp\zlib13\zlib\lib; |
[リンカー]-[入力]-[追加の依存ファイル] |
(スタティックリンク) xlsxwriter.lib;zlibstatic.lib; (ダイナミックリンク) xlsxwriter.lib;zlib.lib; |
サンプルソース
libxlsxwriterのライブラリ関数は、C言語にて実装されています。ライブラリ側にてextern "C"
しているので、そのままC++から呼び出しが可能です。
また、引数に渡すパスやテキストの文字コードはUTF-8です。UTF-16からUTF-8に変換する方法は、「【C++/Win32】UTF-16とUTF-8を相互に変換する」を参照してください。
#include <xlsxwriter.h>
// Excelファイルの新規作成
lxw_workbook *workbook = workbook_new("test.xlsx");
// シートの追加
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, nullptr);
// テキストの入力
// 2番目の引数は行のインデックス、3番目の引数は列のインデックス
// いずれもゼロ開始(ゼロゼロがA1)
worksheet_write_string(worksheet, 0, 0, u8"表示するテキスト", nullptr);
// 数値の入力
worksheet_write_number(worksheet, 1, 0, 123.45, nullptr);
worksheet_write_number(worksheet, 2, 0, 654.32, nullptr);
// 式の入力
worksheet_write_formula(worksheet, 3, 0, "=SUM(A2:A3)", nullptr);
// 終了
workbook_close(workbook);

上記の例ならCSVファイルを作成したほうが早いですが、libxlsxwriterは、CSVでは不可能なExcelの機能も実装されています。公式ドキュメント(https://libxlsxwriter.github.io/)にて、チュートリアル、リファレンス、サンプルソース等、詳しく説明されています。
シートを追加する
同じブックに対して、シート毎にworkbook_add_worksheet関数を実行します。
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, nullptr);
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, nullptr);
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, nullptr);
// 2番目の引数はシート名
lxw_worksheet *worksheet4 = workbook_add_worksheet(workbook, u8"2023年");
lxw_worksheet *worksheet5 = workbook_add_worksheet(workbook, u8"2024年");
lxw_worksheet *worksheet6 = workbook_add_worksheet(workbook, u8"2025年");

フォント等を設定する
フォーマットを構成後、各セルに対して設定します。
lxw_format *format = workbook_add_format(workbook);
// メイリオ、サイズ10の例
format_set_font_name(format, u8"メイリオ");
format_set_font_size(format, 10);
worksheet_write_string(worksheet, 0, 0, u8"表示するテキスト", format);
worksheet_write_number(worksheet, 1, 0, 123.45, format);
worksheet_write_number(worksheet, 2, 0, 654.32, format);
worksheet_write_formula(worksheet, 3, 0, "=SUM(A2:A3)", format);
// セルは、以下のような指定も可
worksheet_write_string(worksheet, CELL("A1"), u8"表示するテキスト", format);
worksheet_write_number(worksheet, CELL("A2"), 123.45, format);
worksheet_write_number(worksheet, CELL("A3"), 654.32, format);
worksheet_write_formula(worksheet, CELL("A4"), "=SUM(A2:A3)", format);

ここで、合計のセルのみ背景を黄色にしたい場合、新しく別のフォーマットを構成します。
lxw_format *format_total = workbook_add_format(workbook);
format_set_font_name(format_total, u8"メイリオ");
format_set_font_size(format_total, 10);
format_set_bg_color(format_total, LXW_COLOR_YELLOW);
worksheet_write_formula(worksheet, 3, 0, "=SUM(A2:A3)", format_total);

フォーマット系のリファレンス
https://libxlsxwriter.github.io/working_with_formats.html
列幅を設定する
列幅に合わせて自動的にテキストを縮小するには、format_set_shrink関数を使用します。逆に、テキストに合わせて自動的に列幅を拡大する関数は、ありません。
[列の幅]数値指定
Excelの[列の幅]にて表示される数値(デフォルトは約8)を、worksheet_set_column関数に指定します。実際には、指定した数値と約0.1ずれた幅が設定されます。使用するフォントによるのかもしれません。
// 列A~Cに幅20を指定する例
// worksheet_set_column(シート, 開始列, 終了列, 幅, フォーマット)
worksheet_set_column(worksheet, 0, 2, 20, nullptr);
// 列は、以下のような指定も可
worksheet_set_column(worksheet, COLS("A:C"), 20, nullptr);

ピクセル指定
実行環境の画面の「拡大/縮小」が100%の場合、worksheet_set_column_pixels関数にピクセルを直接指定できます。「拡大/縮小」の設定は、Windows 11/10は[設定]-[システム]-[ディスプレイ]-[拡大縮小とレイアウト]、Windows 7は[コントロール パネル]-[デスクトップのカスタマイズ]-[ディスプレイ]です。
// 列A~Cに幅200ピクセルを指定する例
// worksheet_set_column_pixels(シート, 開始列, 終了列, 幅をピクセルで指定, フォーマット)
worksheet_set_column_pixels(worksheet, 0, 2, 200, nullptr);
100%以外の場合、設定を取得して補正する必要があります。以下のソースは、実行環境が何%かに関係なく、テキストに合わせた列幅を設定します。
#include <windows.h>
#include <xlsxwriter.h>
#include <string>
// Windows 11/10
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
// Windows 7
//SetProcessDPIAware();
HDC hdc = GetDC(nullptr);
// テキスト表示に必要なピクセルを取得するためのフォント指定
// メイリオ、サイズ14の例。72は固定値
LOGFONT lf{};
std::wstring fontname = L"メイリオ";
int fontsize = 14;
wcsncpy_s(lf.lfFaceName, fontname.c_str(), fontname.size());
lf.lfHeight = -MulDiv(fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
HFONT hf = CreateFontIndirect(&lf);
HFONT hfOld = (HFONT)SelectObject(hdc, hf);
// ピクセルを取得
// テキストは「テキストの幅に合わせる」の例
SIZE size;
std::wstring str = L"テキストの幅に合わせる";
GetTextExtentPoint32(hdc, str.c_str(), static_cast<int>(str.size()), &size);
// 画面のDPIを取得
int dpi = GetDeviceCaps(hdc, LOGPIXELSX);
// 解放
SelectObject(hdc, hfOld);
DeleteObject(hf);
ReleaseDC(nullptr, hdc);
// ここまで、Win32 APIの処理。取得した値は、size.cxとdpi
// ここから、libxlsxwriterの処理
lxw_workbook *workbook = workbook_new("test.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, nullptr);
// 列Aに、「テキストの幅に合わせる」を表示できる幅を指定する例。96は固定値
worksheet_set_column_pixels(worksheet, 0, 0, MulDiv(size.cx, 96, dpi), nullptr);
// セルA1に、メイリオ、サイズ14にて表示する例
lxw_format *format = workbook_add_format(workbook);
format_set_font_name(format, u8"メイリオ");
format_set_font_size(format, fontsize);
worksheet_write_string(worksheet, 0, 0, u8"テキストの幅に合わせる", format);
workbook_close(workbook);

ここで、GetDeviceCaps(hdc, LOGPIXELSX)が返す値は、「拡大/縮小」が100%なら96、125%なら120、150%なら144、200%なら192です。実際のモニターのDPIとは関係ありません。
また、引数の文字コードは、Win32 APIはUTF-16、libxlsxwriterはUTF-8であることに注意してください。