Zoom couple of columns to fit page with VBA - excel

I'm having trouble fitting my columns in Excel on a sheet.
I have a sheet with columns from A to CK (can be different per project).
I don't need to print column A, but column B has to be on all pages and next to column B has to be 3 columns. So that will make column "B,C:E" on first page, next page "B,F:H", and so on... Column B is set as title, so it will be printed on every page.
My problem is to set the scale. What I'm doing:
Take pagesize and translate to points, take off margin left and margin right = my printable area
Get the width of range("B:E") = my range to fit the page
Divide my printable area by my range to fit, multiply that with 100%, and extract 1% to make sure it will fit
The outcome in my situation is 83, but is has to be 77 to fit the page. I'll have to find other numbers I think, but I don't know how and which...
My code:
If ActiveSheet.Name = "Meterkastlijst" Then
Dim lngZoom As Long
Dim lngKolB As Long
Dim lngPagB As Long
lngKolB = ActiveSheet.Range("B:E").Width
If ActiveSheet.PageSetup.PaperSize = xlPaperA4 Then
lngPagB = CLng(Application.CentimetersToPoints(21)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
ElseIf ActiveSheet.PageSetup.PaperSize = xlPaperA3 Then
lngPagB = CLng(Application.CentimetersToPoints(29.7)) - CLng((ActiveSheet.PageSetup.LeftMargin + ActiveSheet.PageSetup.RightMargin))
End If
If lngPagB <> 0 And lngKolB <> 0 Then
lngZoom = ((lngPagB / lngKolB) * 100) - 1
With ActiveSheet.PageSetup
.Zoom = lngZoom
End With
End If
End If
Different widths:
Column B: 45 (319 pixels) -> in Excel, set with VBA
Column C: 15 (109 pixels) -> in Excel, set with VBA
Column D: 30 (214 pixels) -> in Excel, set with VBA
Column E: 20 (144 pixels) -> in Excel, set with VBA
Column B-E: 589 points -> with VBA
Page: 21 centimeters (595 points)
Margins (left & right): 1.8 centimeters (50.4 points)
Print area: 595 - 101 (100.8) = 494 points
With numbers above it calculates 83%, but then it doesn't fit, when I set it manually to 77% it does fit, but how can I get this number with VBA? I don't understand the column widths, what I see in Excel and how I set it in VBA (45+15+30+20) is different from what VBA tells me it should be (589)...

Column Width Units
Column width is measured in Characters, Points, Centimeters / Inches, Pixels, ...
Column width in Characters
If you set a column width by manual value input or by mouse, you see the "amount of standard font number characters". Please refer to Microsoft support for details.
This value can be read and written in VBA: .Range.ColumnWidth = 10.78.
The maximum value is 255.
Column width in Points
This is an internal value not shown in GUI during manual resize of a column.
It corresponds to 72 points per inch.
In VBA it can only be read: .Range.Width
Column width in Pixels
Excel shows the column width in pixels (in parentheses) during manual resize of a column width in normal view. This value can not be read or written directly in VBA.
Column width in Centimeters or Inches
During manual resize within the page layout view Excel shows column width in centimeters (or inches) instead of pixels.
Only this value depends on print zoom level!
The measurement unit itself can be read in VBA:
Application.MeasurementUnit ' 0 = xlInches, 1 = xlCentimeters, 2 = xlMillimeters
Conversion Formulas
By this you may check or verify all values in your environment:
Dim ScreenResolution As Double
Dim ColumnWidthChars As Double
Dim ColumnWidthPoints As Double
Dim ColumnWidthPixels As Double
Dim ColumnWidthInches As Double
Dim ColumnWidthCentimeters As Double
ScreenResolution = 120 ' normal (96 dpi) or large (120 dpi)
ColumnWidthChars = ActiveSheet.Columns(1).ColumnWidth
ColumnWidthPoints = ActiveSheet.Columns(1).Width
ColumnWidthPixels = (ColumnWidthPoints / 72) * ScreenResolution
ColumnWidthInches = ColumnWidthPoints / 72 * ActiveSheet.PageSetup.Zoom / 100
ColumnWidthCentimeters = ColumnWidthInches * 2.54
Debug.Print ColumnWidthChars, ColumnWidthPoints, ColumnWidthInches, _
ColumnWidthCentimeters, ColumnWidthPixels
ScreenResolution may be retrieved with API function GetDeviceCaps(hDC, 88)
Rounding Effects
Excel stores the character-based .Range.ColumnWidth with decimals for each relevant column in the workbook file. If you set it to 100, it is stored as e. g.
<cols><col min="1" max="1" width="100.77734375" customWidth="1"/></cols>
After reopening this file, the reported .ColumnWidth is 100 without decimals.
If you set a large column width and switch between normal view and page layout view, then you may register difference of about 2% between the measures (.Range.Width and pixels suddenly change) - but all values still correspond to each other according to above formulas.
Display Scaling Dependency
All different column width values are independent of Excel's view zoom level and/or Windows 10 display scaling.
Print Zoom Dependency
Only the inch- and centimeter values change, if you change the print zoom level.
But you get more or less columns i. e. amount of points on your paper.
Excel measures .PageSetup.Leftmargin in points (with a scale of 72 points per inch). This corresponds to .Range.Width which is also measured in points.
Example: If I set both paper margins to 5.5 cm, then the resulting A4 paper width of 10 cm holds e. g. two columns with a total .Width of appr. 283 points which corresponds to 72 points/inch.
If I set the print zoom to 83 percent a .Width of appr. 340 points is maximum, and at a print zoom of 30 % it's almost 943 points.
Print Scaling
The calculation of a print zoom factor is
WorkSheet.PageSetup.Zoom = (PageWidthInPoints / AllColumnsWidthInPoints) * 100
Your calculation seems to be correct, but I would subtract at least 2 % (see rounding effects above).

Related

Excel 2016 and newer VBA: how to maximize a chart within/to the worksheet size?

In https://i.stack.imgur.com/s6gII.png and How to get the size (width and height) of the area with excel vsto c# excluding the ribbon area? a similar question has already been put.
Excluding all GUI elements outside/around the "inner/client" worksheet area, e.g. without the ribbon, "X/ok/fx" + cell contents, Sheet menu, "Ready + Record Macro" footer line + frame heights, left + right border + frame widths, etc.
And together with How to get the screen position of an active workbook? neither of these links has answered my needs yet. Or their instructions do not work for me, because neither of the .PageSetup.*Margin values corresponds to my worksheet "inner/client" OR "outside/GUI" borders + frames + overhead sizes.
I know, by writing
With ActiveChart.Parent 'access the chart container = the Shape
.Left = 0
.Top = 0
.Width = 4 * 72 'fixed size example
.Height = 3 * 72 'fixed size example
End With
I can set the chart position + size, in this example to a fixed size of 3 * 4 inches.
But HOW TO GET/fetch the whole currently visible dynamic worksheet "inner/client" size (at least once a method call) ?
In order to set the chart size, so that it covers/uses the whole currently visible dynamic worksheet "inner/client" size (at least once a method call). Hopefully: nothing more (no scrollbars shifting needed to see the whole chart), nothing less (no unneccessary "tiny" chart) ?
[I know, that size assignment will work for me only "for a moment" until a workbook resize happens. So I'll have to adjust the chart size again (and again (and again ...)), e.g. by using a timer (or a system timer). Or is there some "anchor/chain/nail" chart property, so that it ALWAYS keeps up with the "inner/client" worksheet size (within the workbook) ?]
Thanks for your help
This is about as good as you can do.
Sub SizeChartToWindow()
Dim VisibleRange As Range
Set VisibleRange = ActiveWindow.VisibleRange
Dim UsableRange As Range
Set UsableRange = VisibleRange.Resize(VisibleRange.Rows.Count - 1, _
VisibleRange.Columns.Count - 1)
With ActiveChart.Parent
.Left = UsableRange.Left
.Top = UsableRange.Top
.Width = UsableRange.Width
.Height = UsableRange.Height
End With
End Sub
Many thanks, that helped me a lot.
This also takes care of the worksheet scrollbars "scrolled away", wonderful.
And the right + bottom remainder of 0.00 .. 0.99 * cell sizes is "good enough" (and I have reduced the cell width to match the cell height = 20 pixels in order to reduce that remainder effect).
:)))

