From e39aa6587ed0741ec592981672d2aa40957ebf62 Mon Sep 17 00:00:00 2001 From: troldal Date: Sat, 18 Sep 2021 18:02:34 +0200 Subject: [PATCH] Cleanup of demo programs --- Examples/CMakeLists.txt | 5 - Examples/Demo7.cpp | 34 ++- Examples/Demo8.cpp | 21 -- README.md | 574 ++-------------------------------------- 4 files changed, 51 insertions(+), 583 deletions(-) delete mode 100644 Examples/Demo8.cpp diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 6cdb19ed..eb5a229e 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -51,9 +51,4 @@ target_link_libraries(Demo6 PRIVATE OpenXLSX::OpenXLSX) add_executable(Demo7 Demo7.cpp) target_link_libraries(Demo7 PRIVATE OpenXLSX::OpenXLSX) -#======================================================================================================================= -# Define Demo8 target -#======================================================================================================================= -add_executable(Demo8 Demo8.cpp) -target_link_libraries(Demo8 PRIVATE OpenXLSX::OpenXLSX) diff --git a/Examples/Demo7.cpp b/Examples/Demo7.cpp index 4d3bb77c..65d975f1 100644 --- a/Examples/Demo7.cpp +++ b/Examples/Demo7.cpp @@ -10,36 +10,53 @@ using namespace OpenXLSX; int main() { cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #07: Row Handling - Implicit Conversion\n"; + cout << "DEMO PROGRAM #07: Row Data - Implicit Conversion\n"; cout << "********************************************************************************\n"; + + // The previous example showed, among other things, how a std::vector of XLCellValue objects + // could be assigned to to an XLRow object, to populate the data to the cells in that row. + // In fact, this can be done with any container supporting bi-directional iterators, holding + // any data type that is convertible to a valid cell value. This is illustrated in this example. + + // First, create a new document and access the sheet named 'Sheet1'. cout << "\nGenerating spreadsheet ..." << endl; XLDocument doc; doc.create("./Demo07.xlsx"); auto wks = doc.workbook().worksheet("Sheet1"); + // A std::vector holding values that are convertible to a cell value can be assigned to an XLRow + // object, using the 'values()' method. For example ints, doubles, bools and std::strings. wks.row(1).values() = std::vector { 1, 2, 3, 4, 5, 6, 7, 8 }; wks.row(2).values() = std::vector { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8 }; wks.row(3).values() = std::vector { true, false, true, false, true, false, true, false }; wks.row(4).values() = std::vector { "A", "B", "C", "D", "E", "F", "G", "H" }; + // Save the sheet... cout << "Saving spreadsheet ..." << endl; doc.save(); doc.close(); + // ...and reopen it (just to make sure that it is a valid .xlsx file) cout << "Re-opening spreadsheet ..." << endl << endl; doc.open("./Demo07.xlsx"); wks = doc.workbook().worksheet("Sheet1"); + // The '.values()' method returns a proxy object that can be converted to any container supporting + // bi-directional iterators. The following three blocks shows how the row data can be converted to + // std::vector, std::deque, and std::list. In principle, this will also work with non-stl containers, + // e.g. containers in the Qt framework. This has not been tested, though. + + // Conversion to std::vector cout << "Conversion to std::vector ..." << endl; for (auto& row : wks.rows()) { - // for (auto& value : std::vector(row.values())) { - for (auto& value : row.values>()) { + for (auto& value : std::vector(row.values())) { cout << value << " "; } cout << endl; } + // Conversion to std::deque cout << endl << "Conversion to std::deque ..." << endl; for (auto& row : wks.rows()) { for (auto& value : std::deque(row.values())) { @@ -48,6 +65,7 @@ int main() cout << endl; } + // Conversion to std::list cout << endl << "Conversion to std::list ..." << endl; for (auto& row : wks.rows()) { for (auto& value : std::list(row.values())) { @@ -56,6 +74,11 @@ int main() cout << endl; } + // In addition to supporting any bi-directional container types, the cell values can also be converted to + // compatible plain data types instead of XLCellValue objects, e.g. ints, doubles, bools and std::string. + // This is illustrated in the following three blocks: + + // Conversion to std::vector<[int, double, bool, std::string]> cout << endl << "Conversion to std::vector<[int, double, bool, std::string]> ..." << endl; for (auto& value : std::vector(wks.row(1).values())) cout << value << " "; cout << endl; @@ -66,9 +89,9 @@ int main() for (auto& value : std::vector(wks.row(4).values())) cout << value << " "; cout << endl; + // Conversion to std::deque<[int, double, bool, std::string]> cout << endl << "Conversion to std::deque<[int, double, bool, std::string]> ..." << endl; - // for (auto& value : std::deque(wks.row(1).values())) cout << value << " "; - for (auto& value : wks.row(1).values>()) cout << value << " "; + for (auto& value : std::deque(wks.row(1).values())) cout << value << " "; cout << endl; for (auto& value : std::deque(wks.row(2).values())) cout << value << " "; cout << endl; @@ -77,6 +100,7 @@ int main() for (auto& value : std::deque(wks.row(4).values())) cout << value << " "; cout << endl; + // Conversion to std::list<[int, double, bool, std::string]> cout << endl << "Conversion to std::list<[int, double, bool, std::string]> ..." << endl; for (auto& value : std::list(wks.row(1).values())) cout << value << " "; cout << endl; diff --git a/Examples/Demo8.cpp b/Examples/Demo8.cpp deleted file mode 100644 index d64298b3..00000000 --- a/Examples/Demo8.cpp +++ /dev/null @@ -1,21 +0,0 @@ - -#include -#include - -using namespace std; -using namespace OpenXLSX; - -int main() -{ - cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #06: Reset Calculation Chain\n"; - cout << "********************************************************************************\n"; - - XLDocument doc; - doc.open("./Demo01.xlsx"); - doc.workbook().setFullCalculationOnLoad(); - doc.saveAs("./Demo01_CalcReset.xlsx"); - doc.close(); - - return 0; -} \ No newline at end of file diff --git a/README.md b/README.md index a332e4ac..64e1f03b 100644 --- a/README.md +++ b/README.md @@ -30,52 +30,6 @@ smaller feature set than for other languages. Because there are no open source library that fully fitted my needs, I decided to develop the OpenXLSX library. -Here is a summary of the main C++ libraries for Excel files that I'm -aware of: - -### libxls - -The libxls library (https://sourceforge.net/projects/libxls/) is a C -library for reading files in the legacy Excel file format, .xls. It -cannot be used for writing or modifying Excel files. - -### xlslib - -The xlslib library (https://sourceforge.net/projects/xlslib/) is a C/C++ -library for creating files in the legacy Excel file format, .xls. It -cannot be used for reading or modifying Excel files. - -### libxlsxwriter - -The libxlsxwriter library (https://libxlsxwriter.github.io) is a C -library for creating .xlsx files. It cannot be used for reading or -modifying Excel files. - -### LibXL - -The LibXL library (http://www.libxl.com) can read, write, create and -modify Excel files, in both the .xls and .xlsx formats. It is the most -feature complete library available and has interfaces for C, C++, C# and -Delphi. It is only available for purchase, however. - -### QtXlsx - -Of the open source libraries, the QtXlsx library -(https://github.com/dbzhang800/QtXlsxWriter) is the most feature -complete. It is, however, based on the Qt framework. While I'm a big fan -of Qt for application programming purposes, I don't believe it is the -best option for lower-level libraries. - -### XLNT - -Recently, I found the XLNT library on GitHub -(https://github.com/tfussell/xlnt). It was not available when I began -developing OpenXLSX. To be honest, if it had, I wouldn't have begun -OpenXLSX. It has a larger feature set and probably has fewer bugs. -However, I decided to continue developing OpenXLSX, because I believe -that in a few areas it is better than XLNT. Primarily, OpenXLSX is -better able to handle very large spreadsheets (up to a million rows). - ## Ambition The ambition is that OpenXLSX should be able to read, write, create and @@ -87,8 +41,11 @@ dependencies as possible. Currently, OpenXLSX depends on the following - Zippy (C++ wrapper around miniz) - Boost.Nowide (for opening files with non-ASCII names on Windows) -these libraries are included in the repository, i.e. it's not necessary -to download and build separately. +These libraries are all header-only and included in the repository, i.e. it's not necessary to download and build +separately. + +Also, focus has been put on **speed**, not memory usage (although there are options for reducing the memory usage, +at the cost of speed; more on that later). ## Compatibility @@ -96,14 +53,12 @@ OpenXLSX has been tested on the following platforms/compilers. Note that a '-' doesn't mean that OpenXLSX doesn't work; it just means that it hasn't been tested: -| | GCC | Clang | MSVC | -|:--------|:----|:------|:-----| -| Windows | N/A | - | + | -| MinGW | + | + | N/A | -| MSYS | + | N/A | N/A | -| Cygwin | - | - | N/A | -| MacOS | + | + | N/A | -| Linux | + | + | N/A | +| | GCC | Clang | MSVC | +|:--------|:------|:------|:-----| +| Windows | MinGW | MinGW | + | +| Cygwin | - | - | N/A | +| MacOS | + | + | N/A | +| Linux | + | + | N/A | The following compiler versions should be able to compile OpenXLSX without errors: @@ -226,13 +181,6 @@ for Windows, where the configuration of the library must be the same as for the reason, on Windows, it is much easier to just include the OpenXLSX source folder as a subdirectory to your CMake project; it will save you a lot of headaches. -## Python Interface - -A Python interface has been developed for OpenXLSX. You can find -instructions in the Python folder. - -HOLD: Not updated recently. - ## Current Status OpenXLSX is still work i progress. The following is a list of features @@ -242,7 +190,8 @@ which have been implemented and should be working properly: - Read/write/modify cell contents - Copy cells and cell ranges - Copy worksheets -- Ranges and Iterators +- Cell ranges and iterators +- Row ranges and iterators Features related to formatting, plots and figures have not been implemented, and are not planned to be in the near future. @@ -254,7 +203,7 @@ not working! The table below is the output from a benchmark (using the Google Benchmark library), which shows that read/write access can be done at a -rate of around 2,000,000 cells per second. Floating point numbers are +rate of around 4,000,000 cells per second. Floating point numbers are somewhat lower, due to conversion to/from strings in the .xml file. ``` @@ -380,498 +329,19 @@ non-UTF-8. To stay sane, I recommend that source code files are always in UTF-8 files; all IDE's I know of can handle source code files in UTF-8 encoding. Welcome to the wonderful world of unicode on Windows 🤮 -## Reference Guide -This section will contain the user reference for usage of OpenXLSX. -HOLD - -### XLDocument class -HOLD - -### XLWorkbook class -HOLD - -### XLWorksheet class -HOLD - -### XLCellReference class -The most common way of addressing cells in an Excel spreadsheet is by using the A1 notation, i.e. the columns are -represented by letters and the rows are represented by numbers. However, it is also possible to use the so-called -R1C1 notation, where both rows and columns are represented by numbers. - -The XLCellReference class encapsulates the concept of a cell address, and can be used to convert between different -notations. It is also used as an input parameter on XLWorksheet objects to retrieve specific cells. - -The most common way of creating an XLCellReference object is to call the constructor with a string with the cell -address in A1 notation, like this: - -```cpp -auto cellRef = XLCellReference("B2"); -``` -It is also possible to create an XLCellReference object by providing the row and column coordinates of the cell, -like this: -```cpp -auto cellRef = XLCellReference(2,2); -``` - -If the default constructor is called (i.e. no input parameters), the resulting object will refer to cell A1. - -If you have an XLCellReference object, you can get the row/column number or the address using the `row()`, `column() -`, or `address()` member functions. Similarly, the object can be modified using the `setRow()`, `setColumn() -`, or `setAddress()` member functions: - -```cpp -uint16_t row = cellRef.row(); // Get the row number -uint32_t column = cellRef.column(); // Get the column number -std::string address = cellRef.address(); // Get the cell address - -cellRef.setRow(3); // Set the row number; -cellRef.setColumn(5); // Set the column number; -cellRef.setAddress("E3"); // Set the cell address; -``` - -### XLCell class -An object of the XLCell class represents a cell in a spreadsheet. The XLCell class itself doesn't do much, as it can -mostly be considered a container of various cell properties, such as the cell value, cell formulas (not yet -implemented), and cell formatting (not yet implemented). - -An XLCell object can be retrieved via the `cell()` member function of the XLWorksheet class. This method takes an -XLCellReference object, or alternatively a string with the cell address, as a parameter. - -### XLCellValue and XLCellValueProxy classes -As mentioned previously, an object of the XLCell class doesn't contain the actual cell value. Instead, the value is -contained in an XLCellValue object. XLCellValue is essentially a wrapper around a std::variant object, with some -handy functionality for conversion and assignment. - -An XLCellValue object has no knowledge about the cell it belongs to; it is simply a value that can passed around or -stored in a container. Hence, assigning a new value to an XLCellValue object does **not** change the value of any -cells in the spreadsheet. - -The XLCellValue class has a templated constructor that can take any integer value (including booleans), any floating -point value, and any string type with a `c_str()` method for getting a c-string. It is also possible to construct an -XLCellValue object from raw c-strings and from std::string_view objects, although it doesn't have a `c_str()` member -function. The copy assignment operator works in the same manner. - -For conversion in the other direction, the XLCellValue class provides a templated `get()` function, for converting -to a basic type. Similar to construction, the template parameter can be any integer type, and floating point type, -and any type that can be constructed from c-strings. For example: - -```c++ -auto val1 = cellValue.get(); -auto val2 = cellValue.get(); -auto val3 = cellValue.get(); -auto val4 = cellValue.get(); -``` - -Note, however, that if the value contained in the XLCellValue object cannot be converted to the template parameter -type (e.g. if the XLCellValue object contains a string, and the template parameter is int), then an XLValueTypeError -will be thrown. - -In addition to the `get()` function, the XLCellValue class has a templated explicit conversion operator, that can -perform explicit conversion, using the the same rules as above. For example: - -```cpp -auto val1 = static_cast(cellValue); -auto val2 = double(cellValue); -``` - -The XLCell class has a `value()` member function, and one would think that it returns the XLCellValue object for -that cell. And it does...sort of. The `value()` member function actually returns a reference to an XLCellValueProxy -object. This objects serves as a placeholder that facilitates conversion to an XLCellValue object, as well as -assignment of a value to a cell. Whereas assigning a new value to an XLCellValue object does not modify the -spreadsheet in any way, assigning a value to a XLCellValueProxy object, will. - -This is probably better illustrated by example: - -```cpp -XLCellValue val = cell.value(); -``` -While the `value()` member function returns a reference to a XLCellValueProxy object, this will be implicitly -converted to an XLCellValue object. In addition, the XLCellValueProxy class supports the same conversion options as -XLCellValue. - -But the XLCellValueProxy class also supports assignment operations, that will modify the cell value in the -underlying spreadsheet. Assignment can be done with XLCellValue objects, any integer type, booleans, any floating -point types, c-strings, std::string_view and any string type with a `c_str()` member function. For example: - -```cpp -cell.value() = 42; -cell.value() = "Hello, OpenXLSX!"; -cell.value() = 3.14159; -cell.value() = false; -cell.value() = XLCellValue(123); -``` - -The benefit of this approach is, that we can have XLCellValue objects that uses value semantics, i.e. contains no -pointers to the underlying spreadsheet, and that can be copied around, while at the same time can use the same `value -()` member function to assign a new value to the underlying XLCell object. - -This approach works seamlessly...almost. There is one drawback, and that is that it is not possible to use the auto -keyword: -```cpp -auto val = cell.value(); // Error! -``` -Using the auto keyword would invoke the copy constructor of the XLCellValueProxy object, which is undesired. -Therefore the copy constructor has been made private, and the code above will therefore not compile. Using auto& -instead would compile, but would not be of any use. - -### XLRow class -HOLD - -### XLRowData and XLRowDataProxy classes -HOLD - ## Example Programs -The following example programs illustrates the key features of OpenXLSX. -The source code is included in the 'examples' directory in the OpenXLSX -repository. - -### Basic Usage -This example program illustrates simple usage, such as assigning values to spreadsheet cells, and retrieving cell -values as XLCellValue objects. -```cpp -#include -#include - -using namespace std; -using namespace OpenXLSX; - -int main() -{ - cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #01: Basic Usage\n"; - cout << "********************************************************************************\n"; - - XLDocument doc; - doc.create("./Demo01.xlsx"); - auto wks = doc.workbook().worksheet("Sheet1"); - - // Here an address string is used in the .cell member function, but an XLCellReference object can - // also be used. For example, for the cell at 'A1', XLCellReference{1,1} can be usedas an argument. - wks.cell("A1").value().set(3.14159); - wks.cell("B1").value() = 42; - wks.cell("C1").value() = " Hello OpenXLSX! "; - wks.cell("D1").value() = true; - wks.cell("E1").value() = wks.cell(XLCellReference("C1")).value(); - - XLCellValue A1 = wks.cell("A1").value(); - XLCellValue B1 = wks.cell("B1").value(); - XLCellValue C1 = wks.cell("C1").value(); - XLCellValue D1 = wks.cell("D1").value(); - XLCellValue E1 = wks.cell("E1").value(); - - cout << "Cell A1: (" << A1.typeAsString() << ") " << A1.get() << endl; - cout << "Cell B1: (" << B1.typeAsString() << ") " << B1.get() << endl; - cout << "Cell C1: (" << C1.typeAsString() << ") " << C1.get() << endl; - cout << "Cell D1: (" << D1.typeAsString() << ") " << D1.get() << endl; - cout << "Cell E1: (" << E1.typeAsString() << ") " << E1.get() << endl << endl; - - doc.save(); - - return 0; -} -``` - -### Sheet Handling - -```cpp -#include -#include - -using namespace std; -using namespace OpenXLSX; - -int main() -{ - cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #02: Sheet Handling\n"; - cout << "********************************************************************************\n"; - - XLDocument doc; - doc.create("./Demo02.xlsx"); - auto wbk = doc.workbook(); - - cout << "\nSheets in workbook:\n"; - for (const auto& name : wbk.worksheetNames()) cout << wbk.indexOfSheet(name) << " : " << name << "\n"; - - cout << "\nAdding new sheet 'MySheet01'\n"; - wbk.addWorksheet("MySheet01"); - - cout << "Adding new sheet 'MySheet02'\n"; - wbk.addWorksheet("MySheet02"); - - cout << "Cloning sheet 'Sheet1' to new sheet 'MySheet03'\n"; - wbk.sheet("Sheet1").get().clone("MySheet03"); - - cout << "Cloning sheet 'MySheet01' to new sheet 'MySheet04'\n"; - wbk.cloneSheet("MySheet01", "MySheet04"); - - cout << "\nSheets in workbook:\n"; - for (const auto& name : wbk.worksheetNames()) cout << wbk.indexOfSheet(name) << " : " << name << "\n"; - - cout << "\nDeleting sheet 'Sheet1'\n"; - wbk.deleteSheet("Sheet1"); - - cout << "Moving sheet 'MySheet04' to index 1\n"; - wbk.worksheet("MySheet04").setIndex(1); - - cout << "Moving sheet 'MySheet03' to index 2\n"; - wbk.worksheet("MySheet03").setIndex(2); - - cout << "Moving sheet 'MySheet02' to index 3\n"; - wbk.worksheet("MySheet02").setIndex(3); - - cout << "Moving sheet 'MySheet01' to index 4\n"; - wbk.worksheet("MySheet01").setIndex(4); - - cout << "\nSheets in workbook:\n"; - for (const auto& name : wbk.worksheetNames()) cout << wbk.indexOfSheet(name) << " : " << name << "\n"; - - wbk.sheet("MySheet01").setColor(XLColor(0, 0, 0)); - wbk.sheet("MySheet02").setColor(XLColor(255, 0, 0)); - wbk.sheet("MySheet03").setColor(XLColor(0, 255, 0)); - wbk.sheet("MySheet04").setColor(XLColor(0, 0, 255)); - - doc.save(); - - return 0; -} -``` - -### Unicode - -```cpp -#include -#include - -using namespace std; -using namespace OpenXLSX; - -int main() -{ - cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #03: Unicode\n"; - cout << "********************************************************************************\n"; - - XLDocument doc1; - doc1.create("./Demo03.xlsx"); - auto wks1 = doc1.workbook().worksheet("Sheet1"); - - wks1.cell(XLCellReference("A1")).value() = "안녕하세요 세계!"; - wks1.cell(XLCellReference("A2")).value() = "你好,世界!"; - wks1.cell(XLCellReference("A3")).value() = "こんにちは世界"; - wks1.cell(XLCellReference("A4")).value() = "नमस्ते दुनिया!"; - wks1.cell(XLCellReference("A5")).value() = "Привет, мир!"; - wks1.cell(XLCellReference("A6")).value() = "Γειά σου Κόσμε!"; - - doc1.save(); - doc1.saveAs("./スプレッドシート.xlsx"); - doc1.close(); - - XLDocument doc2; - doc2.open("./Demo03.xlsx"); - auto wks2 = doc2.workbook().worksheet("Sheet1"); - - cout << "Cell A1 (Korean) : " << wks2.cell(XLCellReference("A1")).value().get() << endl; - cout << "Cell A2 (Chinese) : " << wks2.cell(XLCellReference("A2")).value().get() << endl; - cout << "Cell A3 (Japanese): " << wks2.cell(XLCellReference("A3")).value().get() << endl; - cout << "Cell A4 (Hindi) : " << wks2.cell(XLCellReference("A4")).value().get() << endl; - cout << "Cell A5 (Russian) : " << wks2.cell(XLCellReference("A5")).value().get() << endl; - cout << "Cell A6 (Greek) : " << wks2.cell(XLCellReference("A6")).value().get() << endl; - - - cout << "\nNOTE: If you are using a Windows terminal, the above output will look like gibberish,\n" - "because the Windows terminal does not support UTF-8 at the moment. To view to output,\n" - "open the Demo03.xlsx file in Excel.\n\n"; - - doc2.close(); - - return 0; -} -``` - -### Number Formats - -```cpp -#iclude -#include - -using namespace std; -using namespace OpenXLSX; - -int main() -{ - cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #04: Number Formats\n"; - cout << "********************************************************************************\n"; - - XLDocument doc1; - doc1.create("./Demo04.xlsx"); - auto wks1 = doc1.workbook().worksheet("Sheet1"); - - wks1.cell("A1").value() = 0.01; - wks1.cell("B1").value() = 0.02; - wks1.cell("C1").value() = 0.03; - wks1.cell("A2").value() = 0.001; - wks1.cell("B2").value() = 0.002; - wks1.cell("C2").value() = 0.003; - wks1.cell("A3").value() = 1e-4; - wks1.cell("B3").value() = 2e-4; - wks1.cell("C3").value() = 3e-4; - - wks1.cell("A4").value() = 1; - wks1.cell("B4").value() = 2; - wks1.cell("C4").value() = 3; - wks1.cell("A5").value() = 845287496; - wks1.cell("B5").value() = 175397487; - wks1.cell("C5").value() = 973853975; - wks1.cell("A6").value() = 2e10; - wks1.cell("B6").value() = 3e11; - wks1.cell("C6").value() = 4e12; - - doc1.save(); - doc1.close(); - - XLDocument doc2; - doc2.open("./Demo04.xlsx"); - auto wks2 = doc2.workbook().worksheet("Sheet1"); - - auto PrintCell = [](const XLCell& cell) { - cout << "Cell type is "; - - switch (cell.valueType()) { - case XLValueType::Empty:à - cout << "XLValueType::Empty"; - break; - - case XLValueType::Float: - cout << "XLValueType::Float and the value is " << cell.value().get() << endl; - break; - - case XLValueType::Integer: - cout << "XLValueType::Integer and the value is " << cell.value().get() << endl; - break; - - default: - cout << "Unknown"; - } - }; - - cout << "Cell A1: "; - PrintCell(wks2.cell("A1")); - - cout << "Cell B1: "; - PrintCell(wks2.cell("B1")); - - cout << "Cell C1: "; - PrintCell(wks2.cell("C1")); - - cout << "Cell A2: "; - PrintCell(wks2.cell("A2")); - - cout << "Cell B2: "; - PrintCell(wks2.cell("B2")); - - cout << "Cell C2: "; - PrintCell(wks2.cell("C2")); - - cout << "Cell A3: "; - PrintCell(wks2.cell("A3")); - - cout << "Cell B3: "; - PrintCell(wks2.cell("B3")); - - cout << "Cell C3: "; - PrintCell(wks2.cell("C3")); - - cout << "Cell A4: "; - PrintCell(wks2.cell("A4")); - - cout << "Cell B4: "; - PrintCell(wks2.cell("B4")); - - cout << "Cell C4: "; - PrintCell(wks2.cell("C4")); - - cout << "Cell A5: "; - PrintCell(wks2.cell("A5")); - - cout << "Cell B5: "; - PrintCell(wks2.cell("B5")); - - cout << "Cell C5: "; - PrintCell(wks2.cell("C5")); - - cout << "Cell A6: "; - PrintCell(wks2.cell("A6")); - - cout << "Cell B6: "; - PrintCell(wks2.cell("B6")); - - cout << "Cell C6: "; - PrintCell(wks2.cell("C6")); - - doc2.close(); - - return 0; -} -``` - -### Ranges and Iterators - -```cpp -#include -#include -#include -#include - -using namespace std; -using namespace OpenXLSX; - -int main() -{ - cout << "********************************************************************************\n"; - cout << "DEMO PROGRAM #05: Ranges and Iterators\n"; - cout << "********************************************************************************\n"; - - cout << "\nGenerating spreadsheet (1,048,576 rows x 8 columns) ..." << endl; - XLDocument doc; - doc.create("./Demo05.xlsx"); - auto wks = doc.workbook().worksheet("Sheet1"); - auto rng = wks.range(XLCellReference("A1"), XLCellReference(1048576, 8)); - - std::random_device rand_dev; - std::mt19937 generator(rand_dev()); - std::uniform_int_distribution distr(0, 99); - - for (auto& cell : rng) cell.value() = distr(generator); - - cout << "Saving spreadsheet (1,048,576 rows x 8 columns) ..." << endl; - doc.save(); - doc.close(); - - cout << "Re-opening spreadsheet (1,048,576 rows x 8 columns) ..." << endl; - doc.open("./Demo05.xlsx"); - wks = doc.workbook().worksheet("Sheet1"); - rng = wks.range(XLCellReference("A1"), XLCellReference(1048576, 8)); - - cout << "Reading data from spreadsheet (1,048,576 rows x 8 columns) ..." << endl; - cout << "Cell count: " << std::distance(rng.begin(), rng.end()) << endl; - cout << "Sum of cell values: " - << accumulate(rng.begin(), rng.end(), 0, [](uint64_t a, XLCell& b) { return a + b.value().get(); }); - - doc.close(); - - return 0; -} -``` +In the 'Examples' folder, you will find several example programs, that illustrates how to use OpenXLSX. Studying +those example programs is the best way to learn how to use OpenXLSX. The example programs are annotated, so it +should be relatively easy to understand what's going on. ## Changes -### New in version 0.3.0 -HOLD +### New in version 0.3.x +This version includes row ranges and iterators. It also support assignment of containers of cell values to XLRow +objects. This is significantly faster (up to x2) than using cell ranges or accessing cells by cell references. -### New in version 0.2.0 +### New in version 0.2.x The internal architecture of OpenXLSX has been significantly re-designed since the previous version. The reason is that the library was turning @@ -893,7 +363,7 @@ should be easy to update: an attempt to implement the pimpl idiom, but it wasn't very effective. In the future, I may try to implement pimpl again, but only if it can be done in a simpler way. -* All member functions have been renamed to begin wtih a small letter +* All member functions have been renamed to begin with a small letter (camelCase), i.e. the member function WorksheetCount() is renamed to worksheetCount(). This was done mostly for cosmetic reasons.