Centering shape in Cell increases height from top as row increases - excel

I have a macro that is taking information from another sheet and reformating. Every 5th row down there should be an image and all other information is entered correctly in the following rows. As the row number increases it is increasing distance from the top of the cell to the image. For example, if the first shape is 5 pixels from the top of the designated cell, the next will be 6 and so forth. If it was a simple trend I could add a variable to accommodate this, but all images are slightly different in size thus why I am trying to do this dynamically.
So far, as mentioned above, I have tried doing this statically by using a variable to account for the increase, but to no success. Below is the code I am currently using that does not seem to be working.
If CopyPicFromCell(shtSource.Range("A1").Offset(i - 1, 2)) Then
'copied the picture, so paste to shtDest
shtDest.Paste
With shtDest.Shapes(shtDest.Shapes.Count)
.Top = shtDest.Range("A1").Offset(x - 3, 0).Top + ((shtDest.Range("A1").Offset(x - 3, 0).Height - .Height) / 2)
.Left = shtDest.Range("A1").Offset(x - 3, 0).Left + (shtDest.Range("A1").Offset(x - 3, 0).Width - .Width) / 2
End With
End If
This always centers the image left to right but does not seem to be doing the trick vertically. Please inform if there is any other information needed. Thanks!

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.

VBA - How to access and retrieve the PageSetup.FitToPagesWide variable?

My Page Breaks can almost be seen on the end of Column H and Row 33.
The end of Column H is 245 pixels (34.14cm)
The end of Row 33 is 20 pixel (15cm)
I need some guidance on how can I accesss these figures rather than have fixed variables. These figures will change so I need to somehow intelligently retrieve these PageSetup.FitToPagesWide to get the correct figure.
It is somewhat saying, finding the width of the page and finding the height of the page.
If a small snippet of the length of a cell is Cells(c.row, 2) = Len(c)
Then what would width of the PageSetup.FitToPagesWide be?

Adjust right edge position of Word table with merged columns using Excel macro

I am working on a macro to format and extract information from a number of word documents that all have 1 table in it. The problem is that this table has many rows, and each each row has either 1, 2, or 3 columns in it, and I need to ensure that the right edge of the table is always the same width.
The actual behaviour that I want to replicate in VBA code is when you drag the little square thing on the ruler bar in word (that represents the right edge of the table) to adjust the right edge of the table for all rows. However, when I try and record a macro, it generates the following line of code, which does not work for tables with merged columns:
Selection.Tables(1).Columns(1).SetWidth ColumnWidth:=501.3, RulerStyle:= _
wdAdjustNone
Next I tried to explicitly target just the first row using the following code. This worked, but it only resized the width for the first row - all of the other rows were unchanged:
wdApp.Documents(myDoc).Tables(1).Cell(1, 1).SetWidth ColumnWidth:=501.3, RulerStyle:=_
wdAdjustNone
I then played around with the .width property, rather than the .setwdith property, but they seemed to behave the same. I even tried all four .setwidth RulerStyle parameters but they all behaved the same.
Finally, in frustration, I decided to loop through all of the rows in the table, and resize the rightmost column as needed so the entire row is my desired 501.3 pixels. This took some doing, as I could not find a way to tell how many columns are on a given row. I ended up relying on trapped errors to solve the issue - see below. The 4th row will error when there are not enough columns on that row, so I simply reduce the i variable and try again until there is no error:
On Error GoTo BadExit
For row = 1 To wdApp.Documents(myDoc).Tables(1).Rows.count
i = 3
If wdApp.Documents(myDoc).Tables(1).Cell(row, i).PreferredWidth <> 1501.3 Then
If i = 3 Then
wid = 501.3 - wdApp.Documents(myDoc).Tables(1).Cell(row, 2).Width - wdApp.Documents(myDoc).Tables(1).Cell(row, 1).Width
wdApp.Documents(myDoc).Tables(1).Cell(row, i).Width = wid
ElseIf i = 2 Then
wid = 501.3 - wdApp.Documents(myDoc).Tables(1).Cell(row, 1).Width
wdApp.Documents(myDoc).Tables(1).Cell(row, i).Width = wid
Else
wid = 501.3
wdApp.Documents(myDoc).Tables(1).Cell(row, i).Width = wid
End If
End If
GoTo SafeExit
BadExit:
If i = 3 Then
i = 2
Resume
ElseIf i = 2 Then
i = 1
Resume
End If
SafeExit:
Next row
This code runs through with no errors however the final width never seems to be 501.3 - it seems to vary inconsistently (which I confirmed by using msgbox with the .width property), and also, sometimes the right edges are not lined up! The rows with 1 column may stick out a bit further than the rows with 2 columns, etc. And this code is very slow.
Can anybody help me find a simple solution to replicate the behavior of manually using your mouse to move the right square on the ruler to adjust the width of every row in a word table to a specific value? Your help would be greatly appreciated.
Thanks in advance,
-Josh