Excel charts are placed on different positions depending on screen resolution

I am creating some charts with VBA. Target is to position them at the upper left corner of a cell (here as range rgCht) with a size of 16 rows x 9 columns.
Here is the code:
' Calculate active cell to place the chart
Set rgCht = wsGr.Cells(i * 17 + 2, 2)
Set cht = wsGr.ChartObjects.Add( _
Left:=rgCht.Left, _
Width:=rgCht.Width * 9, _
Top:=rgCht.Top, _
Height:=rgCht.Height * 16)
The result is that if the sheet is displayed on my notebook screen while the macro runs, all charts are placed and sized properly. However when I run it on a bigger screen, the charts are shifted 1 unit per row down, i. e. in line 70 I have 7 units difference between the calculated position and the real position on the sheet:
The line height is 14.5 units, so in row 70 the top position is 1000.5 . However when I manually move the chart to the top left corner of the cell and check the coordinates, I get 993.5.
I'm running out of ideas. Any hint is appreciated.
Both monitors run with a resolution of 1920x1080. Only difference is that the scaling is 125% on the big screen and 150% on the small one.

Excel pixels not proportional to points

I've noticed that (by changing column width) that the column width measured in points is not proportional to the pixel size. For example, at 21.44 points the pixel width of a column is 200. But at 20 pixels the width becomes 1.44 points, not the expected 2.14 points.
This is very confusing as I'm trying to write a code in VBA which will divide a particular size in 'n' different columns of equal size. Can anyone explain this abnormality? How can I write a code to divide the width (since the parameters for the column width are in points)?
Thanks
So I just was trying things and stumbled across this.
Maybe the numbers are off from a "true" width. If the theory is correct, then there must exist such an offset.
(21.44 + x) = 10 (1.44 + x)
x = 0.7822
Now let's see if this offset works for other some other lengths. For 80 pixels, the length mentioned by MS Excel is 8.11 points. Thus the true length is 8.89. The true length of a column with a width 20 pixels is 1.44 + 0.7822 = 2.222. Note that 2.222 * 4 = 8.89 approx. And this works for some other numbers as well, so I guess the theory should be correct.
Thus to answer the question, add the offset 0.7822 to the observed column width that you need to divide. Then divide it by 'n'. Subtract the offset to obtain the length 'x'. Then use the command Columns(var).ColumnWidth = x for each of the n columns

