6
votes

I'm trying to add conditional formatting in my excel sheet. Unfortunately examples on Spreadsheet::WriteExcel page are too simple and I don't know how to do it.

I wanted to change row backgroud color by RC10 cell value. In excel I will add formatting formula

=IF(RC10="xxxx";1;0)

I've tried to do something like that in Spreadsheet::WriteExcel:

my $detail_rest_fmt = $excel->add_format(font => "Calibri", size => 11, valign  => "vcenter", align => "right", border => 1);
$detail_rest_fmt->set_num_format("[Green]=IF(RC10=\"xxxx\";1;0);[Red]=IF(RC10=\"yyyyyy\";1;0)"); 

but withouts any effect.

4

4 Answers

4
votes

The bad news is I think it can hardly be done with Spreadsheet::WriteExcel.

The good news is it can easily be done with Excel::Writer::XLSX. Which happens to be a kind of descendant of Spreadsheet::WriteExcel. Please read the article: Spreadsheet::WriteExcel is dead. Long live Excel::Writer::XLSX

The following code does exactly the formatting you want (only based on cell A1 instead of RC10, this can be changed of course):

#!/usr/bin/perl -w
use strict;
use Excel::Writer::XLSX;

my @matrix = (
    ['xxxx', '<-- Change the value in cell A1 to change the colour of row 4'],
    [qw(Redyard Kipling)],
    [qw(If--)],
    [qw(If you can keep your head when all about you)],
    [qw(Are losing theirs and blaming it on you;)],
);

writeSpreadsheet('conditional.formatting.xlsx', \@matrix);

sub writeSpreadsheet {
    my ($outFile, $matrix) = @_;
    my $MIN_COL_WIDTH = 5;
    my $MAX_COL_WIDTH = 35;
    my $workbook = Excel::Writer::XLSX->new($outFile);
    my $worksheet = $workbook->add_worksheet();
    my $redFormat = $workbook->add_format(font => 'Arial', color => 'red');
    my $greenFormat = $workbook->add_format(font => 'Arial', color => 'green', bold => 1);
    $worksheet->set_row(0, undef,
        $workbook->add_format(font => 'Arial', align => 'center', bold => 1));
    $worksheet->conditional_formatting('A4:Z4',
        {
            type => 'formula',
            criteria => '=$A$1 = "xxxx"',
            format => $greenFormat
        }
    );
    $worksheet->conditional_formatting('A4:Z4',
        {
            type => 'formula',
            criteria => '=$A$1 = "yyyyyy"',
            format => $redFormat
        }
    );
    foreach my $row (0 .. $#$matrix) {
        foreach my $col (0 .. $#{$matrix->[$row]}) {
            $worksheet->write($row, $col, $matrix->[$row][$col] || '');
        }
    }
}
1
votes

Anton, is correct. Conditional formatting isn't really supported in Spreadsheet::WriteExcel.

However, the newer, API compatible replacement, Excel::Writer::XLSX offers a rich set of conditional formatting features.

See the updated Conditional Formatting docs in Excel::Writer::XLSX and this example.

1
votes

Behavior of conditional_formatting is very strange. I got something like that:

my $yyy = $excel->add_format(font => "Calibri", size => 11, valign  => "vcenter", align => "right", border => 1, border_color => "black", bg_color => $green);

for my $section (@sections) {
   for my $sector (@sectors) {
       my $xxxx = $excel->add_format(font => "Calibri", size => 11, valign  => "vcenter", align => "right", border => 1, border_color => "black", bg_color => $green);
            $sheet->conditional_formatting("A1", 
            {
                type => "formula",
                criteria => '=J4="T1"',
                format => $yyy
            });
   }
}

When I use $yyy it dosen't work (in excel there is set pattern fill instead of backgroud color) When I use $xxxx it works fine. $yyy and $xxxx are the same, so why it doesn't work?

1
votes

For your second question:

You may be encountering an issue where the formats are getting garbage collected before you get to use them due to scope issues.

If it is a scope problem try add a $workbook->close() to the end of your program to see if it fixes it.

Otherwise we would need a more complete example program to debug it.