private void CheckColumnWidth(int expectedWidth, int column, bool useMergedCells) { int bestFitWidth = tracker.GetBestFitColumnWidth(column, useMergedCells); if (bestFitWidth < 0 && expectedWidth < 0) { return; } double abs_error = Math.Abs(bestFitWidth - expectedWidth); double rel_error = abs_error / expectedWidth; if (rel_error > 0.25) { Assert.Fail("check column width: " + rel_error + ", " + abs_error + ", " + expectedWidth + ", " + bestFitWidth); } }
/** * Adjusts the column width to fit the contents. * <p> * This process can be relatively slow on large sheets, so this should * normally only be called once per column, at the end of your * processing. * </p> * You can specify whether the content of merged cells should be considered or ignored. * Default is to ignore merged cells. * * <p> * Special note about SXSSF implementation: You must register the columns you wish to track with * the SXSSFSheet using {@link #trackColumnForAutoSizing(int)} or {@link #trackAllColumnsForAutoSizing()}. * This is needed because the rows needed to compute the column width may have fallen outside the * random access window and been flushed to disk. * Tracking columns is required even if all rows are in the random access window. * </p> * <p><i>New in POI 3.14 beta 1: auto-sizes columns using cells from current and flushed rows.</i></p> * * @param column the column index to auto-size * @param useMergedCells whether to use the contents of merged cells when calculating the width of the column */ public void AutoSizeColumn(int column, bool useMergedCells) { // Multiple calls to autoSizeColumn need to look up the best-fit width // of rows already flushed to disk plus re-calculate the best-fit width // of rows in the current window. It isn't safe to update the column // widths before flushing to disk because columns in the random access // window rows may change in best-fit width. The best-fit width of a cell // is only fixed when it becomes inaccessible for modification. // Changes to the shared strings table, styles table, or formulas might // be able to invalidate the auto-size width without the opportunity // to recalculate the best-fit width for the flushed rows. This is an // inherent limitation of SXSSF. If having correct auto-sizing is // critical, the flushed rows would need to be re-read by the read-only // XSSF eventmodel (SAX) or the memory-heavy XSSF usermodel (DOM). int flushedWidth; try { // get the best fit width of rows already flushed to disk flushedWidth = _autoSizeColumnTracker.GetBestFitColumnWidth(column, useMergedCells); } catch (Exception e) { throw new InvalidOperationException("Could not auto-size column. Make sure the column was tracked prior to auto-sizing the column.", e); } // get the best-fit width of rows currently in the random access window int activeWidth = (int)(256 * SheetUtil.GetColumnWidth(this, column, useMergedCells)); // the best-fit width for both flushed rows and random access window rows // flushedWidth or activeWidth may be negative if column contains only blank cells int bestFitWidth = Math.Max(flushedWidth, activeWidth); if (bestFitWidth > 0) { int maxColumnWidth = 255 * 256; // The maximum column width for an individual cell is 255 characters int width = Math.Min(bestFitWidth, maxColumnWidth); SetColumnWidth(column, width); } }