Handle HTMLElement events in VBA - vba

I use SHDocVw.InternetExplorer to show in powerpoint a local html file to the user. The file contains a form with a submit button and I would like to run my vba function when the button is clicked. I did the following to handle the onQuit-event of the InternetExplorer.
Class module "CIE"
Public WithEvents ie As SHDocVw.InternetExplorer
Private Sub ie_onQuit()
Debug.Print "onQuit was fired"
End Sub
Module code
Option Explicit
Public curCIE As CIE
Sub open_ie()
Dim CIEobj As CIE
Set CIEobj = New CIE
Dim ie As SHDocVw.InternetExplorer
Set ie = New SHDocVw.InternetExplorer
ie.Visible = True
ie.Navigate "C:\search.html"
Do While ie.Busy Or ie.readyState <> 4
DoEvents
Loop
Set CIEobj.ie = ie
Set curCIE = CIEobj
End Sub
I actually want to handle the onclick event of
curCIE.ie.Document.getElementsByTagName("button").Item(0)
but I do not know how to proceed.

You could add reference to MSHTML, then make your class module this way:
Public WithEvents ie As SHDocVw.InternetExplorer
Private WithEvents button As MSHTML.HTMLButtonElement
Public Sub LoadButton()
Set button = ie.document.getElementsByTagName("button").Item(0)
End Sub
Private Function button_onclick() As Boolean
'do what you want here
End Function
Private Sub ie_onQuit()
Debug.Print "onQuit was fired"
End Sub
And then, in the other module, add this statement after setting CIEobj.ie property:
CIEobj.LoadButton

Related

How to hide an ActiveX Command Button when printing a word document?

