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

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).
:)))

Related

Resize Chart Right to Left

I need help please in resizing Excel charts to expan right versus the standard expanding left.
I input the vba code below to each chart to resize and it works fine, except for the charts of the right side of the workbook, it expands off the screen and I don't want to have to scroll right.
How can I modify the code so that it expands left versus rt?
Thanks!
Sub Chart140_Click()
With ActiveSheet.ChartObjects(Application.Caller)
If .Height = (ThisWorkbook.Sheets("configuration").Range("chrtrngzoominh")) Then
.Height = Format(ThisWorkbook.Sheets("configuration").Range("chrtrngzoomouth"))
.Width = Format(ThisWorkbook.Sheets("configuration").Range("chrtrngzoomoutw"))
Else
.Height = Format(ThisWorkbook.Sheets("configuration").Range("chrtrngzoominh"))
.Width = Format(ThisWorkbook.Sheets("configuration").Range("chrtrngzoominw"))
End If
End With
End Sub
Excel charts are positioned with the top left corner. If you want to change the size of a chart and and anchor the right hand side, you will need to use a workaround along these lines:
save the initial chart position of the top left into variables
save the initial chart width into a variable
increase the chart width
calculate the width difference between initial and the new width
adjust the top left position by the width difference

Excel chart (shape) pasted as Bitmap will not adjust width in VBA?

I have a chart in a spreadsheet that I want to copy as a bitmap and place somewhere else within the same sheet. My code is below, although there's not much to see. No matter what I change .width to, the width of the chart does not adjust to what I tell it to. However, the width will change if I change .Height. This indicates that the pasted Bitmap image insists on retaining its original proportions.
Is this property specific to Bitmap objects, and is there a way around this problem without changing the paste format to something other than Bitmap?
Thanks for your help.
Set AB = ActiveSheet.Shapes(ActiveSheet.Shapes.Count)
With AB
.Left = ActiveSheet.Range("AB1").Left
.Top = ActiveSheet.Range("AB1").Top
.Width = ActiveSheet.Range("AB100:BM100").Width
.Height = ActiveSheet.Range("AB1:AB50").Height
End With
I'm guessing the bitmap you pasted has "Lock Aspect Ratio" set (Format Picture -> Size & Properties). In this case, Excel will change the Width of the bitmap after you set the Height (to preserve the bitmap's aspect ratio).
Use .LockAspectRatio = msoFalse before you set the Height and Width properties.

Zoom couple of columns to fit page with VBA

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).

How to set Excel column widths to a certain number of pixels?

I have the following data set on a worksheet:
SheetName|ColumnIndex|Pixels
---------+-----------+------
abc |1 |50
abc |2 |150
def |1 |125
For each sheet, I'd like to set the column width to the appropriate number of pixels, using something like:
Sub setColumn (sheetName As string, columnIndex As long, pixels As long)
width=getWidthInCharacters(pixels)
ThisWorkbook.Sheets(sheetName).Cells(1, columnIndex).EntireColumn.ColumnWidth = width
End Sub
I haven't been able to figure out how to write the getWidthInCharacters() function. How do I convert pixels to characters, or possibly set .ColumnWidth to pixels directly?
I'm sorry to tell you, but in my experience, you can't. Column width is measured in points, and whilst you can - in theory - convert points to pixels, Excel won't listen very precisely when you assign them. They also seem to vary somewhat from monitor to monitor. Basically, points are fractions of inches, pixels are dots on the screen. Windows has a notion (right or wrong) of how many pixels there are to a point given a particular output device.
You can write a function that tweaks column width, but usually the approach has to be
Find the smallest contextual value that excel is willing to increment a column width by (say, store the original value, then assign .ColumnWidth = dblOriginal + 0.01. Check if columnwidth has changed - if it has, you just made a 1-pixel adjustment. If it hasn't, you need a bigger number than 0.01.
Find a final column width in pixels that you want, and repeat this first step until you've incremented the column width that many times.
Check the result, and see if it looks OK.
Word of warning: this is horrible, slow, and not good code, and if they've fixed column widths in versions of Excel after 2010, then you might be lucky and just be able to use a pixels-to-points function, convert and assign. There are some around, just in my experience they didn't give me consistent results on different screens on the same machine. Really weird that one.
.ColumnWidth does not depend on theme font selection, but pixel width does: https://support.microsoft.com/en-us/kb/214123
'pixel width of column A
Debug.Print (Columns("A").Width / 72) * ThisWorkbook.WebOptions.PixelsPerInch
After some reading and thinking, my solution:
Sub setColumnWidth(rColumnWidth As Range, iPixelWidth As Integer)
' set column width by pixels
' check status ScreenUpdating
Dim bScreenUpdatingState As Boolean
bScreenUpdatingState = Application.ScreenUpdating
' set status ScreenUpdating
If bScreenUpdatingState = True Then Application.ScreenUpdating = False
Dim iPointsPerInch As Byte
iPointsPerInch = 72
Dim iPixelsPerInch As Byte
iPixelsPerInch = ThisWorkbook.WebOptions.PixelsPerInch
' check 2 column widths: get iPointDelta
Dim rColumn As Range
Set rColumn = rColumnWidth.EntireColumn
rColumn.ColumnWidth = 1
Dim iPoint_1 As Single
iPoint_1 = rColumn.Width
rColumn.ColumnWidth = 2
Dim iPoint_2 As Single
iPoint_2 = rColumn.Width
Dim iPointDelta As Single
iPointDelta = iPoint_2 - iPoint_1
' set column width to iPixelWidth
Dim iPoint_New As Single
iPoint_New = iPixelWidth / iPixelsPerInch * iPointsPerInch
Dim iChar_New As Single
iChar_New = (iPoint_New - (iPointDelta - 1.5)) / iPointDelta
rColumn.ColumnWidth = iChar_New
' reset status ScreenUpdating
If bScreenUpdatingState = True Then Application.ScreenUpdating = True
End Sub
To run the sub setColumnWidth:
Sub call_setColumnWidth()
Dim r As Range
Set r = ActiveSheet.Range("C1")
setColumnWidth r, 70
End Sub

Position a shape in Excel based on its center point

Is it possible to position a shape by its center point?
I'm trying to overlay shapes onto a picture of a map in Excel and adjust the size of the shapes based on the value in a cell.
I have the sizing portion figured out, but every time my shapes size increases it slowly starts to move to the right and bottom due to the positioning of its left and top. I would like it if the positioning of my circles would not moved once the data gets refreshed. I only want the size of the shape to be altered.
Any thoughts?
If you know the X/Y (really Left/Top, since {0,0} is upper left) where you want to put it, it is as simple as subtracting off half the size of the shape to get the center to be there.
Here is some simple code which puts the center of a circle at the corner of cell E8. I assume you have some way of selecting the shape based on your question.
Sub PositionByCenter()
Dim dbl_x As Double
Dim dbl_y As Double
'select a cell just to put it somewhere
dbl_x = Range("E8").Left
dbl_y = Range("E8").Top
'grab a reference to a shape
Dim shp As Shape
Set shp = Selection.ShapeRange.Item(1)
'position by the center
shp.Top = dbl_y - shp.Height / 2
shp.Left = dbl_x - shp.Width / 2
End Sub
Here is what you get after running that with a circle selected.

Resources