This issue can be demonstrated both in Delphi driving Excel through Ole-automation, but also from a Word/VBA macro. I am showing a test Word Macro (below) to prove it is not a Delphi issue, but also adding Delphi code as this might be easier for some.
This is a big issue for us at present and I wonder if anyone else has seen/solved this, or might at least have some suggestions, since I have spent a lot of time trying various workaround and googling for solutions. We need to get the images sized correctly as we have a hard specification that the images can not have any aspect ratio changes.
The issue is as follows. If we add an image from a jpeg file on to an Excel chart using the Chart.Shapes.AddPicture() method it works nicely as long as Excel is visible. The image appears where we place it, and when you inspect the image properties the horizontal and vertical scaling are both 100%. However we are wanting to perform this procedure on a large number of files, and due to the complexity of some of the other steps, having Excel visible is not great, as there is lots of flashing, resizing etc (which does not look very professional). It also slows the process down.
Now if we perform the exact same steps with Excel hidden (as you normally would doing using COM-Automation), the image appears, but is subtly changed. The amount of change can vary depending on the state of the chart window. But typically I see a Height scaling of 107% and width scaling of 99%.
Word Macro-VBA
Sub Test_Excel()
'
' Test_Excel Macro
'
'
'You will need to go to 'Tools/References' in the Word VBA editor and enable reference to
' Microsoft Excel
Dim Oxl As New Excel.Application
Dim owB As Excel.Workbook
Dim Chrt As Excel.Chart
Dim DSht As Excel.Worksheet
Dim i As Integer
Dim Rng As Excel.Range
Dim Ax As Excel.Axis
Dim Pic As Excel.Shape
'File name of an image on disk we are going to place on the graph. we don't want
' to link to it, as the Excel file will be sent to someone else.
'For the purposes of the test this file can be whatever suits, and what ever you want
' At a guess the scaling effect may differ on different files.
'Since I don't think I can attach a suitable image in StackOverflow it really doesnt
' matter what it is, but something around 300-400 x 160 pixels would show the issue.
ImageToAdd = "C:\Temp\Excel_Logo_test.jpg"
'Create a single chart workbook
Set owB = Oxl.WorkBooks.Add(xlWBATChart)
'Get reference to the chart
Set Chrt = owB.Charts(1)
On Error GoTo Err_Handler
Chrt.Activate
'Insert a data sheet before the chart
Set DSht = owB.Sheets.Add
'Insert some dummy data
DSht.Name = "Processed Data"
DSht.Cells(1, 1) = "X"
DSht.Cells(1, 2) = "Y"
For i = 2 To 11
DSht.Cells(i, 1) = i - 1
DSht.Cells(i, 2) = (i - 1) * 2
Next i
Set Rng = DSht.Range("$A:$B")
'Various set up of chart size and orientation
Chrt.PageSetup.PaperSize = xlPaperA4
Chrt.PageSetup.Orientation = xlLandscape
Chrt.SizeWithWindow = False
Chrt.ChartType = xlXYScatterLinesNoMarkers
Chrt.Activate
'Now add the data on to the chart
Chrt.SeriesCollection.Add Source:=Rng, Rowcol:=xlColumns, SeriesLabels:=True
'Set up for some general titles etc
Set Ax = Chrt.Axes(xlValue, xlPrimary)
Ax.HasTitle = True
Ax.AxisTitle.Caption = "Y-Axis"
Chrt.HasTitle = True
Chrt.ChartTitle.Caption = "Title"
'Resize the graph area to our requirements
Chrt.PageSetup.LeftMargin = Excel.Application.CentimetersToPoints(1.9)
Chrt.PageSetup.RightMargin = Excel.Application.CentimetersToPoints(1.9)
Chrt.PageSetup.TopMargin = Excel.Application.CentimetersToPoints(1.1)
Chrt.PageSetup.BottomMargin = Excel.Application.CentimetersToPoints(1.6)
Chrt.PageSetup.HeaderMargin = Excel.Application.CentimetersToPoints(0.8)
Chrt.PageSetup.FooterMargin = Excel.Application.CentimetersToPoints(0.9)
Chrt.PlotArea.Left = 35
Chrt.PlotArea.Top = 32
Chrt.PlotArea.Height = Chrt.ChartArea.Height - 64
Chrt.PlotArea.Width = Chrt.ChartArea.Width - 70
'Place image (#1) top left corner. At this point Excel is still invisible
Chrt.Shapes.AddPicture ImageToAdd, msoFalse, msoTrue, 0#, 0#, -1, -1
'Place image (#2) more to the right. At this point Excel is still invisible
Set Pic = Chrt.Shapes.AddPicture(ImageToAdd, msoFalse, msoTrue, 300#, 0#, -1, -1)
'Now try and force the scaling.... wont work!
Pic.ScaleHeight 1#, msoTrue, msoScaleFromTopLeft
Pic.ScaleWidth 1#, msoTrue, msoScaleFromTopLeft
Oxl.Visible = True
'Place the same image (#3) lower down. Excel is now visible
Chrt.Shapes.AddPicture ImageToAdd, msoFalse, msoTrue, 0#, 150#, -1, -1
'Place the same image (#4) lower down and right. Excel still visible
Set Pic = Chrt.Shapes.AddPicture(ImageToAdd, msoFalse, msoTrue, 300#, 150#, -1, -1)
'Now try and force the scaling.... will work when visible!
Pic.ScaleHeight 1.2, msoTrue, msoScaleFromTopLeft
Pic.ScaleWidth 1.2, msoTrue, msoScaleFromTopLeft
MsgBox "First check point"
'At this point we are going to pause with Excel visible to see the difference in the 4 images
'On my system (Office 2010)....
'The first: placed when Excel was not visible has some form of image scaling applied.
' Height_Scaling = 107%,
' Width Scaling = 99%.
'The second: Like the first, but we are going to try and force the scaling. Will not work!!
' Height_Scaling = 107%,
' Width Scaling = 99%.
'The 3rd: placed when Excel was visible has NO image scaling applied.
' Height_Scaling = 100%,
' Width Scaling = 100%.
'The 4th: Like the 3rd, but forcing scaling to 120% horz and vert. Will work because visible
' Height_Scaling = 120%,
' Width Scaling = 120%.
'Now try and force the scaling (image #2).... will work when visible!
Set Pic = Chrt.Shapes(2)
Pic.ScaleHeight 1#, msoTrue, msoScaleFromTopLeft
Pic.ScaleWidth 1#, msoTrue, msoScaleFromTopLeft
MsgBox "Do what you like now. When you have finished checking in Excel, click this box and the Excel instance will close"
'Suppress save message...
Oxl.DisplayAlerts = False
'Close the Excel instance so it is not left dangling in memory...
Oxl.Quit
Exit Sub
Err_Handler:
'An ERROR. Lets clear up...
MsgBox "Error"
'Suppress save message...
Oxl.DisplayAlerts = False
'Close the Excel instance so it is not left dangling in memory...
Oxl.Quit
End Sub
Delphi XE7 (but should run on anything from Delphi 7 onwards) test app (Single form one button)
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Vcl.OleAuto,
ExcelXP, OfficeXP;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
const
ExcelAppID = 'Excel.Application';
//File name of an image on disk we are going to place on the graph. we don't want
// to link to it, as the Excel file will be sent to someone else.
//For the purposes of the test this file can be whatever suits, and what ever you want
// At a guess the scaling effect may differ on different files.
//Since I don't think I can attach a suitable image in StackOverflow it really doesnt
// matter what it is, but something around 300-400 x 160 pixels would show the issue.
ImageToAdd = 'C:\Temp\Excel_Logo_test.jpg';
var
Oxl: Variant;
owB: Variant;
Chrt: Variant;
DSht: Variant;
i: Integer;
Rng: Variant;
Ax: Variant;
Pic: Variant;
begin
try
OxL:= CreateOleObject(ExcelAppID);
OxL.Visible:= false;
try
try
//Create a single chart workbook
owB:= Oxl.WorkBooks.Add(Integer(xlWBATChart));
//Get reference to the chart
Chrt:= owB.Charts[1];
Chrt.Activate;
//Insert a data sheet before the chart
DSht:= owB.Sheets.Add;
//Insert some dummy data
DSht.Name:= 'Processed Data';
DSht.Cells[1, 1]:= 'X';
DSht.Cells[1, 2]:= 'Y';
For i:= 2 To 11 do
begin
DSht.Cells(i, 1):= i - 1;
DSht.Cells(i, 2):= (i - 1) * 2;
end;
Rng:= DSht.Range['$A:$B'];
//Various set up of chart size and orientation
Chrt.PageSetup.PaperSize:= xlPaperA4;
Chrt.PageSetup.Orientation:= xlLandscape;
Chrt.SizeWithWindow:= False;
Chrt.ChartType:= xlXYScatterLinesNoMarkers;
Chrt.Activate;
//Now add the data on to the chart
Chrt.SeriesCollection.Add(Source:=Rng, Rowcol:=xlColumns, SeriesLabels:=True);
//Set up for some general titles etc
Ax:= Chrt.Axes(xlValue, xlPrimary);
Ax.HasTitle:= True;
Ax.AxisTitle.Caption:= 'Y-Axis';
Chrt.HasTitle:= True;
Chrt.ChartTitle.Caption:= 'Title';
//Resize the graph area to our requirements
Chrt.PageSetup.LeftMargin:= OxL.CentimetersToPoints(1.9);
Chrt.PageSetup.RightMargin:= OxL.CentimetersToPoints(1.9);
Chrt.PageSetup.TopMargin:= OxL.CentimetersToPoints(1.1);
Chrt.PageSetup.BottomMargin:= OxL.CentimetersToPoints(1.6);
Chrt.PageSetup.HeaderMargin:= OxL.CentimetersToPoints(0.8);
Chrt.PageSetup.FooterMargin:= OxL.CentimetersToPoints(0.9);
Chrt.PlotArea.Left:= 35;
Chrt.PlotArea.Top:= 32;
Chrt.PlotArea.Height:= Chrt.ChartArea.Height - 64;
Chrt.PlotArea.Width:= Chrt.ChartArea.Width - 70;
//Place image top left corner. At this point Excel is still invisible
Pic:= Chrt.Shapes.AddPicture(ImageToAdd, msoFalse, msoTrue, 0, 0, -1, -1);
//Pic:= Chrt.Shapes(1);
//Place image more to the right. At this point Excel is still invisible
Pic:= Chrt.Shapes.AddPicture(ImageToAdd, msoFalse, msoTrue, 300, 0, -1, -1);
//Pic:= Chrt.Shapes(2);
//Now try and force the scaling.... wont work!
Pic.ScaleHeight(1, msoTrue, msoScaleFromTopLeft);
Pic.ScaleWidth(1, msoTrue, msoScaleFromTopLeft);
Oxl.Visible:= True;
//Place the same image lower down. Excel is now visible
Pic:= Chrt.Shapes.AddPicture(ImageToAdd, msoFalse, msoTrue, 0, 150, -1, -1);
//Pic:= Chrt.Shapes(3);
//Place the same image lower down and right. Excel still visible
Pic:= Chrt.Shapes.AddPicture(ImageToAdd, msoFalse, msoTrue, 300, 150, -1, -1);
//Pic:= Chrt.Shapes(4);
//Now try and force the scaling.... will work when visible!
Pic.ScaleHeight(1.2, msoTrue, msoScaleFromTopLeft);
Pic.ScaleWidth(1.2, msoTrue, msoScaleFromTopLeft);
ShowMessage('First check point');
//At this point we are going to pause with Excel visible to see the difference in the 4 images
//On my system (Office 2010)....
//The first: placed when Excel was not visible has some form of image scaling applied.
// Height_Scaling = 107%,
// Width Scaling = 99%.
//The second: Like the first, but we are going to try and force the scaling. Will not work!!
// Height_Scaling = 107%,
// Width Scaling = 99%.
//The 3rd: placed when Excel was visible has NO image scaling applied.
// Height_Scaling = 100%,
// Width Scaling = 100%.
//The 4th: Like the 3rd, but forcing scaling to 120% horz and vert. Will work because visible
// Height_Scaling = 120%,
// Width Scaling = 120%.
//Now try and force the scaling.... will work when visible!
Pic:= Chrt.Shapes[2];
Pic.ScaleHeight(1, msoTrue, msoScaleFromTopLeft);
Pic.ScaleWidth(1, msoTrue, msoScaleFromTopLeft);
ShowMessage('Do what you like now. When you have finished checking in Excel, click this box and the Excel instance will close');
//Suppress save message...
Oxl.DisplayAlerts:= False;
//Close the Excel instance so it is not left dangling in memory...
Oxl.Quit;
except
//An ERROR. Lets clear up...
ShowMessage('Error');
end;
finally
//Suppress save message...
Oxl.DisplayAlerts:= False;
//Close the Excel instance so it is not left dangling in memory...
Oxl.Quit;
end;
except
raise exception.create('Excel could not be started.');
end;
end;
end.
I have tried all sorts of things, like explicitly trying to set the HeightScaling and WidthScaling properties of the image, but when Excel is not visible these do not work.
As far as I can see this is a bug in Excel, but if anybody has another idea I would love to hear it, and particularly if you have a workaround that does not involve Excel being visible. (I have tried making it visible just for the adding of the picture, and this works fine, but again a quick flash of Excel will look really unprofessional in our application, perhaps even more unprofessional).
The test code was written as a macro in Word 2010. [You have to make sure that you add Excel in the Project/References section]. [As mentioned in the code you will need to provide an image of some sort, since I don't think I can attach files in StackOverflow...]. It creates a spread sheet with a chart, adds a small amount of data, and charts it. Then 4 copies of the image are added
1. Simple Add (Excel hidden)
2. Simple add (Excel hidden), and then try and force the scaling
Show Excel
3. Simple Add
4. Simple Add, and then try and force the scaling (120%/120%)
A message box is then shown to halt the macro to allow inspection of the image properties on the chart area.
Images 1 and 2 are both show with scaling 107%/99%
Images 3 and 4 show as (100%/100%) and (120%/120%) so both 3 and 4 are correct.
When the message box is cleared (and with Excel now visible), the scaling on image 2 is adjusted to 100%/100%, and this now works correctly.
Another message box to allow checking this and finally Excel is closed.
I don't think the InsertPicture method is an option, as this links to the image file rather than embedding it. The final files must work properly as stand-alone entities so file links can not be used.
I would also prefer not to try workarounds like using the clipboard and the paste method. Nuking the clipboard can seriously upset users doing other things at the same time as this process is running.
Thanks in anticipation.
Related
I am trying to automate a series of PivotCharts within Excel. I am using Delphi Rio and Excel 2019. I have an XLSX file, with one sheet, called 'Sheet1'. I have enabled record macro within Excel, and recorded the VBA code. I have ported it to Delphi. Everything compiles, and I get an AV when I go to add my row fields (which becomes Axis fields in the PivotChart). In Excel, to record the macro, I select my sheet with my data, go to Insert/Pivot Chart, checking 'Add Data to Data Model', and then build a simple PivotChart.
The VBA code is
Cells.Select
Workbooks("TestFile.xlsx").Connections.Add2 "WorksheetConnection_Sheet1!$A:$CU" _
, "", "WORKSHEET;S:\Temp\[TestFile.xlsx]Sheet1", "Sheet1!$A:$CU", 7, True, _
False
Sheets.Add
ActiveWorkbook.PivotCaches.Create(SourceType:=xlExternal, SourceData:= _
ActiveWorkbook.Connections("WorksheetConnection_Sheet1!$A:$CU"), Version:=7). _
CreatePivotChart(ChartDestination:="Sheet3").Select
ActiveChart.ChartType = xlColumnClustered
ActiveChart.ChartStyle = 201
With ActiveChart.PivotLayout.PivotTable.CubeFields("[Range].[Fiscal Quarter]")
.Orientation = xlRowField
.Position = 1
End With
With ActiveChart.PivotLayout.PivotTable.CubeFields("[Range].[Territory Name]")
.Orientation = xlColumnField
.Position = 1
End With
ActiveChart.PivotLayout.PivotTable.CubeFields.GetMeasure "[Range].[Pipeline]", _
xlSum, "Sum of Pipeline"
ActiveChart.PivotLayout.PivotTable.AddDataField ActiveChart.PivotLayout. _
PivotTable.CubeFields("[Measures].[Sum of Pipeline]"), "Sum of Pipeline"
The problem I run into (when running my Delphi compiled executable' is when adding the 'Fiscal Quarter' rowfield. It APPEARS that CubeFields is not defined, although I get 'data inaccessible' when I mouse over it. So my first question, in Delphi, is CubeFields created automatically?
My Delphi code is
procedure BuildPivotChart;
var
myChart: _Chart;
myChartShape: Shape;
myPivotCache: PivotCache;
SourceSheet, DestSheet: _Worksheet;
myConnection: WorkbookConnection;
ConnName, ConnString, ConnCommand: String;
begin
// Create the connection since we are adding to DataModel
ConnName := 'WorksheetConnection_Sheet1!$A:$CU';
ConnString := 'WORKSHEET;S:\Temp\[TestFile.xlsx]Sheet1';
ConnCommand := 'Sheet1!$A:$CU';
myConnection := oExcel.ActiveWorkbook.Connections.Add2(ConnName, '', ConnString, ConnCommand, 7, True, False);
// Create a new Sheet, and get a handle to it...
oExcel.Worksheets.Add(EmptyParam, EmptyParam,1, xlWorksheet, LCID );
// Get a handle to the new sheet and set the Sheet Name
DestSheet := oExcel.ActiveSheet as _Worksheet;
DestSheet.Name := 'Graphs';
// Create a Pivot Cache, with a Chart object
myPivotCache := oExcel.ActiveWorkbook.PivotCaches.Create(xlExternal, myConnection, 7);
myChartShape := myPivotCache.CreatePivotChart(DestSheet, xlColumnClustered, 10, 10, 300, 300);
myChartShape.Select(EmptyParam);
myChart := oExcel.ActiveChart;
myChart.ChartStyle := 201;
if oExcel.ActiveChart.PivotLayout.PivotTable.PivotCache.IsConnected = True then
ShowMessage('Connected');
// Now add Row Fields
// ALL THREE OF THE BELOW LINES gives AV
oExcel.ActiveChart.PivotLayout.PivotTable.CubeFields.AddSet('[Range].[Fiscal Quarter]', 'MyName').Orientation := xlRowField;
oExcel.ActiveChart.PivotLayout.PivotTable.CubeFields['[Range].[Fiscal Quarter]'].Orientation := xlRowField;
// Thinking that the CUBE is not defined... check to see cube fields count..
ShowMessage(IntToStr(oExcel.ActiveChart.PivotLayout.PivotTable.CubeFields.Count));
...
When I step through my Delphi code, on the 'myPivotCache.CreatePivotChart' line, I see the chart object show up in Excel, and I see my columns listed in the Pivot selected on the right side of Excel. I have a suspicion that something is wrong with CubeFields, but I can't prove it, or I don't know how to fix it... I DO get my 'Connected' popup.
Any help or ideas appreciated.
This problem occurs when using EXCEL_TLB units.
It can be solved by changing to OLE development.
Use add unit "Excel2010" to "Uses" after interface, as:
interface
uses Excel2010
I have a macro that will append a page to the current document from a pre-formatted template. This page inserts a picture based off user selection, which they have the standard excel supported images(i.e. .jpg, .png, .bmp) as well as PDF's(taken off an AutoCAD program that can only save as PDF/DWG/DXF file types. The problem I'm having is that I cannot rotate landscape print formatted images the way that I can with the regular images. I know that the problem is likely that not all OLEobjects can be rotated and the shaperange option probably does not allow for rotation. That being said, is it possible to do this within VBA?
I have tried to use the OLEobject shaperange option, as well as inserting the PDF as a picture(which is not supported by MS-Office as far as I know). I have also tried to select the OLEobject as a shape to no avail.
Set rng = crrntWorkbook.Sheets(1).Range("B" & tempRow)
'Allows for the insertion of PDF files into the workbook
Set oleobj = ActiveSheet.OLEObjects.Add(Filename:=txtFileName, link:=False, DisplayAsIcon:=False)
With oleobj
'Inserts the picture into the correct cell
oleobj.Top = rng.Top
oleobj.Left = rng.Left
'If the image is wider than it's height, image will be scaled down by it's width, otherwise it's height
If oleobj.Width > oleobj.Height Then
oleobj.IncrementRotation = 90
oleobj.Width = 545
oleobj.Left = (570 - oleobj.Width) / 2
oleobj.Top = oleobj.Top + 2
'Centers the image
Else
oleobj.Height = 625
oleobj.Left = (550 - oleobj.Width) / 2
oleobj.Top = oleobj.Top + 2
End If
End With
The expected result is that the image will be rotated upon insertion, but I will get either a "runtime error '438' Object doesn't support this property or method" or a "runtime error -2147024809 the shape is locked and cannot be rotated if I use the shaperange approach"
I have an Excel spreadsheet displayed within an old VB6 application using OLE but recently the table is displayed very small for some reason. I did not change the code recently as far as I know and the problem seems to be only on users' computers.
Is there any way of forcing the size of display?
Changing the scale in the template file makes no difference.
Changing the sizemode makes no difference:
olePumpDetails.CreateLink g_strRangePumpDocumentation & strTemplate
If Not m_bDetailsExcelError Then
Set oBook = olePumpDetails.object
Set osheet = oBook.Sheets(1)
SetDetailExcelValues oBook, osheet
olePumpDetails.Refresh
End If
Elsewhere in the project on resize of form:
If olePumpDetails.Visible = True Then
olePumpDetails.Visible = False
olePumpDetails.Move 100, 400, Me.Width - 300, Me.Height - 1000
lblPumpDetailsError.Move (Me.ScaleWidth / 2) - (lblPumpDetailsError.Width / 2), lblPumpDetailsError.Top, lblPumpDetailsError.Left, lblPumpDetailsError.Top
olePumpDetails.Visible = True
End If
I expected the spreadsheet to be displayed normal size.
The Window object has a read / write Zoom property.
From the Microsoft Office Dev Center:
Returns or sets a Variant value that represents the display size of the window, as a percentage (100 equals normal size, 200 equals double size, and so on).
If Not m_bDetailsExcelError Then
Set oBook = olePumpDetails.object
Set osheet = oBook.Sheets(1)
SetDetailExcelValues oBook, osheet
oBook.Windows(1).Zoom = 200 'set the default zoom
olePumpDetails.Refresh
End If
My Excel UserForms contain a variety of objects, including text boxes, combo boxes, radio buttons, etc. The UserForm and the objects on the UserForm shrink and expand when my laptop is on a docking station and the VBA window is open on a larger monitor.
When I access the UserForm editor from the Forms tab in VBA, I can drag the UserForm resize handles and the objects in the UserForm will immediately snap back to their original state, but I want to do this programmatically so that the end user will not deal with shrunken/expanded UserForms.
I have tried resizing the UserForm upon opening (UserForm_Initialize), but it seems as if the shrinking/expanding takes place while the UserForm is not active, meaning that my UserForm resizing only acts to return the UserForm to its shrunken/expanded state and not its original state.
Sub UserForm_Initialize()
Call ResizeUserform(Me)
End Sub
Sub ResizeUserform(UserForm_Name As Object)
UserForm_Name.Width = UserForm_Name.Width + 0.001
UserForm_Name.Width = UserForm_Name.Width - 0.001
UserForm_Name.Height = UserForm_Name.Height + 0.001
UserForm_Name.Height = UserForm_Name.Height - 0.001
End Sub
Don't leave your form's dimensions ambiguous or prone to logic circularity (i.e. as a function of itself); set them up before loading/showing.
i.e.:
'where XX and YY are integer constants:
With YourFormName
.width=XX
.height=YY
.show
end with
If you absolutely need to incur in circular statements, do it indirectly by storing your calculated variable in a global/local variable, and then proceed to declare its properties (i.e. YourFormName.width=variable)
Good luck!.
I had a similar issue, ever time the program opened the Login user form would be smaller than the last time. It only did it on my lap top with extra monitors. I finally used
Private Sub UserForm_Initialize()
With Userform
.Width = Application.Width * 0.3
.Height = Application.Height * 0.6
End With
End Sub
in the userforms code and it kind of stopped meaning it no longer showed the user the change but if I open the VBA it had changed size on the Height and Width but since it was only in the VBA and the user didn't have to try and enter a password in a mini box its fine.
I had a similar problem. The only thing that worked for me was going into the Advanced Options of Excel and checking the box, "Disable hardware graphics acceleration." I wasted several hours trying to find this. I hope this helps someone else!
Don't make the form maximized. "Maximized" means you don't know at design-time what the size of the form will be, because you're making that depend on what monitor size it's being displayed in.
Larger monitor = larger maximized form, that's by design.
If you don't want the form to resize automatically when it's displayed in a different-size monitor, then don't maximize it.
Alternatively, handle the form's Resize event, and programmatically move each control where it needs to be relative to the bottom-right edge. Note, that's tricky and extremely annoying code to write, especially if the form is any kind of complicated. Much simpler to just not have a maximized form.
this operation can also be done with a loop. I used the button to increase and decrease the height of userform. I created a loop and assigned it to the button.At the same time there was a nice animation.
You set a height value, when the button is pressed, the userform becomes longer if the height is less than this value, and the userform becomes shorter if it is larger.
Codes:
Private Sub CommandButton4_Click()
Dim X, d, yuk, mak As Integer
For X = 1 To 100
DoEvents
If e = 0 Then
d = d + 10
yuk = 242
mak = 342
Else
d = d - 10
yuk = 345
mak = 245
End If
UserForm2.Height = yuk + d
If UserForm2.Height >= mak And e = 0 Then GoTo 10
If UserForm2.Height <= mak And e = 1 Then GoTo 20
Next
10 CommandButton4.Caption = "<"
e = 1
ListBox1.ListIndex = 0
ScrollBar1_Change
Exit Sub
20 CommandButton4.Caption = ">"
e = 0
ListBox1.ListIndex = 0
End Sub
It's video :https://www.youtube.com/watch?v=1LCxgQGy9tU
Source and Example file here
How can I stop a button from resizing? Each time I click on the button, either the size of the button or the font size changes.
Note: I cannot lock my sheet as my Macro will write into the sheet.
Autosize is turned off. I run Excel 2007 on Windows 7 (64 Bit).
I use the following for ListBoxes. Same principle for buttons; adapt as appropriate.
Private Sub myButton_Click()
Dim lb As MSForms.ListBox
Set lb = Sheet1.myListBox
Dim oldSize As ListBoxSizeType
oldSize = GetListBoxSize(lb)
' Do stuff that makes listbox misbehave and change size.
' Now restore the original size:
SetListBoxSize lb, oldSize
End Sub
This uses the following type and procedures:
Type ListBoxSizeType
height As Single
width As Single
End Type
Function GetListBoxSize(lb As MSForms.ListBox) As ListBoxSizeType
GetListBoxSize.height = lb.height
GetListBoxSize.width = lb.width
End Function
Sub SetListBoxSize(lb As MSForms.ListBox, lbs As ListBoxSizeType)
lb.height = lbs.height
lb.width = lbs.width
End Sub
I added some code to the end of the onClick thus:
CommandButton1.Width = 150
CommandButton1.Height = 33
CommandButton1.Font.Size = 11
Seems to work.
I got the issue a slightly different way. By opening the workbook on my primary laptop display, then moving it to my big monitor. Same root cause I would assume.
Seen this issue in Excel 2007, 2010 and 2013
This code prevents the issue from manifesting. Code needs to run every time a active X object is activated.
Sub Shared_ObjectReset()
Dim MyShapes As OLEObjects
Dim ObjectSelected As OLEObject
Dim ObjectSelected_Height As Double
Dim ObjectSelected_Top As Double
Dim ObjectSelected_Left As Double
Dim ObjectSelected_Width As Double
Dim ObjectSelected_FontSize As Single
ActiveWindow.Zoom = 100
'OLE Programmatic Identifiers for Commandbuttons = Forms.CommandButton.1
Set MyShapes = ActiveSheet.OLEObjects
For Each ObjectSelected In MyShapes
'Remove this line if fixing active object other than buttons
If ObjectSelected.progID = "Forms.CommandButton.1" Then
ObjectSelected_Height = ObjectSelected.Height
ObjectSelected_Top = ObjectSelected.Top
ObjectSelected_Left = ObjectSelected.Left
ObjectSelected_Width = ObjectSelected.Width
ObjectSelected_FontSize = ObjectSelected.Object.FontSize
ObjectSelected.Placement = 3
ObjectSelected.Height = ObjectSelected_Height + 1
ObjectSelected.Top = ObjectSelected_Top + 1
ObjectSelected.Left = ObjectSelected_Left + 1
ObjectSelected.Width = ObjectSelected_Width + 1
ObjectSelected.Object.FontSize = ObjectSelected_FontSize + 1
ObjectSelected.Height = ObjectSelected_Height
ObjectSelected.Top = ObjectSelected_Top
ObjectSelected.Left = ObjectSelected_Left
ObjectSelected.Width = ObjectSelected_Width
ObjectSelected.Object.FontSize = ObjectSelected_FontSize
End If
Next
End Sub
(Excel 2003)
It seems to me there are two different issues:
- resizing of text of ONE button when clicking on it(though not always, don't know why), and
- changing the size of ALL buttons, when opening the workbook on a display with a different resolution (which subsist even when back on the initial display).
As for the individual resizing issue: I found that it is sufficient to modify one dimension of the button to "rejuvenate" it.
Such as :
myButton.Height = myButton.Height + 1
myButton.Height = myButton.Height - 1
You can put it in each button's clicking sub ("myButton_Click"), or implement it
a custom Classe for the "onClick" event.
I experienced the same problem with ActiveX buttons and spins in Excel resizing and moving. This was a shared spreadsheet used on several different PC's laptops and screens. As it was shared I couldn't use macros to automatically reposition and resize in code.
In the end after searching for a solution and trying every possible setting of buttons. I found that grouping the buttons solved the problem immediately. The controls, buttons, spinners all stay in place. I've tested this for a week and no problems. Just select the controls, right click and group - worked like magic.
Use a Forms button rather than an ActiveX one, ActiveX controls randomly misbehave themselves on sheets
Do you have a selection command in the buttons macro?
Shortly after I renamed some cells in a worksheet including one that the toggle button selects after its toggle function, the font size shrunk. I fixed this by making sure Range("...").Select included the new cell name, not the coordinates.
It happens when the screen resolution / settings change after Excel has been open.
For example:
Open a workbook that has a button on it
Log in with Remote Desktop from a computer with different screen size
Click on the button => the button size will change
The only solution I found is to close Excel and reopen it with the new screen settings. All instances of Excel must be closed, including any invisible instance executed by other processes without interface must be killed.
Old issue, but still seems to be an issue for those of us stuck on Excel 2007. Was having same issue on ActiveX Listbox Object and would expand its size on each re-calculate. The LinkCells property was looking to a dynamic (offset) range for its values. Restructuring so that it was looking to a normal range fixed my issue.
I had this problem using Excel 2013. Everything for working fine for a long time and all of sudden, when I clicked on the button (ActiveX), it got bigger and the font got smaller at the same time.
Without saving the file, I restarted my computer and open the same Excel file again and everything is fine again.
Mine resized after printing and changing the zoom redrew the screen and fixed it
ActiveWindow.Zoom = 100
ActiveWindow.Zoom = 75
Found the same issue with Excel 2016 - was able to correct by changing the height of the control button, changing it back, then selecting a cell on the sheet. Just resizing did not work consistently. Example below for a command button (cmdBALSCHED)
Public Sub cmdBALSCHED_Click()
Sheet3.cmdBALSCHED.Height = 21
Sheet3.cmdBALSCHED.Height = 20
Sheet3.Range("D4").Select
This will reset the height back to 20 and the button font back to as found.
After some frustrated fiddling, The following code helped me work around this Excel/VBA bug.
Two key things to note that may help:
Although others have recommended changing the size, and then immediately changing it back, notice that this code avoids changing it more than once on single toggle state change. If the value changes twice during one event state change (particularly if the second value is the same at the initial value), the alternate width and height properties may not ever be applied to the control, which will not reset the control width and height as it needs to be to prevent the width and height value from decreasing.
I used hard-coded values for the width and height. This is not ideal, but I found this was the only way to prevent the control from shrinking after being clicked several times.
Private Sub ToggleButton1_Click()
'Note: initial height is 133.8 and initial width was 41.4
If ToggleButton1.Value = True Then
' [Code that I want to run when user clicks control and toggle state is true (not related to this issue)]
'When toggle value is true, simply change the width and height values to a specific value other than their initial values.
ToggleButton1.Height = 40.4
ToggleButton1.Width = 132.8
Else
' [Code that I want to run when user clicks control and toggle state false (not related to this issue)]
'When toggle value is false adjust to an alternate width and height values.
'These can be the same as the initial values, as long as they are in a separate conditional statement.
ToggleButton1.Height = 41.4
ToggleButton1.Width = 133.8
End If
End Sub
For a control that does not toggle, you may be able to use an iterator variable or some other method to ensure that the width and height properties alternate between two similar sets of values, which would produce an effect similar the toggle state changes that I used in this case.