I have an ActiveX Command Button that when pressed opens a userform to allow data entry into the word document. This button needs to remain visible when working on the document but not visible when printing.
How can I hide/make invisible only when printing?
Unlike in Excel VBA where the properties include an option to 'PrintObject', word VBA does not have this functionality. The best I have been able to do is delete the button after being clicked but this is not really what I want.
'Needs to hide button only on printing, not delete it
UserForm2.Show
CommandButton1.Select
Selection.Delete
I assume you are having ActiveX Command Button in word and using user form entered data gets feed in corresponding fields and you are closing user form and then trying to print document and printed file should not have ActiveX Command Button in it
Paste the following code into CommandButton_Click event
Private Sub CommandButton1_Click()
With ActiveDocument
.Shapes(1).Visible = msoFalse
.PrintOut Background:=False
.Shapes(1).Visible = msoTrue
End With
End Sub
#ille P. - You should post a new question, perhaps with a link to this one.
Try the Shapes collection as well as inlineshape collection.
The following is suggested by Ibby on the Microsoft Word MVP VBA FAQ pages:
Private Sub CommandButton1_Click()
With ActiveDocument
.Shapes(1).Visible = msoFalse
.PrintOut Background:=False
.Shapes(1).Visible = msoTrue
End With
End Sub
So translating to the collection:
Dim oShape as Shape
For Each oShape in ActiveDocument.Shapes
oShape.Visible = False
Next oShape
That would, though hide all shapes, not just your buttons.
You could add bookmarks to your buttons and use them as a filtering Range.
After investigating what happens with the CommandButtons, I detected that in the document they are included (if it has not been edited to be a Shape) in the InLineShape collection by being encapsulated in an InLineShape object.
It would be great if we could directly typecast from CommandButton to InShapeLine but I think Microsoft doesn't allow it, too bad.
The idea is to create two class modules:
One will be an event manager to capture the 'before printing' event and another.
The other will be an encapsulation of an InLineShape object that will have the methods to make the object visible, taking advantage of the Brightness property of the PictureFormat object.
CLASS clsButton
Option Explicit
Private M_ishpButton As InlineShape
Public Property Get button() As InlineShape
Set button = M_ishpButton
End Property
Public Property Set button(oObj As InlineShape)
Set M_ishpButton = oObj
End Property
Public Property Get Visible() As Boolean
Visible = Not bIsHidden
End Property
Public Property Let Visible(bValue As Boolean)
Dim oPictureFormat As PictureFormat
Set oPictureFormat = M_ishpButton.PictureFormat
If bValue Then
Call show
Else
Call hide
End If
End Property
Private Function bIsHidden() As Boolean
Dim oPictureFormat As PictureFormat
Set oPictureFormat = M_ishpButton.PictureFormat
If oPictureFormat.Brightness = 1 Then bIsHidden = True: Exit Function
bIsHidden = False
End Function
Private Sub hide()
Dim oPictureFormat As PictureFormat
Set oPictureFormat = M_ishpButton.PictureFormat
oPictureFormat.Brightness = 1
End Sub
Private Sub show()
Dim oPictureFormat As PictureFormat
Set oPictureFormat = M_ishpButton.PictureFormat
With oPictureFormat
.Brightness = 0.5
.Contrast = 0.5
End With
End Sub
CLASS clsEvents
Option Explicit
Public WithEvents appWord As Word.Application
Public WithEvents docWord As Word.Document
Private m_button As New clsButton
Private Sub appWord_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
'If process is not cancel and button is not visible
With m_button
If Cancel = False And .Visible = True Then
.Visible = False
End If
End With
End Sub
Private Sub appWord_WindowDeactivate(ByVal Doc As Document, ByVal Wn As Window)
'If button is not visible then set to true
With m_button
If .Visible = False Then
.Visible = True
End If
End With
End Sub
Public Property Set button(oObj As clsButton)
Set m_button = oObj
End Property
CLASS ThisDocument
Now, in ThisDocument class should create objects and linking
Dim oEventsManager As New clsEvents
Dim oEditedButton As New clsButton
Const BUTTON_LINKS As String = "cmdUpdateLinks" 'For example
Dim oInShpDoc As Word.InlineShape, oOleDoc As Word.OLEFormat, oInShapesDoc As Word.InlineShapes
Public Sub Set_Manager_Events()
Set oEventsManager.appWord = Word.Application 'ThisDocument.Application
Set oEventsManager.docWord = ThisDocument
Set oInShpDoc = FNC_oGet_Button_Variable(BUTTON_LINKS)
If Not oInShpDoc Is Nothing Then
Set oEditedButton.button = oInShpDoc
Set oEventsManager.button = oEditedButton
End If
End Sub
'###### EVENTOS OF BUTTON
Private Sub cmdUpdateLinks_Click()
If oEventsManager.appWord Is Nothing Then Call Set_Manager_Events
Call UpdateLinks ' Is one example
End Sub
Public Function FNC_oGet_Button_Variable(sCodeName As String) As InlineShape
Dim oForm As InlineShape, oFormsInLine As InlineShapes, oOLEFormat As OLEFormat
Set oFormsInLine = ThisDocument.InlineShapes
If oFormsInLine .Count < 1 Then GoTo bye
i = 0
For Each oForm In oFormsInLine
With oForm
Set oOLEFormat = .OLEFormat
If Not oOLEFormat Is Nothing Then
If InStr(1, oOLEFormat.ClassType, "CommandButton") > 0 Then
If .OLEFormat.Object.Name = sCodeName Then
Set FNC_oGet_Button_Variable= oForm
Exit Function
End If
End If
End If
End With
Next
bye:
Set FNC_oGet_Button_Variable = Nothing
End Function
With this you will can hide button for printing.

VBA Input Value From Another UserFormB into TextBox From UserFormA

