checkbox rename in excel macro - vb.net

I would like to create an excel macro, in which I create some chechboxes. When I record the macro, I choose the properties of the chechbox in edit mode, then on the left side i give new position values, size values, name and caption to the chechbox. But the macro itself don't remember, just the size and position values.
It will be in the visual basic code:
ActiveSheet.OLEObjects.Add(ClassType:="Forms.CheckBox.1", Link:=False, _
DisplayAsIcon:=False, Left:=128.25, Top:=84.75, Width:=108, Height:= _
21).Select
When I try to write in the code itself, that Caption:="xyz", that will be error.
How can I handle this?

If you want to do this via your VBA macro. Then the code in this question (not answers) can provide the syntax needed.
Otherwise, the following should work, it's not the cleanest but does the job (hat tip to Google for finding this):
Sub test()
Dim obj As OLEObject
Set obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CheckBox.1")
obj.Name = "checkboxx"
obj.Object.Caption = "CAPTION"
End Sub
Note that you will not be able to run this using the Step Into functionality of VBA (F8).

Please take a look at the attached image 1

Related

VBA (Word): Draw Textbox with TextEffect msoTextEffectShapeArchUpCurve

Summary:
Using Visual Basic for Applications (VBA), I'm trying to draw a Textbox and apply the TextEffect msoTextEffectShapeArchUpCurve to it.
This works fine when drawing this in an Excel sheet, but will not work in a Word document (although it can be done in the same way using the GUI).
So I have an Excel file where the script is run from. This script creates a new Word document and draws shapes inside of it.
Example:
Dim objWord
Dim objDoc
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
objDoc.Activate
With ActiveDocument.Shapes.AddTextbox( _
msoTextOrientationHorizontal, _
50, _
50, _
200, _
200 _
)
.TextFrame.TextRange.text = "Some text to curve"
.TextEffect.PresetShape = msoTextEffectShapeArchUpCurve '<-- error
End With
Problem:
The code gives an Error 4652: Invalid type of drawing object for this command.
According to the documentation this should work. (And it can be done with the GUI, although no code is produced when recording the actions in a macro..)
Am I doing something wrong? And how can I fix this?
A screenshot of how it should look like (left) and how this is done in the GUI (right):
Note: Using AddTextEffect instead of AddTextbox is not really an option, since WordArt text is distorted compared to a textbox with the chosen effect.
You are using late binding (with CreateObject) so Excel does not know what msoTextEffectShapeArchUpCurve is.
It is a constant, a value, so you can just replace it with 9.
Unfortunately, it's still a mystery why Word won't let VBA set this text effect on textboxes, while on the other hand allowing it in the GUI. (Any help or information on that would still be greatly appreciated!)
However, there is a work around that worked for me:
Create the textbox in the Excel document and apply the text effect there (using the code from my example).
Then let VBA cut and paste the shape into the new Word document.

Detect Button Press Event on an Excel Sheet MultiPage Form (NOT a VBA MultiPage)

