I am using this code to add an entry to excel right_click menu:
Private Sub Workbook_Open()
Application.ShortcutMenus(xlWorksheetCell).MenuItems.Add "Open document", "OpenDocument", , 1, , ""
End Sub
Sub OpenDocument()
‘vba code here
End Sub
I need to add an icon to this entry (using shell32.dl or any standalone image), as it is now blank.
Your requirement can be solved in more ways, but (at least, this is what I know how to handle) using a different approach (CommandBar):
To place a custom picture, please try the first version. It uses a picture from a specific path:
Sub AddItemContextMenuWithImage_1()
Const butName As String = "Open document"
Const calledProc As String = "testSubX"
deleteCellCustomControl butName
Dim cmBar As CommandBar, ctrlButt As CommandBarButton, picPicture As IPictureDisp
Set cmBar = Application.CommandBars("Cell")
Set ctrlButt = cmBar.Controls.Add(Type:=msoControlButton, Before:=1) 'create it to be the first menu option
Set picPicture = stdole.StdFunctions.LoadPicture(ThisWorkbook.Path & "\test.gif") 'accepted extensions: bmp, jpg, gif
With ctrlButt
.Picture = picPicture
.OnAction = calledProc
.Caption = butName
End With
End Sub
To check it, the demonstative Sub should look as:
Sub testSubX()
MsgBox "It works..."
End Sub
Of course, you may adapt the code to call your own/necessary Sub...
A second version uses/copies a picture already added on a specific sheet of ThisWorkbook:
Sub AddItemContextMenuWithImage_2()
Const butName As String = "Open document"
Const calledProc As String = "testSubX"
deleteCellCustomControl butName
Dim cmBar As CommandBar, ctrlButt As CommandBarButton
Set cmBar = Application.CommandBars("Cell")
Set ctrlButt = cmBar.Controls.Add(Type:=msoControlButton, Before:=1) 'create it to be the first menu option
ActiveSheet.Pictures("Picture 2").Copy 'need to have a "Picture 2" picture on the active sheet
'you can copy it as image of the newly added control button
With ctrlButt
.PasteFace 'paste the above copied picture
.OnAction = calledProc
.Caption = butName
End With
End Sub
The third version uses standard, already defined FaceIDs. There are so many, that it is very probable to find something suitable for your need, so this is the version I prefer:
Sub AddItemContextMenuWithImage_3()
'Here the list of FaceID controls with their images:
'https://bettersolutions.com/vba/ribbon/face-ids-2003.htm
Const butName As String = "Open document"
Const calledProc As String = "testSubX"
deleteCellCustomControl butName
Dim cmBar As CommandBar, ctrlButt As CommandBarButton
Set cmBar = Application.CommandBars("Cell")
Set ctrlButt = cmBar.Controls.Add(Type:=msoControlButton, Before:=1) 'create it to be the first menu option
With ctrlButt
.FaceId = 1661
.OnAction = calledProc
.Caption = butName
End With
End Sub
A lot of such FaceIDs can be found here. I also place the link as a comment inside the Sub, to remain there for people being interested in this approach...
All the above Subs firstly call the next Sub, to preliminarily delete the menu option, if it already exists:
Sub deleteCellCustomControl(strBut As String)
On Error Resume Next 'for the case of not existing button to be deleted...
Application.ShortcutMenus(xlWorksheetCell).MenuItems(strBut).Delete
On Error GoTo 0
End Sub
If there is only such a custom option in the context menu, or if you want deleting all of them (the custom once), you can simple reset the command Bar, using:
Private Sub ResetContextMenuBar()
Application.CommandBars("Cell").Reset
End Sub
Related
Header
I know how to add a submenu (control) in the commandBars("Cell"), and it's perfect! When I right-click on a cell in Excel, my submenu appears.
Question
But when I want to add a submenu in a commandBars("Chart"), the control is added and exists in the commandBars("Chart"), but it doesn't show up when I right click on the char object!!!!
Can you help me, I can not progress on this problem?
Code :
Private Sub SubAddSubmenuInChart()
Dim memObj_CdeBar As CommandBar
Dim memObj_CdeBarCtrl As CommandBarControl
Set memObj_CdeBar = ThisWorkbook.Application.CommandBars("Chart") 'or "Plot aera", etc ...
Set memObj_CdeBarCtrl = memObj_CdeBar.Controls.Add(Type:=msoControlButton, Before:=1, Temporary:=True)
With memObj_CdeBarCtrl
'.OnAction = "MyMacroX"
.Enabled = True
.Visible = True
.Priority = 1
.Caption = "BBB_Test"
.Tag = "Tag_001"
End With
End Sub
I am using excel/vba to create a tree structure. Nodes have checkbox in front of them. I am using a recursive function to traverse the nodes and copy the text of selected/checked nodes. I tried to put it in variable, excel rows, arrays but I am only getting last selected node's text.
Below is the recursive function.
I am passing the root node to it. How to copy selected items?
Public Sub TraverseTree(objNode As Node)
Dim objSiblingNode As Node
Set objSiblingNode = objNode
Do
If objSiblingNode.Checked Then
Debug.Print objSiblingNode.Text
End If
If Not objSiblingNode.Child Is Nothing Then
Call TraverseTree(objSiblingNode.Child)
End If
Set objSiblingNode = objSiblingNode.Next
Loop While Not objSiblingNode Is Nothing
End Sub
Tree nodes defined in VBA code
'Parent Nodes
TreeView1.Nodes.Add Key:="P1", Text:="Phone is down/blank screen"
TreeView1.Nodes.Add Key:="P2", Text:="phone is showing Configuring IP"
TreeView1.Nodes.Add Key:="P3", Text:="Phone stuck at registering"
'Child for P1
TreeView1.Nodes.Add "P1", tvwChild, "ch1", "Is the phone getting power?"
'Child for ch1
TreeView1.Nodes.Add "ch1", tvwChild, "ch1.1", "Yes"
TreeView1.Nodes.Add "ch1", tvwChild, "ch1.2", "No"
'Child for ch1.1
TreeView1.Nodes.Add "ch1.1", tvwChild, "ch1.1.1", "Do you see any buttons lit up, what are they?"
So, try the next scenario, please:
Declare a Private Variable on top of form module (in the declarations area):
Private strWiew As String
Your TraverseTree Sub will become:
Private Sub TraverseTree(objNode As Node)
Do
If objNode.Checked Then
If strWiew = "" Then
strWiew = objNode.Text
Else
strWiew = strWiew & vbCrLf & vbTab & objNode.Text
End If
End If
If Not objNode.Child Is Nothing Then
Call TraverseTree(objNode.Child)
End If
Set objNode = objNode.Next
Loop While Not objNode Is Nothing
End Sub
You need the function to put the resulted string in clipboard:
Dim clipboard As New MSForms.DataObject
clipboard.SetText strNode
clipboard.PutInClipboard
End Sub
Your Copy button Click event will become:
Private Sub CommandButton1_Click()
Dim objNode As Node
Set objNode = TreeView1.Nodes("P1")
strWiew = ""
TraverseTree objNode
CopyToClipboard strWiew
End Sub
Run your application. Check the tree node you want their text to be returned and press Copy button. Open Notepad, Wordpad, Word (any text editor) and try Ctrl + V...
I am new to MS Publisher 2010, and I am trying to add a "dynamic" reference to a specific page. Ideally, the visualized text should be something like:
...see the example on page XXX
I would like to make the XXX part visualize the page number of the page I am referring to. I saw that you can place bookmarks in the document, and create hyperlinks to those bookmarks, but so far I could not manage to visualize the page number tied to a bookmark.
To make another example, I would like the equivalent of this Latex expression:
...see the example on page~\pageref{reference-to-XXX}
Would it be possible to obtain this effect in Publisher 2010, maybe using a VB script? Thank you for your help!
http://answers.microsoft.com/en-us/office/forum/office_2007-office_other/how-do-i-hyperlink-specific-text-within-the-same/598cfd98-6217-4eac-9ac9-969477c46401?auth=1
"This is fairly easy with Pub 2007. Just Insert > bookmark and drag that icon to where you want the link to go. Then select the text >insert hyperlink > place in this document and choose the bookmark that you just created. The only time I have had problems is if the page is not long enough below the bookmark...and there are workarounds.
http://office.microsoft.com/en-us/publisher-help/create-a-hyperlink-HP010203490.aspx
DavidF"
Let me know if this helps or if you for some reason need to do it in VBA
Edit:
It is fairly easy to write a macro to refresh links to pages, but links to bookmarks seem to be poorly supported by the object model, unless I've overlooked something. My solution consists of two parts.
First of all, links that should be refreshed are recognised by their display text starting with "page " (LIKE "page *"). The refresh macro simply recognizes those links and changes their display text to page X. However, this doesn't work for links to bookmarks, which in the object model seem to behave like links to pages, except the pageID they refer to does not exist. I spent quite a while trying to figure out what the relationship might be between this non-existent hyperlink and the bookmark, but to no avail. Instead I've created a workaround in which you manually link the hyperlink and the bookmark with a tag object (creating a tag for the bookmark with the value of the non-existent page ID of the hyperlink).
Instructions for normal links to pages
Create a hyperlink to a page. The text of it must begin with ”page ”
(otherwise RefreshReferenceLinks must be edited)
Run C_RefreshReferenceLinks to refresh to check that it worked
Instructions for links to bookmarks (tagging workaround)
Create a bookmark (Insert -> Bookmark)
Create a hyperlink to the Bookmark
Select the hyperlink and run A_GetPageIdOfHyperlink
Select the bookmark and run B_TagBookmarkWithPageId
Run C_RefreshReferenceLinks to refresh to check that it worked
You can download my example project containing example content, instructions, and the macros below here: http://www.filedropper.com/showdownload.php/pageandbookmarklinks (it will probably give you a security warning because it contains macros)
Full source
Public Const tagName = "BookmarkPageId"
Sub A_GetPageIdOfHyperlink()
Dim oHyperlink As Hyperlink
Set oHyperlink = ActiveDocument.Selection.TextRange.Hyperlinks(1)
CopyText oHyperlink.pageId
MsgBox oHyperlink.pageId & " copied to clipboard as text"
End Sub
Sub B_TagBookmarkWithPageId()
Dim oShape As Shape
Set oShape = ActiveDocument.Selection.ShapeRange(1)
If IsBookmark(oShape) Then
If TagExists(oShape.Tags, tagName) Then
oShape.Tags(tagName).Delete
End If
Dim txt As String
txt = Trim(GetClipBoardText())
Debug.Print "Ssdsd:" & txt
Dim newTag As Tag
Set newTag = oShape.Tags.Add(tagName, txt)
MsgBox "Tagged as " & tagName & " = '" & txt & "'"
Else
MsgBox "Not a bookmark"
End If
End Sub
Sub C_RefreshReferenceLinks()
Dim oPage As Page
Dim oShape As Shape
For Each oPage In ActiveDocument.Pages
For Each oShape In oPage.Shapes
RefreshInShape oShape
Next oShape
Next oPage
For Each oPage In ActiveDocument.MasterPages
For Each oShape In oPage.Shapes
RefreshInShape oShape
Next oShape
Next oPage
For Each oShape In ActiveDocument.ScratchArea.Shapes
RefreshInShape oShape
Next oShape
End Sub
Function RefreshInShape(oShape As Shape)
Dim cHyperlinks As Hyperlinks
Dim oHyperlink As Hyperlink
If oShape.HasTextFrame = False Then Exit Function
Set cHyperlinks = oShape.TextFrame.TextRange.Hyperlinks
For i = 1 To cHyperlinks.Count
Set oHyperlink = cHyperlinks(i)
If oHyperlink.TargetType = pbHlinkTargetTypePageID Then
If oHyperlink.TextToDisplay Like "page *" Then
oHyperlink.TextToDisplay = "page " & GetPageNumberByPageId(oHyperlink.pageId)
End If
End If
Next i
End Function
Function GetPageNumberByPageId(pageId)
Dim oPage As Page
Dim oShape As Shape
Dim oTag As Tag
For Each oPage In ActiveDocument.Pages
If CLng(oPage.pageId) = CLng(pageId) Then
GetPageNumberByPageId = oPage.PageNumber
Exit Function
End If
Next oPage
For Each oPage In ActiveDocument.Pages
For Each oShape In oPage.Shapes
If TagExists(oShape.Tags, tagName) Then
Set oTag = oShape.Tags(tagName)
If CStr(oTag.Value) = CStr(pageId) Then
GetPageNumberByPageId = oPage.PageNumber
Exit Function
End If
End If
Next oShape
Next oPage
GetPageNumberByPageId = "[ERROR]"
End Function
Function IsBookmark(oShape As Shape)
IsBookmark = False
If oShape.Type = pbWebHTMLFragment And oShape.AutoShapeType = msoShapeMixed Then
IsBookmark = True
End If
End Function
Function TagExists(collection As Tags, itemName As String) As Boolean
TagExists = False
Dim oTag As Tag
For Each oTag In collection
If oTag.Name = itemName Then
TagExists = True
Exit For
End If
Next oTag
End Function
Function GetParentOfType(obj As Object, sTypeName As String)
Do Until TypeName(GetParentOfType) = "Page"
Set GetParentOfType = obj.Parent
Loop
End Function
Sub CopyText(Text As String)
'VBA Macro using late binding to copy text to clipboard.
'By Justin Kay, 8/15/2014
'Thanks to http://akihitoyamashiro.com/en/VBA/LateBindingDataObject.htm
Set MSForms_DataObject = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
MSForms_DataObject.SetText Text
MSForms_DataObject.PutInClipboard
Set MSForms_DataObject = Nothing
End Sub
Function GetClipBoardText() As String
Set DataObj = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
On Error GoTo Whoa
'~~> Get data from the clipboard.
DataObj.GetFromClipboard
'~~> Get clipboard contents
GetClipBoardText = DataObj.GetText(1)
Exit Function
Whoa:
GetClipBoardText = ""
End Function
I'm trying to make my own drill-through action for PivotTable by means of VBA.
The action will be called from context menu of a PivotTable from Additional Actions.
I want to put my button under Additional Actions control of PivotTable Context Menu command bar.
The point is that by default Additional Actions already contains (No Actions Defined) item.
So, I want to remove this (No Actions Defined) after adding my button, but nothing works.
I cannot even change any property of (No Actions Defined) control, like Caption, Visible, etc.
What might be the reason, and what is the workaround?
Here is my code so far (you can put it under Workbook_SheetBeforeRightClick, for example, and then test with any Pivot Table in that workbook):
Dim PCell As PivotCell
Dim PComBar As CommandBar
Dim PControl As CommandBarControl
Dim DControl As CommandBarControl
Dim BControl As CommandBarControl
Dim IsFromPivotTable As Boolean
IsFromPivotTable = False
On Error GoTo NotFromPivot
Set PCell = Target.PivotCell
IsFromPivotTable = True
NotFromPivot:
On Error GoTo 0
If IsFromPivotTable Then
Set PComBar = Application.CommandBars("PivotTable Context Menu")
Set PControl = PComBar.Controls("Additional Actions")
On Error Resume Next
With PControl
Call .Controls("My Drillthrough Action").Delete
.Enabled = True
End With
On Error GoTo 0
Set DControl = PControl.Controls.Add(Type:=msoControlButton, Temporary:=True, Before:=1)
With DControl
.Style = msoButtonIconAndCaption
.Caption = "My Drillthrough Action"
.FaceId = 786
End With
On Error Resume Next
Set BControl = PControl.Controls("(No Actions Defined)")
With BControl 'This does not work and throws error if do not suppress with On Error
.Enabled = True
.Visible = False
.Caption = "Hello there"
End With
On Error GoTo 0
End If
So, the last section With BControl ... End With does not work at all, and throws an error "Automation Error".
I can successfully edit Additional Actions itself, like enable it, but I would like to get rid of (No Actions Defined) control, or replace it with my own.
Note, that Call .Controls("(No Actions Defined)").Delete does not work either.
How can I do that?
I tried to google the problem, but no luck...
I suspect you can't add to that menu. You could, however, add to the context menu itself:
Sub test()
Dim PCell As PivotCell
Dim PComBar As CommandBar
Dim DControl As CommandBarControl
Dim target As Excel.Range
Set target = ActiveCell
On Error Resume Next
Set PCell = ActiveCell.PivotCell
On Error GoTo 0
If Not PCell Is Nothing Then
Set PComBar = Application.CommandBars("PivotTable Context Menu")
Set DControl = PComBar.Controls.Add(Type:=msoControlButton, Temporary:=True, Before:=1)
With DControl
.Style = msoButtonIconAndCaption
.Caption = "My Drillthrough Action"
.FaceId = 786
End With
End If
End Sub
I have a group box with option buttons in it and I need to find out which one of them is selected in VBA. I have been browsing MSDN for hours now and I can't find a solution.
There has to be a way to find the selected option button. Possibly find the group by name and for-each through each option button?
Here's what seems to be a working solution.
(Nod to KazJaw for Dim ... As OptionButton. this seems to be the key to get .GroupBox to work)
Function WhichOption(shpGroupBox As Shape) As OptionButton
Dim shp As OptionButton
Dim shpOptionGB As GroupBox
Dim gb As GroupBox
If shpGroupBox.FormControlType <> xlGroupBox Then Exit Function
Set gb = shpGroupBox.DrawingObject
For Each shp In shpGroupBox.Parent.OptionButtons
Set shpOptionGB = shp.GroupBox
If Not shpOptionGB Is Nothing Then
If shpOptionGB.Name = gb.Name Then
If shp.Value = 1 Then
Set WhichOption = shp
Exit Function
End If
End If
End If
Next
End Function
Use it like this
Sub test()
Dim shpOpt As OptionButton
Set shpOpt = WhichOption(Worksheets("Sheet1").Shapes("Group Box 1"))
Debug.Print shpOpt.Name
End Sub
If you really need to check OptionButton which are grouped (Grouped in the way we group any type of shape) you could go with this code:
Sub Grouped_into_UnitType()
Dim i!
'grouped into 'UnitType' Shape
For i = 1 To ActiveSheet.Shapes("UnitType").GroupItems.Count
With ActiveSheet.Shapes("UnitType").GroupItems(i).ControlFormat
If .Value = 1 Then
MsgBox "Chosen item: " & i
End If
End With
Next i
End Sub
Edit having in mind the following picture the code above will solve the problem if we have Option Buttons which are group in the way we group any Shapes placed in the sheet.
The code under the picture will find which option button is selected if they are located within GroupBox. Code check the name of the group in which OptionButton is located.
Important Note! the code below didn't work until I switched Excel off and run it again.
Sub Grouped_into_GroupBox_UnitType()
Dim OB As OptionButton
For Each OB In ActiveSheet.OptionButtons
'check if grouped into 'UnitType' Shape
If OB.GroupBox.Name = "UnitType" Then
If OB.Value = 1 Then
MsgBox "Chosen item: " & OB.Name & _
vbNewLine & _
"Alt text: " & OB.ShapeRange.AlternativeText
End If
End If
Next
End Sub
Lets say you have two standard option buttons:
To check if its "on" use:
Dim opt As Shape
Set opt = Worksheets("Sheet1").Shapes("Option Button 1")
If opt.ControlFormat.Value = xlOn Then
Debug.Print "option is ""on"" value of 1"
Else
Debug.Print "option is ""off"" value of -4146"
End If
To get its alternat text use:
Debug.Print "Alternate Text is: " & opt.AlternativeText
For a large amount of options the "FormControlType" property can be used:
Dim s as Shape
For Each s In Worksheets("Sheet1").Shapes
If s.FormControlType = xlOptionButton Then
If s.ControlFormat.Value = xlOn Then
Debug.Print "option is ""on"" value of 1"
Else
Debug.Print "option is ""off"" value of -4146"
End If
Debug.Print "Alternate Text is: " & s.AlternativeText
End If
Next
If you wanted a particular group:
Dim s As Shape, o
For Each s In Worksheets("Sheet1").Shapes
If s.FormControlType = xlOptionButton Then
Set o = s.OLEFormat.Object
If o.GroupBox.Name = "Group Box 3" Then
If s.ControlFormat.Value = xlOn Then
Debug.Print "Option is ""on"" value of 1"
Else
Debug.Print "Option is ""off"" value of -4146"
End If
Debug.Print "Alternate Text is: " & s.AlternativeText
Debug.Print "Group: " & o.GroupBox.Name
End If
Set o = Nothing
End If
Next