I have a userForm (mappingGuide) that allows user to pick a smartyTag from a list of more user-friendly names.
I have a second user-form (conditionalBuilder) that I would like to call this userForm upon double-clicking a text field so that a user can lookup which smartyTag to apply (in case they don't know).
So logic, is:
open conditionalBuilder
double-click Field text box
mappingGuide opens
pick a smartytag from listbox
fill smartytag value into field text-box in conditionalBuilder
unload mappingGuide
The issue I think I having with completing the requirement is that when I load the forms themselves I cannot find a way to set the text of the fieldName textbox of the loaded instance of conditionalBuilder (see last code block below). I've been searching around, but cannot figure it out.
Here is relevant code:
conditionalBuilder loads from Custom UI ribbon
Sub RunCode(ByVal Control As IRibbonControl)
Select Case Control.ID
Case Is = "mapper": LoadMappingGuide
Case Is = "conditional": LoadConditionalBuilder
End Select
End Sub
Sub LoadConditionalBuilder()
Dim conditionalForm As New conditionalBuilder
conditionalForm.Show False
End Sub
double-click event of fieldName then loads mappingGuide
Private Sub fieldName_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Me.hide
Dim pickField As New mappingGuide
pickField.Show False
End Sub
smartTag listbox click event then attempts to place selection into fieldName (or selection if form not loaded)
Private Sub smartTagList_Click()
If smartTagList.ListIndex > -1 And smartTagList.Selected(smartTagList.ListIndex) Then
Dim smartyTag As String
smartyTag = smartTagList.List(smartTagList.ListIndex, 2)
If isUserFormLoaded(conditionalBuilder.Name) Then
'*** ---> below is my issue how to reference instance of form
conditionalBuilder.fieldName.Text = smartyTag
conditionalBuilder.Show
Else
Selection.Range.Text = smartyTag
End If
End If
Unload Me
End Sub
If there is a better set-up that would be great to know too. I have the forms separate because there's a couple of levels a user can create tags with.
This is how I would do it, a bit of overkill but in case of multiple forms it will be beneficial.
Module 1:
Option Explicit
Sub test()
frmMaster.Show False
End Sub
Form 1 : frmMaster:
Option Explicit
'/ Declare with events
Dim WithEvents frmCh As frmChild
Private Sub TextBox1_DblClick(ByVal cancel As MSForms.ReturnBoolean)
handleDoubleClick
End Sub
Sub handleDoubleClick()
If frmCh Is Nothing Then
Set frmCh = New frmChild
End If
frmCh.Show False
End Sub
'/ Handle the event
Private Sub frmCh_cClicked(cancel As Boolean)
Me.TextBox1.Text = frmCh.bChecked
End Sub
Form 2: frmChild:
Option Explicit
Event cClicked(cancel As Boolean)
Private m_bbChecked As Boolean
Public Property Get bChecked() As Boolean
bChecked = m_bbChecked
End Property
Public Property Let bChecked(ByVal bNewValue As Boolean)
m_bbChecked = bNewValue
End Property
Private Sub CheckBox1_Click()
Me.bChecked = Me.CheckBox1.Value
'/ Raise an event when something happens.
'/ Caller will handle it.
RaiseEvent cClicked(False)
End Sub
You can do this with a presenter class which controls userform instances and pass values between them. I mocked up something similar to give you an idea.
Presenter. This is a class module which creates the userforms, controls their scope, and catches the event thrown by the
ConditionalBuilder. It makes it super easy to pass values between
userforms.
Private WithEvents CB As ConditionalBuilder
Private MG As MappingGuide
Public Sub ShowCB()
Set CB = New ConditionalBuilder
CB.Show vbModal
End Sub
Private Sub CB_ShowMappingGuide()
Set MG = New MappingGuide
MG.Show vbModal
CB.UpdateTB1 Value:=MG.SmartTag
End Sub
ConditionalBuilder.
This has a simple function to update your textbox and also an event which raises actions in the presenter.
Public Event ShowMappingGuide()
Public Function UpdateTB1(Value As String)
TextBox1.Value = Value
End Function
Private Sub TextBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
RaiseEvent ShowMappingGuide
End Sub
MappingGuide.
The Type and Property could be overkill since we just want one value from the mapping guide but it's still good practice.
Private Type TView
Tag As String
End Type
Private this As TView
Public Property Get SmartTag() As String
SmartTag = this.Tag
End Property
Private Sub UserForm_Initialize()
Tags.List = Array("a", "b", "c")
End Sub
Private Sub Tags_Click()
this.Tag = Tags.List(Tags.ListIndex, 0)
Me.Hide
End Sub
I have one final Standard Module which creates the Presenter. This is what you'd hook up to your ribbon.
Public Sub ShowProject()
With New Presenter
.ShowCB
End With
End Sub
Step 1 (double click text field)
Step 2 (selecting "b")
Step 3 (result)
I actually solved it by placing the below block inside the IF where I check for the form being loaded and I will leave open for better answers, if there are any.
Dim uForm As Object
For Each uForm In VBA.UserForms
If uForm.Name = conditionalBuilder.Name Then
uForm.fieldName.Text = smartyTag
uForm.Show
End If
Next

Find value stored in IE object in VBA

I have declared an object named IE in my VBA code.
Set IE = CreateObject("InternetExplorer.Application")
Sometimes user may close the browser linked to IE object. How can i write code to find if the browser is closed or open?
As shown in below image, software shows Internet Explorer when i place cursor on IE object during run time. Can this value be used to determine if browser is closed or open? If not, any other way?
Create a custom class to capture the Internet Explorer events using WithEvents. You'll need to set a reference to Microsoft Internet Controls.
Option Explicit
Private WithEvents IE As InternetExplorer
Private Sub IE_OnQuit()
End Sub
Private Sub IE_OnVisible(ByVal Visible As Boolean)
End Sub
Private Sub Class_Initialize()
Set IE = New InternetExplorer
End Sub
If the object is closed, then accessing some of it's members should give you an error.
Dim isOpen As Boolean ' False by default
On Error Resume Next
If IE.HWND > 0 Then isOpen = True
On Error Goto 0

VB6 - WebBrowser Detect if a link has been clicked

Hi I am new to Visual Basic 6,
My application has a section which shows an advertisement. When the ad is clicked, the button "Power" is activated.
I tried to detect click on my ad that is inside a with the id "anuncio1".
So far I've only managed to detect when you click in the WebBrowser zone but does not detect when I've clicked on a link.
Then I let my code:
Option Explicit
'Reference to HTML DOM
Dim WithEvents HTMLDOC As HTMLDocument
Private Const READYSTATE_COMPLETE As Long = 4
'Load the website directly to the ad hiding Scrollbars and focusing anchor #anuncio1
Private Sub Form_Load()
WebBrowser1.Navigate "www.traductoramixer.es#anuncio1"
Do While WebBrowser1.Busy: DoEvents: Loop
Do While WebBrowser1.ReadyState <> READYSTATE_COMPLETE: DoEvents: Loop
WebBrowser1.Document.parentWindow.scrollBy 25, 0
WebBrowser1.Document.body.Scroll = "no"
WebBrowser1.Document.body.Style.overflow = "hidden"
End Sub
'Deteck click in WebBrowser1 zone
Private Function HTMLDOC_onclick() As Boolean
Command1.Enabled = True
End Function
Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant)
If Not WebBrowser1.Document Is Nothing Then
Set HTMLDOC = WebBrowser1.Document
End If
End Sub
i suggest you:
1) create a Timer with Interval 100
2) and check WebBrowser1.LocationName string value frequently
if its value was not equal to the url your customer clicked on it, then be sure that your customer clicked on a wrong link