I am struggling to figure out how to detect a button press event on a MultiPage form that resides directly on an Excel sheet. In other words, the form is not generated using VBA, it is built directly on the sheet.
I expect the syntax to be something like:
Private Sub MultiPage1_Frame1_CommandButton1_Click()
Do Stuff
End Sub
However, that doesn't work because I think I also need to specify the page in the MultiPage. For example, a text box on the same form can be accessed via:
MultiPage1.Pages(0).Frame1.TextBox1.Text = "Some Text"
Unfortunately,
Private Sub MultiPage1_Pages(0)_Frame1_CommandButton1_Click()
gives a Compile error: Expected: identifier with the zero inside (0) selected.
So, how do I convert
MultiPage1.Pages(0).Frame1.CommandButton1
to a Sub name that will detect the button press event?
Thank you!
I'm not sure but I think you may have stumbled onto a bug.
There is a Microsoft Forms 2.0 Control under More Controls, but I'm pretty sure it's only intended only for use on UserForms.
I tried adding it to a worksheet and got an error. However, once I added one to a UserForm and went back to the worksheet, I was able to add it... but things got "glitchy" for moment, and when I opened the Properties dialog for the bod, the font was poorly rendered.
All the documentation that I looked at (like this, this and this) only have examples of it being used on a UserForm, or in Outlook.
There are many types of ActiveX controls, and not all of them can be used anywhere. As a rule of thumb in Excel, it's best to stick to the controls that are built-in.
Also, from another forum:
Q: It seems that I could not find and add Multipage control into worksheet.
How to add a Multipage control to Excel worksheet?
A: Unless you put it on a UserForm first, you can't display it on a Worksheet. The UserForm provides the user interface to VBA. The MultiPagecontrol is designed to work with this user interface, and not the Excel Worksheet. Is there a problem using the UserForm to display the MutliPage control? Source: Leith Ross
This evidence combined tells me, even if you can get it to work, you shouldn't. There's no predicting how it will behave.
In case you decide to use a MultiPage on a UserForm, note that in your example above, MultiPage1 is the name of the control; that's not referring to "page 1". The control as a whole has a Click event which is not specific to a page:
Private Sub MultiPage1_Click(ByVal Index As Long)
For the sake of completeness, I'll paste in a complete code sample but once again: this is not recommended for a worksheet-based control.
How to: Access a Page in a MultiPage Control
The following example accesses an individual page of a MultiPage in several ways:
Using the Pages collection with a numeric index.
Using the name of the individual page in the MultiPage.
Using the SelectedItem property.
To use this example, copy this sample code to the Script Editor of a form. Make sure that the form contains a MultiPage named MultiPage1 and a CommandButton named CommandButton1.
Sub CommandButton1_Click()
Dim PageName
Set MultiPage1 = Item.GetInspector.ModifiedFormPages("P.2").MultiPage1
For i = 0 To MultiPage1.Count - 1
'Use index (numeric or string)
MsgBox "MultiPage1.Pages(i).Caption = " & MultiPage1.Pages(i).Caption
MsgBox "MultiPage1.Pages.Item(i).Caption = " & _
MultiPage1.Pages.Item(i).Caption
'Use Page object without referring to Pages collection
If i = 0 Then
MsgBox "MultiPage1.Page1.Caption = " & MultiPage1.Page1.Caption
ElseIf i = 1 Then
MsgBox "MultiPage1.Page2.Caption = " & MultiPage1.Page2.Caption
End If
'Use SelectedItem Property
MultiPage1.Value = i
MsgBox "MultiPage1.SelectedItem.Caption = " & _
MultiPage1.SelectedItem.Caption
Next
End Sub
(Source)
Now I'm going to delete that buggy worksheet and reboot; I'd suggest you do the same!
Mikerickson and Jaafar Tribak on MrExcel.com figured it out:
https://www.mrexcel.com/forum/excel-questions/1054446-detect-button-press-event-excel-sheet-multipage-form-not-vba-userform-multipage-2.html
Big thanks to both of them!

VBA macro not triggering when target cell changes via form control option buttons

