2015-04-18 14:06:14 +01:00
|
|
|
/*
|
|
|
|
* Example of adding an autofilter to a worksheet in Excel using
|
|
|
|
* libxlsxwriter.
|
|
|
|
*
|
2025-02-11 00:03:36 +00:00
|
|
|
* Copyright 2014-2025, John McNamara, jmcnamara@cpan.org
|
2015-04-18 14:06:14 +01:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "xlsxwriter.h"
|
|
|
|
|
|
|
|
|
2021-08-08 20:25:35 +01:00
|
|
|
void write_worksheet_header(lxw_worksheet *worksheet, lxw_format *header);
|
2015-04-18 14:06:14 +01:00
|
|
|
|
|
|
|
|
2021-08-08 20:25:35 +01:00
|
|
|
int main() {
|
|
|
|
|
|
|
|
lxw_workbook *workbook = workbook_new("autofilter.xlsx");
|
|
|
|
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
|
|
|
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
|
|
|
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
|
|
|
|
lxw_worksheet *worksheet4 = workbook_add_worksheet(workbook, NULL);
|
|
|
|
lxw_worksheet *worksheet5 = workbook_add_worksheet(workbook, NULL);
|
|
|
|
lxw_worksheet *worksheet6 = workbook_add_worksheet(workbook, NULL);
|
|
|
|
lxw_worksheet *worksheet7 = workbook_add_worksheet(workbook, NULL);
|
2015-04-18 14:06:14 +01:00
|
|
|
|
|
|
|
struct row {
|
|
|
|
char region[16];
|
|
|
|
char item[16];
|
|
|
|
int volume;
|
|
|
|
char month[16];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct row data[] = {
|
|
|
|
{"East", "Apple", 9000, "July" },
|
|
|
|
{"East", "Apple", 5000, "July" },
|
|
|
|
{"South", "Orange", 9000, "September" },
|
|
|
|
{"North", "Apple", 2000, "November" },
|
|
|
|
{"West", "Apple", 9000, "November" },
|
|
|
|
{"South", "Pear", 7000, "October" },
|
|
|
|
{"North", "Pear", 9000, "August" },
|
|
|
|
{"West", "Orange", 1000, "December" },
|
|
|
|
{"West", "Grape", 1000, "November" },
|
|
|
|
{"South", "Pear", 10000, "April" },
|
|
|
|
{"West", "Grape", 6000, "January" },
|
|
|
|
{"South", "Orange", 3000, "May" },
|
|
|
|
{"North", "Apple", 3000, "December" },
|
|
|
|
{"South", "Apple", 7000, "February" },
|
|
|
|
{"West", "Grape", 1000, "December" },
|
|
|
|
{"East", "Grape", 8000, "February" },
|
|
|
|
{"South", "Grape", 10000, "June" },
|
|
|
|
{"West", "Pear", 7000, "December" },
|
|
|
|
{"South", "Apple", 2000, "October" },
|
|
|
|
{"East", "Grape", 7000, "December" },
|
|
|
|
{"North", "Grape", 6000, "April" },
|
|
|
|
{"East", "Pear", 8000, "February" },
|
|
|
|
{"North", "Apple", 7000, "August" },
|
|
|
|
{"North", "Orange", 7000, "July" },
|
|
|
|
{"North", "Apple", 6000, "June" },
|
|
|
|
{"South", "Grape", 8000, "September" },
|
|
|
|
{"West", "Apple", 3000, "October" },
|
|
|
|
{"South", "Orange", 10000, "November" },
|
|
|
|
{"West", "Grape", 4000, "July" },
|
|
|
|
{"North", "Orange", 5000, "August" },
|
|
|
|
{"East", "Orange", 1000, "November" },
|
|
|
|
{"East", "Orange", 4000, "October" },
|
|
|
|
{"North", "Grape", 5000, "August" },
|
|
|
|
{"East", "Apple", 1000, "December" },
|
|
|
|
{"South", "Apple", 10000, "March" },
|
|
|
|
{"East", "Grape", 7000, "October" },
|
|
|
|
{"West", "Grape", 1000, "September" },
|
|
|
|
{"East", "Grape", 10000, "October" },
|
|
|
|
{"South", "Orange", 8000, "March" },
|
|
|
|
{"North", "Apple", 4000, "July" },
|
|
|
|
{"South", "Orange", 5000, "July" },
|
|
|
|
{"West", "Apple", 4000, "June" },
|
|
|
|
{"East", "Apple", 5000, "April" },
|
|
|
|
{"North", "Pear", 3000, "August" },
|
|
|
|
{"East", "Grape", 9000, "November" },
|
|
|
|
{"North", "Orange", 8000, "October" },
|
|
|
|
{"East", "Apple", 10000, "June" },
|
|
|
|
{"South", "Pear", 1000, "December" },
|
|
|
|
{"North", "Grape", 10000, "July" },
|
|
|
|
{"East", "Grape", 6000, "February" }
|
|
|
|
};
|
|
|
|
|
2021-08-08 20:25:35 +01:00
|
|
|
uint16_t i;
|
|
|
|
lxw_row_col_options hidden = {.hidden = LXW_TRUE};
|
2015-04-18 14:06:14 +01:00
|
|
|
|
2021-08-08 20:25:35 +01:00
|
|
|
lxw_format *header = workbook_add_format(workbook);
|
|
|
|
format_set_bold(header);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 1. Autofilter without conditions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet1, header);
|
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
|
|
|
worksheet_write_string(worksheet1, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet1, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet1, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet1, i + 1, 3, data[i].month, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
|
|
|
worksheet_autofilter(worksheet1, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 2. Autofilter with a filter condition in the first column.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet2, header);
|
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
|
|
|
worksheet_write_string(worksheet2, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet2, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet2, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet2, i + 1, 3, data[i].month, NULL);
|
|
|
|
|
|
|
|
/* It isn't sufficient to just apply the filter condition below. We
|
|
|
|
* must also hide the rows that don't match the criteria since Excel
|
|
|
|
* doesn't do that automatically. */
|
|
|
|
if (strcmp(data[i].region, "East") == 0) {
|
|
|
|
/* Row matches the filter, no further action required. */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Hide rows that don't match the filter. */
|
|
|
|
worksheet_set_row_opt(worksheet2, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note, the if() statement above is written to match the logic of the
|
|
|
|
* criteria in worksheet_filter_column() below. However you could get
|
|
|
|
* the same results with the following simpler, but reversed, code:
|
|
|
|
*
|
|
|
|
* if (strcmp(data[i].region, "East") != 0) {
|
|
|
|
* worksheet_set_row_opt(worksheet2, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* The same applies to the Examples 3-6 as well.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
|
|
|
worksheet_autofilter(worksheet2, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
/* Add the filter criteria. */
|
|
|
|
lxw_filter_rule filter_rule2 = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
|
|
|
|
.value_string = "East"};
|
|
|
|
|
|
|
|
worksheet_filter_column(worksheet2, 0, &filter_rule2);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 3. Autofilter with a dual filter condition in one of the columns.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet3, header);
|
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
|
|
|
worksheet_write_string(worksheet3, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet3, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet3, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet3, i + 1, 3, data[i].month, NULL);
|
|
|
|
|
|
|
|
if (strcmp(data[i].region, "East") == 0 || strcmp(data[i].region, "South") == 0) {
|
|
|
|
/* Row matches the filter, no further action required. */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* We need to hide rows that don't match the filter. */
|
|
|
|
worksheet_set_row_opt(worksheet3, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
|
|
|
worksheet_autofilter(worksheet3, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
/* Add the filter criteria. */
|
|
|
|
lxw_filter_rule filter_rule3a = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
|
|
|
|
.value_string = "East"};
|
|
|
|
|
|
|
|
lxw_filter_rule filter_rule3b = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
|
|
|
|
.value_string = "South"};
|
|
|
|
|
|
|
|
worksheet_filter_column2(worksheet3, 0, &filter_rule3a, &filter_rule3b, LXW_FILTER_OR);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 4. Autofilter with filter conditions in two columns.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet4, header);
|
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
|
|
|
worksheet_write_string(worksheet4, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet4, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet4, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet4, i + 1, 3, data[i].month, NULL);
|
|
|
|
|
|
|
|
if (strcmp(data[i].region, "East") == 0 &&
|
|
|
|
data[i].volume > 3000 && data[i].volume < 8000)
|
|
|
|
{
|
|
|
|
/* Row matches the filter, no further action required. */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* We need to hide rows that don't match the filter. */
|
|
|
|
worksheet_set_row_opt(worksheet4, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
|
|
|
worksheet_autofilter(worksheet4, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
/* Add the filter criteria. */
|
|
|
|
lxw_filter_rule filter_rule4a = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
|
|
|
|
.value_string = "East"};
|
|
|
|
|
|
|
|
lxw_filter_rule filter_rule4b = {.criteria = LXW_FILTER_CRITERIA_GREATER_THAN,
|
|
|
|
.value = 3000};
|
2015-04-18 14:06:14 +01:00
|
|
|
|
2021-08-08 20:25:35 +01:00
|
|
|
lxw_filter_rule filter_rule4c = {.criteria = LXW_FILTER_CRITERIA_LESS_THAN,
|
|
|
|
.value = 8000};
|
|
|
|
|
|
|
|
worksheet_filter_column(worksheet4, 0, &filter_rule4a);
|
|
|
|
worksheet_filter_column2(worksheet4, 2, &filter_rule4b, &filter_rule4c, LXW_FILTER_AND);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 5. Autofilter with a dual filter condition in one of the columns.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet5, header);
|
2015-04-18 14:06:14 +01:00
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
2021-08-08 20:25:35 +01:00
|
|
|
worksheet_write_string(worksheet5, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet5, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet5, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet5, i + 1, 3, data[i].month, NULL);
|
|
|
|
|
|
|
|
if (strcmp(data[i].region, "East") == 0 ||
|
|
|
|
strcmp(data[i].region, "North") == 0 ||
|
|
|
|
strcmp(data[i].region, "South") == 0)
|
|
|
|
{
|
|
|
|
/* Row matches the filter, no further action required. */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* We need to hide rows that don't match the filter. */
|
|
|
|
worksheet_set_row_opt(worksheet5, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
}
|
2015-04-18 14:06:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
2021-08-08 20:25:35 +01:00
|
|
|
worksheet_autofilter(worksheet5, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
/* Add the filter criteria. */
|
2023-09-24 20:40:07 +01:00
|
|
|
const char* list[] = {"East", "North", "South", NULL};
|
2021-08-08 20:25:35 +01:00
|
|
|
|
|
|
|
worksheet_filter_list(worksheet5, 0, list);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 6. Autofilter with filter for blanks.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet6, header);
|
|
|
|
|
|
|
|
/* Simulate one blank cell in the data, to test the filter. */
|
|
|
|
data[5].region[0] = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
|
|
|
worksheet_write_string(worksheet6, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet6, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet6, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet6, i + 1, 3, data[i].month, NULL);
|
|
|
|
|
|
|
|
if (strcmp(data[i].region, "") == 0) {
|
|
|
|
/* Row matches the filter, no further action required. */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* We need to hide rows that don't match the filter. */
|
|
|
|
worksheet_set_row_opt(worksheet6, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
|
|
|
worksheet_autofilter(worksheet6, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
/* Add the filter criteria. */
|
|
|
|
lxw_filter_rule filter_rule6 = {.criteria = LXW_FILTER_CRITERIA_BLANKS};
|
|
|
|
|
|
|
|
worksheet_filter_column(worksheet6, 0, &filter_rule6);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Example 7. Autofilter with filter for non-blanks.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Set up the worksheet data. */
|
|
|
|
write_worksheet_header(worksheet7, header);
|
|
|
|
|
|
|
|
/* Write the row data. */
|
|
|
|
for (i = 0; i < sizeof(data)/sizeof(struct row); i++) {
|
|
|
|
worksheet_write_string(worksheet7, i + 1, 0, data[i].region, NULL);
|
|
|
|
worksheet_write_string(worksheet7, i + 1, 1, data[i].item, NULL);
|
|
|
|
worksheet_write_number(worksheet7, i + 1, 2, data[i].volume, NULL);
|
|
|
|
worksheet_write_string(worksheet7, i + 1, 3, data[i].month, NULL);
|
|
|
|
|
|
|
|
if (strcmp(data[i].region, "") != 0) {
|
|
|
|
/* Row matches the filter, no further action required. */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* We need to hide rows that don't match the filter. */
|
|
|
|
worksheet_set_row_opt(worksheet7, i + 1, LXW_DEF_ROW_HEIGHT, NULL, &hidden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the autofilter. */
|
|
|
|
worksheet_autofilter(worksheet7, 0, 0, 50, 3);
|
|
|
|
|
|
|
|
/* Add the filter criteria. */
|
|
|
|
lxw_filter_rule filter_rule7 = {.criteria = LXW_FILTER_CRITERIA_NON_BLANKS};
|
|
|
|
|
|
|
|
worksheet_filter_column(worksheet7, 0, &filter_rule7);
|
|
|
|
|
|
|
|
|
2015-04-18 14:06:14 +01:00
|
|
|
|
|
|
|
return workbook_close(workbook);
|
|
|
|
}
|
2021-08-08 20:25:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
void write_worksheet_header(lxw_worksheet *worksheet, lxw_format *header) {
|
|
|
|
|
|
|
|
/* Make the columns wider for clarity. */
|
|
|
|
worksheet_set_column(worksheet, 0, 3, 12, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
/* Write the column headers. */
|
|
|
|
worksheet_set_row(worksheet, 0, 20, header);
|
|
|
|
worksheet_write_string(worksheet, 0, 0, "Region", NULL);
|
|
|
|
worksheet_write_string(worksheet, 0, 1, "Item", NULL);
|
|
|
|
worksheet_write_string(worksheet, 0, 2, "Volume", NULL);
|
|
|
|
worksheet_write_string(worksheet, 0, 3, "Month", NULL);
|
|
|
|
|
|
|
|
}
|