VBA IE automation, To trigger some action in VBA before whenever i navigate to other page in website

I need a VBA code which can do some action in VBA when the webpage frame is just about to navigate to other page.for example when i click on some link,button it navigates to other page i want to take screen shot of the page before frame navigates to other.i have done something like this but it is taking screen shot of the blank page and its only working for onetime as the page is navigated and object gets changed. please help me with this i have been searching for this since 2 weeks help me.
Sub pageLoad()
Set ie2 = GetIE("https://xyz.com")
Dim LinkFound As Boolean
Dim linkCollection
Dim IEfr0 As Object
i = 0
Dim Link As MSHTML.HTMLAnchorElement
'HTMLInputElement
Set wordapp = CreateObject("word.Application")
wordapp.Visible = True
Set wrdDoc = wordapp.Documents.Add
Set IEfr0 = ie2.document.frames(0).document
Set linkCollection = IEfr0.getElementsByTagName("a")
Do While ie2.Visible = True
For Each Link In linkCollection
If ie2.document.frames(2).document.readyState = "interactive" Then
sai1
End If
If IEfr0.readyState = 1 Then
sai1
End If
Next
Loop
End Sub
Sub sai1()
Application.SendKeys "{PRTSC}"
wordapp.Selection.Paste
Do While ie2.Busy
Loop
End Sub
Here's a possible solution. Only showing you how to create the object and specify the BeforeNavigate2 event. This requires you to reference Microsoft Internet Controls and create the IE object (this will not work with late binding). This code must be in an object module (worksheet or workbook) because you cannot use WithEvents in a standard module.
Option Explicit
Dim WithEvents ie As InternetExplorer
Sub Example()
Set ie = New InternetExplorer
ie.Visible = True
ie.Navigate "Your URL Here..."
Do Until ie.ReadyState = READYSTATE_COMPLETE: DoEvents: Loop
End Sub
Private Sub ie_BeforeNavigate2(ByVal pDisp As Object, URL As Variant, Flags As Variant, TargetFrameName As Variant, PostData As Variant, Headers As Variant, Cancel As Boolean)
'Place code to run before navigating here.
End Sub
An issue you may see with this is that for some websites, the BeforeNavigate2 event will actually fire multiple times due to additional calls for resources when loading.