I literally just got my feet wet with VBA as this is my first macro. After many hours of searching, I couldn't seem to find an answer that had a solution that worked for me so here I am.
On Sheet3 I have 3 option buttons in a group box that are linked to cell "B18" on Sheet4 (Sheet4 is hidden to the user, a backstage if you will). When any of the three option buttons are selected, 'Sheet4!B18' gets updated as it should (e.g. 1, 2, or 3). What I want to happen is to have 'Sheet3!B17' changed based upon the value in 'Sheet4!B18', or effectively: IF('Sheet4!B18'=2,SET('Sheet3!B17'="Some Text Here:"),SET('Sheet3!B17'="0%")), but still allow user input in 'Sheet3!B17'. I have one VBA macro on Sheet4 with the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Worksheet.Range("B18") = 2 Then
Worksheets("Sheet3").Range("B17") = "Some Text Here:"
Else
Worksheets("Sheet3").Range("B17") = "0%"
End If
End Sub
If I manually update 'Sheet4!B18' then the macro gets triggered with the desired results. If I use any of the 3 option buttons on Sheet3, the macro does not get triggered even though the target cell is getting updated.
In my searching I couldn't seem to find anything concrete, but from what I could tell the "Worksheet_Change" function doesn't see changes to cells from form control as changes to the linked cell are considered a "recalculation" as if it were from a formula. I don't know how correct that is, but my searching led me to believe that I would need another macro assigned on the 3 buttons and/or group box that when either of those get selected/changed, it would somehow trigger the working macro on Sheet4.
I thought that perhaps I could create a new macro that I would assign to the group box or option buttons themselves so I tried that and could not get anything to work. I tried adding the above macro code to another sub, Sub mode() and assigning to only the group box, then only the buttons, but nothing happened in either case. I proceeded to try tweaking the code just in case the references were not correct, but saw no change regardless of how I specified the reference. I am not getting any error messages, but nothing gets triggered unless I manually change the value in 'Sheet4!B18'.
Is there a way to get the first macro that I have working on Sheet4 to trigger off of the option buttons changing the target cell value, something like forcing it to look only at that one specific cell for changes? Am I stuck making another macro for the buttons and/or group box to trigger the macro on Sheet4? Am I over-complicating this and there is some built in Excel sheets function(s) that I can use?
IF/THEN is a fine way to do it. VBA also supports ternary logic with the IIF function, like this:
Worksheets("Sheet3").Range("B17") = IIF(Worksheets("Sheet4").Range("B18") = 2, "Some Text Here:", "0%")
That may seem a little difficult to read, but it's a good concept to understand, since it's present in many languages, and usually with a more simplified implementation that makes it very useful and concise.
Also, I would suggest making a couple of other alterations that may make your code easier to write, read and maintain (especially as it becomes more complex).
First, alias the worksheets, something like this:
Dim this as Worksheet: Set this = Worksheets("Sheet3")
Dim that as Worksheet: Set that = Worksheets("Sheet4")
Now you would be able to rewrite your code like this:
If that.Range("B18") = 2 Then
this.Range("B17") = "Some Text Here:"
Else
this.Range("B17") = "0%"
End If
And the ternary approach would now be:
this.Range("B17") = IIF(that.Range("B18") = 2, "Some Text Here:", "0%")
And you can get as specific as you like with the aliases. For instance, you could realias the ranges, instead of just the worksheets, like this:
Dim this as range: Set this = Worksheets("Sheet3").Range("B17")
Dim that as range: Set that = Worksheets("Sheet4").Range("B18")
this = IIf(that = 2, "Some Text Here:", "0%")
Also, I find it easier to use the cells property than the range property, especially when you start having to do cell math. In that case, Range("B17") becomes Cells(17, 2).
You can also change the way the cells are referenced in the spreadsheet by typing Application.ReferenceStyle = xlR1C1 into the immediate window. That way you don't have to mentally convert between A2 style ranges to Cartesian style (2,1).
Sometimes you just have to go through your entire thought process and type everything out before you have an "ah-hah!" moment because that is exactly what I had happen. I said to myself, "Why can't I have just one macro that gets triggered by the option buttons that checks my linked cell then proceeds to update the cell I want?" Well, eventually I was able to find the right code and this is what worked perfectly:
Sub mode() ' mode is the name of this macro
If Worksheets("Sheet4").Range("B18") = 2 Then
Worksheets("Sheet3").Range("B17") = "Some Text Here:"
Else
Worksheets("Sheet3").Range("B17") = "0%"
End If
End Sub
As it turns out, I was overlooking the simple solution and the above macro is all I need once I assigned it to the 3 option buttons in my group box, but not the group box itself. Since users will not have access to the hidden Sheet4 and therefore 'Sheet4!B18' will never have manual user input, the macro I first had on Sheet4 could be removed safely. Due to the fact that the option buttons being chosen is the trigger for the assigned macro, it executes each time the option is changed and only when the option is changed. Perfect!
EDIT:
Thanks to Chris Strickland for some tips for better code! I went on to modify the above into what you see below for slightly better performance (using Cells() instead of Range()), to save the original value to another cell and restore it if option 1 or 3 were selected, used aliases, and finally the IIf operator.
Sub mode() ' mode is the name of this macro
Dim S3 As Worksheet: Set S3 = Worksheets("Sheet3")
Dim S4 As Worksheet: Set S4 = Worksheets("Sheet4")
If IsNumeric(Cells(17, 2)) = True Then
S3.Activate
S4.Cells(18, 3) = Cells(17, 2).Value
End If
S3.Cells(17, 2) = IIf(S4.Cells(18, 2) = 2, "Some Text Here:", S4.Cells(18, 3))
End Sub

How to lock clipboard or avoid using it in MS Excel?

