I have been working again on dynamic adjustments in column width. I have found that using Canvas.TextWidth(MyString), even when I have ensured that the Font parameters are correctly set, does not yield a very useful figure for Excel. Using your TExcelMetrics.ColMult and a fudge factor is not great, either, as I seem to need a factor of at least 1.3, which seems pretty sloppy. But perhaps that is simply the Excel issues, and can't be improved upon.
Bill,
Canvas.TextWidth(MyString);
const
s = 'A little test!';
procedure TForm12.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(Canvas.TextWidth(s)));
end;
Adrian,
Hi,
Ah, excellent... I will try that out, when I get a chance.... Still, unless it returns the value it likes, so I can analyze across a few row groups, and take the max, it still won't get me where I need to go.
There is another parameter: MinWidth which you can use to make sure that the width doesn't shrink.
/// <summary>
/// Autofits a range of columns so they adapt their width to show all the text inside.
/// </summary>
/// <param name="col1">First column to Autofit.</param>
/// <param name="col2">Last column to Autofit.</param>
/// <param name="minRow">First row that will be used to autofit the column. If you want for example to autofit a column
/// based only in the cells from row 3 to 10, you would use 3 as minRow.</param>
/// <param name="maxRow">Last row that will be used to autofit the column. If you want for example to autofit a column
/// based only in the cells from row 3 to 10, you would use 10 as maxRow.
/// <br /><b>Specify any value <=0 here to use all rows for the autofit.</b></param>
/// <param name="ignoreStrings">When true, strings will not be considered for the autofit. Only numbers will.</param>
/// <param name="adjustment">You will normally want to set this parameter to 1, which means that autofit will be made with standard measurements.
/// If you set it to for example 1.1, then columns will be adjusted to 110% percent of what their calculated width was.
/// Use this parameter to fine-tune autofiting, if for example columns are too small when opening the file in Excel.</param>
/// <param name="adjustmentFixed">You will normally set this parameter to 0, which means standard autofit. If you set it to a value, the column will be
/// made larger by that amount from the calculated autofit. Different from the "adjustment" parameter, this parameter adds a fixed size to the column
/// and not a percentage. The final size of the column will be: FinalSize = CalulatedAutoFit * adjustment + adjusmentFixed</param>
/// <param name="minWidth">Minimum final width for the column to autofit. If the calculated value is less than minWidth, column size will be set to minWidth.
/// <br/>A negative value on minWidth means the column size will be no smaller than the original width.</param>
/// <param name="maxWidth">Maximum final width for the column to autofit. If the calculated value is more than maxWidth, column size will be set to maxWidth.
/// <br/>maxWidth = 0 means no maxWidth.
/// <br/>A negative value on maxWidth means the column size will be no bigger than the original width.
/// </param>
/// <param name="autofitMerged">Specifies which column in a merged cell using more than one column will be used to autofit the merged cell.
/// If you don't specify this parameter, it will be the last column.</param>
procedure AutofitCol(const col1: Int32; const col2: Int32; const minRow: Int32; const maxRow: Int32; const ignoreStrings: Boolean; const adjustment: RealNumber; const adjustmentFixed: Int32; const minWidth: Int32; const maxWidth: Int32; const autofitMerged: TAutofitMerged); overload; virtual; abstract;
OK, I need to consider how this might work out in my code. I would have thought the AutoFitCol less efficient than a MeasureString method, but if is likely to be the other way around, then I will have to see whether I can make this approach serve. Thanks!
OK, about autofitMerged: I have a frequent need to merge two or more cells to make a category header float above column headers. And add the complication that depending on user-selected options, the category header may be above only one column, not two or more. From what you wrote in the documentation, it is not clear to me how to achieve what I want. If columns 11 and 12 are both present, and each is too narrow by itself to contain the category header, but the combined width is sufficient, then I do not want the category header to contribute to the autofit. However, if only either column 11 or 12 is present, then it will need to be wide enough to contain the category header.
Adrian, I have it working as need now, with AutoFitCol. Thanks!
About minwidth: Indeed you would first call it with minWidth = 0, then with a negative value. The first time it will autofit to the block, next times it will only increase the autofit if needed, but never decrease it.
xls := TXlsFile.Create(1, true);
xls.SetCellValue(1, 1, 'this is some long text to try autofit in a merged cell');
xls.MergeCells(1, 1, 1, 2);
xls.AutofitCol(1, 1, false, 1.1, 0, 0, 0, TAutofitMerged.OnLastCell);
xls.Save('r:\test.xlsx');
There are layers of confusion here, and when I got into it, I realized that it was probably not an issue, since I only merge cells if I have both 11 and 12. So in practice, for the way I am laying things out, it is not an issue.