Assigning ColumnWidths with textbox data

I want to control the different column widths of a listbox with the use of textbox input. This is my code:
Sub code()
Dim x1 as integer
Dim x2 as integer
x1 = Me.TB1.value ‘x1 is assigned the number 40
x2 = Me.TB2.value ‘x2 is assigned the number 40
With Me.listbox1
.Clear
.ColumnCount = 2
.ColumnWidths = ‘’x1;x2’’
.list = getArray(SQLinput)
End with
End sub
Thanks for any help!
Edit:
The question, to be more precise, is that the code does not work. I am not allowed to write: .ColumnWidths = «x1;x2» So how can I write the code so that is it possible to control these variables from a textbox?
aListBox.ColumnWidths = newStringValue
or
StringValue = aListBox.ColumnWidths
A list of comma-separated values, with each value controlling the width of the associated column. A value can be an absolute value (in pixels), a percentage, a relative length expressed as i* where i is an integer, or an "*" that indicates "fill in the remaining width." If you use percentages, you can use non-integer values to specify fractions of a percent, e.g., 43.52%. The percentage value can be greater than 100%.
Notes
If you use pixels, the last column doesn't grow to the size of the rest of the ListBox. You should set the width of the last column to "" and it will automatically take up the remaining width of the ListBox.
Without any column width specifications, the headers will be divided evenly. If there are fewer column widths specified than the total number of columns, the remaining columns will divide up the remaining width equally.
An element with a length of "3" will be allotted three times the space of an element with length "1*". The value "" is equivalent to "1" and can be used to mean "fill the remaining space."

Why does the units of Range.ColumnWidth not match either points or Centimeters (default unit used)

I am producing a VBA subroutine in an Access database which generates an Excel File however when I modify the column widths using:
Range("A:A").ColumnWidth = ...
Produces mixed results depending on the unit of measurement. Excel's default measurement set in options is Centimeters. I have tried entering the value in points and in cm but the result is either too wide or too small (see below):
Range("A:A").ColumnWidth = 3.07 'In Centimeters - Too small
Range("A:A").ColumnWidth = 87.02 'In Points - Too big
According to the documentation
Range.ColumnWidth
is set using the measurement in the points unit of measurement (width of 0). Regardless of the value I enter the result isn't the same.
The .ColumnWidth property refers to the number of zeros you can type in a cell in the default font without exceeding the cell's width.
In a new workbook where presumably your default column width is 8.43, type '000000000 in a cell and you'll see that the 9th zero overflows the right cell border by about half a zero.
To set the cell width in points, set .ColumnWidth to points / cell.Width * cell.ColumnWidth. Here's the catch, you have to set it three times to get it close, but it will almost never be exact. So put the .ColumnWidth assignment in a For Next loop and set it three times.
Note that the .Width property is in points and you can't set it. The .ColumnWidth property is in crazy-zero-width-measurement and you can set it. Why it takes three times, I don't know.
See http://dailydoseofexcel.com/archives/2004/06/01/column-widths-in-points/ for some test results on the 'three times' thing.

Resources