I'm writing a program under Excel that generate a lot of spreadsheets by copying / pasting some data from one worksheet to another (example: using a "Layout" worksheet with some header / footer cells which will be copied/pasted to the generated worksheets).
My problem is that, some times (not every time), when running my "generation process", Excel generate this error (sorry this is an English translation from my french Excel error) :
Error 1004 : The 'Paste' method of the '_Worksheet' object has failed
So I'm assuming that there is a problem with the Clipboard (with other software on my computer which probably used the clipboard at the same time :/)
I firstly try to find a way to copy/paste my cells (and other stuff) without using the clipboard, with code like that :
ThisWorkbook.Sheets("Layout").Range("A1").Copy Destination:=ThisWorkbook.Sheets("Test").Range("A1")
or that
ThisWorkbook.Sheets("Test").Range("A1") = ThisWorkbook.Sheets("Layout").Range("A1")
But it seems that we can only copy text or formula, not all the stuff (border, color,...) and also not Chart object (I have ones)!
So I try to find a way to lock/unlock the clipboard during the copy/paste.
I found this code to do that:
Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Declare Function CloseClipboard Lib "user32" () As Long
Declare Function EmptyClipboard Lib "user32" () As Long
Public Sub Lockk()
If OpenClipboard(0) = 0 Then
MsgBox "cannot open clipboard."
ElseIf EmptyClipboard() = 0 Then
MsgBox "cannot clear clipboard."
End If
End Sub
Public Sub Unlockk()
CloseClipboard
End Sub
It seems working when copying cells: I can lock the clipboard under excel, go to another software (notepad for example), and can't copy paste some data into this software; go back to excel and I can copy/paste data (manually or with a macro).
But:
It seems that pasting a cell will unlock the clipboard (I can lock, go to notepad, notepad has not access to the clipboard, go back to excel, copy/paste a cell, go back to notepad, and then the notepad can access to the clipboard; and I have not unlock explicitly the clipboard). That is not really a problem for me.
After locking the clipboard, we can't copy/past a Chart object (manually or with a macro). With a macro, I get exactly the same error as before).
So, is someone as an idea about how to lock/unlock the clipboard to copy chart object? Or to copy them without using the clipboard?
Edit:
The code used to copy/paste the graph object:
Utils_Clipboard.Lockk
ThisWorkbook.Sheets("Layout").ChartObjects("CHART_TEMPLATE").Copy
DoEvents
worksheet_p.Paste Destination:=where_p
Utils_Clipboard.Unlockk
where worksheet_p is a Worksheet object, adn where_p is a range.
Note that without the first and last lines (Lockk the clipboard), it's working fine (except some time).
Ok I've found a solution (maybe not the best one?)
I can use my Utils_Clipboard.Lockk and Utils_Clipboard.Unlockk to ensure that the clipboard will not be used by another software when duplicating (copy/paste) cell, merged cells,...
But it seems that, when the clipboard is locked, we can't copy/paste chart object (manualy by pressing ctrl+c and ctrl+v keys; or automatically in vba with the metod Copy and Past of objects).
My solution for chart object is to use the functions Duplicate (http://msdn.microsoft.com/en-us/library/office/ff840956.aspx) and Move (http://msdn.microsoft.com/en-us/library/office/ff840583.aspx) like this (where worksheet_p is the Worksheet where I want to put the chartobject) :
Utils_Clipboard.Lockk
Dim newchart_l As Shape
Set newchart_l = ThisWorkbook.Sheets("Layout").ChartObjects("CHART_TEMPLATE").Duplicate
newchart_l.Chart.Location xlLocationAsObject, worksheet_p.Name
Utils_Clipboard.Unlockk
Note that the duplicated object is a Shape not a ChartObject (which will make an error when executing the code if we type as a ChartObject).
So ok it's working (and I think there is no need to lock the clipboard here), but the chart object is not where I want (at the correct top/left coordinates on worksheet_p). To do that, I found that we must move the ChartArea (the parent of the duplicated object), but we can't manipulate the "newchart_l" directly (it seems that Excel don't update all its internal variables after the call of Duplicate, why???). So my solution is to firstly retrieve the new duplicate chart object, with this :
Dim ChartObject_m As Chart
Set ChartObject_m = worksheet_p.ChartObjects(worksheet_p.ChartObjects.Count).Chart
And then move the chartarea of that object (where 'where_p' is the range/cell where I want to put my charobject) :
ChartObject_m.ChartArea.Left = where_p.Left
ChartObject_m.ChartArea.Top = where_p.Top
Et voila!
Inspired by your solution I have a improved piece of code that I wanted to share. The improvement is, that it does not rely on assumptions like "The order of charts in the ChartObjects-Collection reflects the order of insertion":
Private Function copyGraph(source As ChartObject, pos As Range) As ChartObject
' Copies a given graph to the given position and returns the resulting
' ChartObject. The destination position is expected to be a cell in the desired
' target worksheet. The resulting ChartObject will be aligned to the Top/Left-
' Border of the given cell.
Dim dup As Object
Dim dstChart As Chart
' First just duplicate the graph. This operation leaves it on the original
' worksheet.
Set dup = source.Duplicate
' In case the duplication failed, ...
If (Not dup.HasChart) Then
' ... we remove the duplicated object and leave the copy function.
' This yields a Nothing-reference as return value to signal the error
' to the caller.
dup.Delete
set copyGraph = Nothing
Exit Function
End If
' Then we move the graph to the target worksheet passed as parameter. This
' gives us the new link to the moved chart.
'
' Excel displays some weired behavior when using the reference returned by ChartObject.Duplicate.
' Namely it yields sporadic 1004 runtime errors without further specification. However it seems,
' that activating the chart and calling location for ActiveChart gets around this problem.
'
' Therefor the original code:
' Set dstChart = dup.Chart.Location(xlLocationAsObject, pos.Parent.Name)
' has been replaced with the following
dup.Chart.parent.Activate
Set dstChart = ActiveChart.Location(xlLocationAsObject, pos.Parent.Name)
' As we relocated the chart as an object, the parent of the chart object is
' an instance of ChartObject. Hence we use it as the return value.
Set copyGraph = dstChart.parent
' Finally we move the graph to the requested position passed by the pos
' parameter.
With copyGraph
.Top = pos.Top
.Left = pos.Left
End With
End Function
I hope this helps other users looking for a simple solution on this issue.

Spell check an Excel sheet in VBA

I have scoured the Internet and I have found a handful of possible solutions to this issue, but I wanted to ask here as well.
The goal is to click a button, and spell check an entire sheet.
Here's some code
Sub spellCheck()
Sheet1.Cells.CheckSpelling
End Sub
Also, I found this:
Sub SpellCheck()
Dim Checkword As String, Result As Boolean
Checkword = Selection.Value
Result = Application.CheckSpelling(Checkword)
Selection.Offset(0, 1) = Result
End Sub
Any ideas? Neither is working for me. Thanks!
You can check the whole workbook by doing something like:
Sub SpellCheck()
For Each sh In Worksheets
Sheets(sh.Name).Cells.CheckSpelling
Next
End Sub
this will cycle through each sheet in the entire book and run a spellcheck on each one. What I can't figure out yet is how to make the spell checker actually move to the position of the spelling error. So, with the above you just get a list of spelling errors with no context with which to asses them.
I noticed I just had a typo in my code.
Below works:
Sub spellCheck()
Sheet1.Cells.CheckSpelling
End Sub
But, if anyone knows how to do the entire workbook, I'd be interested in that. Thanks.
This code will work on selected cells .This will highlight if any spell mistakes in a cell
Dim Myrange As Range
Selection.SpecialCells(xlVisible).Select
For Each Myrange In Selection
If Application.CheckSpelling(word:=Myrange.Value) = False Then
Myrange.Font.Color = vbRed
End If
Next
OK, so you can use the following command to invoke the toolbar's spellchecker which does move you to the position of the spelling error as long as you have screen updating enabled at the time.
Application.CommandBars("Tools").Controls("Spelling...").Execute
You can use this command embedded in the loop above to loop through the sheets in the workbook and invoke this command on each new sheet.
Cap
This uses a code snippet from a previous answer to restrict the area used for spellchecking to a specific region. Something I needed to do in a small project. This give the full functionallity of the spellchecker with errors shown in context. The rowNumber is calculated elsewhere.The selection range can be fully controlled elsewhere in your code to suit your particular need. Thought this might help others searching this posting.
With Sheets("Sheet1")
slic = CStr(rowNumber)
.Range("AL3:AN" & slic).Select
Application.CommandBars("Tools").Controls("Spelling...").Execute
End With
Thanks to previous posters this solved a problem form me. I am most grateful.