Generated Data Label values from worksheet sometimes don't show

I am generating values in Excel 2010, initially putting them into an array, then copying them into a worksheet for use as datalabels for a logarithmix x-axis (actually calling Chart Labeller to do that, but this also happens when i manually apply through Excel). For the most part this works fine without problems. In certain instances, however, some, but not all, of the data labels do not visible show, even though the data in the worksheet is there, manually selecting the data labels shows an invisible label selected.
What I found out, and I think this may be a bug in Excel, when I go to the worksheet, and re-type in the value that is not showing up on the chart, it then shows up on the chart.
Here are my dim's for the array:
Dim chart_labeler_info_x()
Here is how I populate the array:
'Assuming we are going to do the x-axis
ReDim chart_labeler_info_x(1 To x_axis_interval_num, 1 To 3)
For k = 1 To x_axis_interval_num
'Column 1 is the new chart label value, column 2 is the y value of the new series , column 3 is the x value(equivalent to 111...)
'--------------------------------------------------------
chart_labeler_info_x(k, 1) = suf_ize(10 ^ (Log(x_axis.MinimumScale) / Log(10#) + (k - 1)))
chart_labeler_info_x(k, 2) = y_axis.MinimumScale
chart_labeler_info_x(k, 3) = 10 ^ (Log(x_axis.MinimumScale) / Log(10#) + (k - 1))
'--------------------------------------------------------
Next k
Here is how I initialize the range on the worksheet:
Set new_labeler_ws_x_axis = Sheets.Add
new_labeler_ws_x_axis.Name = Chart_for_series & "Eng_Labels_X_Axis"
new_labeler_ws_x_axis.Range("a1:c" & x_axis_interval_num).Value = chart_labeler_info_x
new_labeler_ws_x_axis.Range("a1:c" & x_axis_interval_num).Font.Name = "Arial"
new_labeler_ws_x_axis.Range("a1:c" & x_axis_interval_num).Font.Size = 7
I also create a new series attached to this range:
With ActiveChart.SeriesCollection.NewSeries
.XValues = Sheets(new_labeler_ws_x_axis.Name).Range("C1:C" & x_axis_interval_num)
.Values = Sheets(new_labeler_ws_x_axis.Name).Range("B1:B" & x_axis_interval_num)
.Name = "=""Labeller_x"""
.Border.Color = RGB(0, 0, 0)
.Format.line.Visible = True
End With
The data that is generated in the worksheet looks like this:
1m 100 0.001
10m 100 0.01
100m 100 0.1
1 100 1
10 100 10
100 100 100
1k 100 1000
Column 1 has the values that will be used as the new data labels. Column 2 is the y-value, Column 3 is the actual x-value. (I can attach the worksheet if that helps.)
Here is an image of what I am talking about:
You notice that the 1k data label that should be there, is not visible.
I can make the 1k data label appear one of two ways:
Extend the maximum value for the series, in this case to 10,000 (10k) in which case the 1k label shows.
Manually go to the worksheet, select the cell that has the 1000 value, re-enter the value 1000 and press return, the data label then shows up as 1k.
Some other interesting anomalies, when the maximum value is 100, the data label for 100 disappears also. As the maximum value is increased beyond 1000, there seems to be no problems the data labels all show themselves.
I have tried changing the number format, which general, to number, with two decimal places, no luck. Changing to text and back, no luck.
I think this is a bug, but haven't found in info, can any of the experts out there shine some light on this?
I found a solution, while somewhat of a hack, i think it underlines what the problem may actually be, and maybe someone can suggest a more elegant solution.
I added the last line of this code block:
chart_labeler_info_x(k, 1) = suf_ize(10 ^ (Log(x_axis.MinimumScale) / Log(10#) + (k - 1)))
chart_labeler_info_x(k, 2) = y_axis.MinimumScale
chart_labeler_info_x(k, 3) = 10# ^ (Log(x_axis.MinimumScale) / Log(10#) + (k - 1#))
'This line did the trick
If chart_labeler_info_x(k, 3) >= 1 Then chart_labeler_info_x(k, 3) = Round(chart_labeler_info_x(k, 3), 0)
As i said previously, we had found that manually updating the value in the cell, caused the labels to be visible. We tried applying the Round function to the value in the cell, and that worked, so i put it as a check in the code, for values of 1 and higher.
It appears that, even though the cell value shown is 1000, internally, it must not be. (I checked .value and .value2, they both reported 1000.) The bug i think lies in this happening SOMETIMES. If the maximum value of the series is increased, the 1k label appears, even though it it the same math being used to generate the values.
Maybe someone can explain why this is happening and offer a more elegant solution!
Thanks,
Russ

Resources