I searched around for this for awhile, so forgive me if there is an answer already. I am having trouble applying borders to merged cells using CFSpreadsheet. Below is some example code.
<cfscript>
newSS = SpreadsheetNew('Testing'); //Create Spreadsheet
SpreadsheetMergeCells(newSS,1,1,1,9);
SpreadsheetAddRow(newSS,'Underline this Header');
SpreadSheetFormatCell(newSS,{bold=true,alignment='center',bottomborder='thin'},1,1);
Spreadsheetwrite(newSS,expandpath('myTest.xls'),true); //Write File
</cfscript>
What I would expect is the top cell to be underlined all the way across. What I get is the top cell only underlined through column "A" and not underlined after. Is there anyway around this or is this just a limitation of CFSpreadsheet??
Thanks!
According to the POI FAQ's, ie underlying library CF uses to generate spreadsheets, this is currently not supported (emphasis mine):
12. How do I add a border around a merged cell?
Add blank cells around where the cells normally would have been and
set the borders individually for each cell. We will probably enhance
HSSF in the future to make this process easier.
Probably the best you can do for now is to use SpreadsheetFormatCellRange instead of SpreadSheetFormatCell:
SpreadsheetFormatCellRange ( newSS
, {bold=true,alignment='center',bottomborder='thin'}
, 1,1,1,9 );
Related
I'm running into an issue when trying to compare data across two sheets to find discrepancies - specifically when it comes to comparing start and end times.
Right now, the "IF" statement in my screenshot is executing perfectly, except when a time is involved - it's reading those cells as decimals instead (but only sometimes).
I've tried formatting these cells (on the raw data AND on this "Discrepancies" report sheet) so that they are displayed as a "HH:MM am/pm" time, but the sheet is still comparing the decimal values.
Is there anything that I can add to this function to account for a compared value being a time instead of text, and having that text be compared for any discrepancies? I cannot add or change anything to the raw data sheets, the only thing I can edit is the formula seen in the screenshot I provided.
See the highlighted cells in my screenshot - this is the issue I keep running into. As you can see, there are SOME cells (the non-highlighted ones) that are executing as intended, but I'm unsure why this isn't the case for the whole spreadsheet when I've formatted everything the same way using the exact same formula across the whole sheet.
For example, the values in cell N2 is "8:00 AM" on both sheets, so the formula should just display "8:00 AM" in that cell (and NOT be highlighted) since there is no discrepancy in the cells between both sheets it's comparing. But instead, it's showing both times as a decimal with the slightest difference between them and is suggesting a difference where there technically isn't (or shouldn't be) one.
Please help!
Screenshot of original spreadsheet for reference
---EDIT (added the below):
Here is a view-only version of a SAMPLE SHEET that displays the issue I'm having:
https://docs.google.com/spreadsheets/d/1BdSQGsCajB3kOnYxzM3sl-0o3iTvR3ABdHpnzYRXjpA/edit?usp=sharing
On the sample sheet, the only cells that are performing as intended are C2, E2, G2, I2, K2, K6, or any cells that contain text like "Closed". Any of the other cells that have a time in both raw data tabs appears to be pulling the serial numbers for those times instead of correctly formatting it into "HH:mm AM/PM".
A quick tour of how the SAMPLE SHEET is set up:
User enters raw data into the "MicrositeRawData" and "SalesforceRawData" tabs.
Data is pulled from the "SalesforceRawData" tab into the "CleanedUpSalesforceData" tab using a QUERY that matches the UNIQUE ID's from the "MicrositeRawData" sheet, so that it essentially creates a tab that's in the same order and accounts for any extraneous data between the tabs (keep in mind this is a sample sheet and that the original sheet I'm using includes a lot more data which causes a mismatch of rows between the sheets which makes the QUERY necessary).
The "DISCREPANCIES" tab then compares the data between the "MicrositeRawData" and "CleanedUpSalesforceData" tabs. If the data is the same, it simply copies the data from the "MicrositeRawData" cell. But if the data is NOT the same, it lists the values from both sheets and is conditionally formatted to highlight those cells in yellow.
If there is data on the "MicrositeRawData" tab that is NOT included on the "SalesforceRawData" tab, the "DISCREPANCIES" tab will notate that and highlight the "A" cell in pink instead of yellow (as demonstrated in "A5").
try in B2:
=IF(MicrositeRawData!B2=CleanedUpSalesforceData!B2, MicrositeRawData!B2,
"MICROSITE: "&TEXT(MicrositeRawData!B2, "h:mm AM/PM")&CHAR(10)&
"SALESFORCE: "&TEXT(CleanedUpSalesforceData!B2, "h:mm AM/PM"))
update
delete all formulae from range B2:O10 and use this in B2:
=ARRAYFORMULA(IF(TO_TEXT(MicrositeRawData!B2:O10)=
TO_TEXT(CleanedUpSalesforceData!B2:O10), MicrositeRawData!B2:O10,
"MICROSITE: "&TEXT(IF(MicrositeRawData!B2:O10="",
"", MicrositeRawData!B2:O10), "h:mm AM/PM")&CHAR(10)&
"SALESFORCE: "&TEXT(IF(CleanedUpSalesforceData!B2:O10="",
"", CleanedUpSalesforceData!B2:O10), "h:mm AM/PM")))
I have a table where I need to get the values of the ticked headers as shown. The ALL takes precedence and it will include all headers when ticked.
Here is the working copy of the sheet.,
The expected values are shown in the image below.
The purple cells will have formula, H2, H3 and so for for each row.
I have tried with
=TRANSPOSE(FILTER(Config!A$1:A$16,(INDEX(Config!A$1:G$16,,MATCH(2,Config!$A$1:$1,0) ))=TRUE))
delete H:K range and use in H2:
=INDEX(TRIM(SPLIT(FLATTEN(QUERY(TRANSPOSE(IF(B2:B=TRUE, C1:F1&"♦",
IF(C2:F=TRUE, C1:F1&"♦", ))),,9^9)), "♦")))
Code Guy, see if this formula (need to drag down) does what you want:
=IF(B2,{C$1:F$1},IFERROR(FILTER(C$1:F$1,C2:F2),""))
"Brute-forcing" the solution with IFs kinda works, even though it's inelegant and not scalable to larger number of columns. Might be interesting to re-ask the question with an arbitrary number of columns. Pure formula solution might not be possible.
I've seen this post, but there does look to be a resolution. Anyway, I'm using ColdFusion 10 to generate an Excel spreadsheet. However, when I use SpreadsheetFormatRow() and pass in the rows to be formatted, it only does about 3 and then abruptly stops. Here is an example...
ColdFusion Code
<cfscript>
rowCount = 1;
headingRows = 4;
// Create instance of new Spreadsheet
excelSheet = SpreadsheetNew("ReportName",false);
// HEADING (IMAGE) ROW FORMAT
formatHeadingRow = StructNew();
formatHeadingRow.fgcolor="blue";
// Add rows to fill the header area (must add as many as we are spanning with the above image)
for (x=0;x<headingRows;x++) {
SpreadsheetAddRow(excelSheet,"TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST,TEST");
SpreadsheetFormatRow(excelSheet,formatHeadingRow,rowCount);
rowCount++;
}
</cfscript>
<!--- stream it to the browser --->
<cfheader name="Content-Disposition" value="inline; filename=reportName.xls">
<cfcontent type="application/vnd.ms-excel" variable="#SpreadSheetReadBinary(excelSheet)#">
and here is a screenshot of the resulting Excel sheet
Why is the formatting stopping after X number of rows and cells?
If I switch to using XML format with
excelSheet = SpreadsheetNew("ReportName",true);
it works properly. However I'm using a custom palette for my colors so I don't think switching to XLSX format is going to work for me. When I try and then call
palette = excelSheet.getWorkbook().getCustomPalette();
I get an error stating that getCustomPalette() method is undefined.
coldfusion.runtime.java.MethodSelectionException: The getcustompalette method was not found
Can anyone help me figure this out? Thank you!!!
Or even better since it works with the XML format, can anyone show example of how to use a custom palette with the XLSX (xml format)
This is an issue I have seen often when dealing with xls files from CF; they seem to stop applying styles after a certain number of cells. I've been able to work around it by outputting to xlsx instead. (I was able to replicate and "fix" your issue by doing so.)
excelSheet = SpreadsheetNew("ReportName",true);
...
<cfheader name="Content-Disposition" value="inline; filename=reportName.xlsx">
<cfcontent type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
variable="#SpreadSheetReadBinary(excelSheet)#">
Since you are applying the exact same format to all rows, only do it once, not on each row. Using SpreadsheetFormatCellRange after the loop should resolve the issue:
SpreadsheetFormatCellRange(excelSheet
, formatHeadingRow
, startRow
, startCol
, endRow
, endCol );
I suspect the problem somehow relates back to Excel's maximum style limits. Since CF is a black box, it is difficult to know how many styles it actually creates or exactly how they are applied. However, in my experience it is very easy to exceed the style limits without even knowing it. Especially when using the older .xls file format, whose limits are much lower. That is why I suggested using the newer .xlsx format instead.
getCustomPalette() method is undefined.
Correct. It does not exist in XSSF. Is there some reason you need a custom palette instead of just defining your own colors, as mentioned in your other thread?
In continuation of a previous thread, I've reached pretty close to where I want and have learned a lot. I'm under CF10 on a MSSQL Server 2008 environment. I have a report I'm generating using cfspreadsheet and then spitting out values based on whether a user has an app enabled it will be output as "Yes" and if not output as "No" in the excel spreadsheet.
Problem is, I need to make it a little easier on the eye and so I wanted to see if it was possible to apply conditional formatting to where if the 3 columns with 3 different apps is Y then it will be green and if N it will be red.
Any suggestions or examples would be great, thanks!
Like I mentioned in your other thread, if you return bit values (not strings), it is simple to apply a custom cell format. But you must use the spreadsheet functions, rather than cfspreadsheet (which does not support custom formatting).
Here is an expanded example to demonstrate how you could incorporate conditional color formatting:
<cfscript>
// build sample query
// note: values must be numeric and NOT text/varchar
qData = queryNew("");
queryAddColumn(qData, "AppNameAlpha", "bit", listToArray("0,0,1,0,1"));
queryAddColumn(qData, "AppNameBeta", "bit", listToArray("1,1,0,0,1"));
// create sample sheet
sheet = spreadsheetNew();
spreadsheetAddRows(sheet, qData);
// apply colorized yes/no format
spreadsheetFormatColumns(sheet, {dataformat='[Green]"Y";;[Red]"N"'}, "1-2");
spreadsheetWrite(sheet, "c:/path/to/sheet.xls", true);
</cfscript>
The "dataformat" uses the first three sections of Excel's custom number formatting: <positive><negative><zero>. Translated:
[Green]"Y"; // <positive values>: display "Y" in green
; // <negative values>: do nothing extra
[Red]"N" // <zero values>: display "N" in red
The function you are looking for is SpreadsheetFormatCell()
I've been trying to retrieve the locations of all the page breaks on a given Excel 2003 worksheet over COM. Here's an example of the kind of thing I'm trying to do:
Excel::HPageBreaksPtr pHPageBreaks = pSheet->GetHPageBreaks();
long count = pHPageBreaks->Count;
for (long i=0; i < count; ++i)
{
Excel::HPageBreakPtr pHPageBreak = pHPageBreaks->GetItem(i+1);
Excel::RangePtr pLocation = pHPageBreak->GetLocation();
printf("Page break at row %d\n", pLocation->Row);
pLocation.Release();
pHPageBreak.Release();
}
pHPageBreaks.Release();
I expect this to print out the row numbers of each of the horizontal page breaks in pSheet. The problem I'm having is that although count correctly indicates the number of page breaks in the worksheet, I can only ever seem to retrieve the first one. On the second run through the loop, calling pHPageBreaks->GetItem(i) throws an exception, with error number 0x8002000b, "invalid index".
Attempting to use pHPageBreaks->Get_NewEnum() to get an enumerator to iterate over the collection also fails with the same error, immediately on the call to Get_NewEnum().
I've looked around for a solution, and the closest thing I've found so far is http://support.microsoft.com/kb/210663/en-us. I have tried activating various cells beyond the page breaks, including the cells just beyond the range to be printed, as well as the lower-right cell (IV65536), but it didn't help.
If somebody can tell me how to get Excel to return the locations of all of the page breaks in a sheet, that would be awesome!
Thank you.
#Joel: Yes, I have tried displaying the user interface, and then setting ScreenUpdating to true - it produced the same results. Also, I have since tried combinations of setting pSheet->PrintArea to the entire worksheet and/or calling pSheet->ResetAllPageBreaks() before my call to get the HPageBreaks collection, which didn't help either.
#Joel: I've used pSheet->UsedRange to determine the row to scroll past, and Excel does scroll past all the horizontal breaks, but I'm still having the same issue when I try to access the second one. Unfortunately, switching to Excel 2007 did not help either.
Experimenting with Excel 2007 from Visual Basic, I discovered that the page break isn't known unless it has been displayed on the screen at least once.
The best workaround I could find was to page down, from the top of the sheet to the last row containing data. Then you can enumerate all the page breaks.
Here's the VBA code... let me know if you have any problem converting this to COM:
Range("A1").Select
numRows = Range("A1").End(xlDown).Row
While ActiveWindow.ScrollRow < numRows
ActiveWindow.LargeScroll Down:=1
Wend
For Each x In ActiveSheet.HPageBreaks
Debug.Print x.Location.Row
Next
This code made one simplifying assumption:
I used the .End(xlDown) method to figure out how far the data goes... this assumes that you have continuous data from A1 down to the bottom of the sheet. If you don't, you need to use some other method to figure out how far to keep scrolling.
Did you set ScreenUpdating to True, as mentioned in the KB article?
You may want to actually toggle it to True to force a screen repaint. It sounds like the calculation of page breaks is a side-effect of actually rendering the page, rather than something Excel does on demand, so you have to trigger a page rendering on the screen.