Order of Events for the SheetFollowHyperlink Event - vba

I have a workbook that lists people's names and overall performance for the past few weeks. I was asked to make it so that when their names are clicked, the details for that person would show. The solution I came up with at the time was to point all of the hyperlinks to a sheet that reminded them to turn on their macros.
In the WorkSheet_Activate event, I redirected them to another sheet that populated with the details for the person they had selected. This works fine. If the user doesn't have their macros turned on, they get a friendly reminder, but if they do, they immediately get redirected. There's just one problem. Because the hyperlink takes them somewhere else first, it causes the infamous "screen flicker".
On researching, I found the FollowHyperlink Events (I think the workbook level event would be most suitable for my purposes, though). However, before I get started rebuilding it, I wanted to make sure that this would solve the "screen flicker".
On MSDN, it states that the Event occurs when the user clicks the hyperlink. I can't seem to find anywhere that directly states whether this Event is triggered before or after the user is directed to the other sheet, though. If it gets triggered right after, that wouldn't really help me, but if it gets triggered before, I could put an Application.ScreenUpdates = False in the event, and it would solve my problem.
TL;DR (Get to the point already):
Does the Workbook_SheetFollowHyperlink Event happen before or after the user is directed to where ever the hyperlink is pointed?

To answer your question, the event is triggered after the hyperlink is followed. You can demonstrate this using the code below:
Private Sub Workbook_SheetFollowHyperlink(ByVal Sh As Object, ByVal Target As Hyperlink)
Debug.Print "Workbook level: " & ActiveSheet.Name
End Sub
When the event is triggered, the ActiveSheet is the sheet directed to by the hyperlink.
I'm not sure of a way to solve your problem directly, even the Click() event won't be raised when you click a hyperlink. However, the Worksheet level hyperlink event handler will be called before the Workbook level handler and this may speed the process up enough to not see the flicker.
You can prove this if you leave the Workbook level event as is and add the following code to the Worksheet containing the hyperlinks:
Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
Debug.Print "Worksheet level: " & ActiveSheet.Name
Sleep 1000
Debug.Print "Leaving worksheet level event"
End Sub

After a few experiments (see below) I concluded that:
Allow the user to use the hyperlink columns when macros are disabled.
When macros are enabled, hide the current hyperlink column and show another column that gives the user a different "hyperlink" that takes them directly to where you want them to go.
The 2nd hyperlink can easily be "simulated" such that it picks up the other columns hyperlink. (See below)
I hope his helps
Interesting, here's a few things I tried
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' This does not fire if the user clicks directly on the hyperlink text
' it only fires if when click on the cell space that is not text
With ActiveCell
If Hyperlinks.Count Then
MsgBox "hi" & .Hyperlinks(1).Range
.Hyperlinks(1).Follow
End If
End With
End Sub
However you could make the text in the cells look like a hyperlink but actually just be blue underlined text. You could then use the Worksheet_SelectionChange to go to a related cell.
The question then become how to store the related cell.
You want to store it so that if row and column are inserted on the destination sheet, the reference will adjust. (eg NOT in comments, or the description of named ranges etc..)
Depending on how much data you have there's a variety of ways you could choose from.
I think I would favour this:
Having a hidden column next to the cell on display that has a hyperlink. The cell on display has a formula that is set to pick up the value from the hidden column (I quite like the sound of this as you have the hyperlink column already - so just modify the above code to get the hyperlink from the column next to the clicked cell using offset perhaps)
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' This does not fire if the user clicks directly on the hyperlink text
With ActiveCell.offset(0,1)
If Hyperlinks.Count Then
.Hyperlinks(1).Follow
End If
End With
End Sub
You could mess around with named ranges, but it will be a pain.
I've just realised that what I tried won't help much as you need the hyperlink to work when macros have not been enabled!
So to get the above to work you could change the columns displayed when the user enables macros. ie the hyperlink column is shown when macros are disabled (and the column to the left of it is not).
When macros are enabled hide the hyperlink column and show the one to the left of it that will cause the SelectionChange event to run.
(You need to beware how other hyperlinks are used as any cell with a hyperlink next to it will respond to the event. You may need to use intersection to check the cell clicked is in a namedrange that contains "all the cells that need to respond to a user clicking them in the manner".
All the above sounds a bit mad, but it would appear the event model does not facilitate stopping the screen flickering.
I hope there is a better way of doing what you want, but for what it's worth, the above might help.
Harvey

Related

Get value from command button VBA

I have created A userform with few command buttons.
I can't seem to figure out how do I get the information from them.
I want to open this userform from another one and then I want the user to choose an option from one of the buttons which will change a specific cell in the table itself
the userform I created
I did not write anything on this userform therefor there is no code from it to show only the design.
how do get the information from the buttons to be written in A specific cell on a specific worksheet?
double click on one of the buttons, in the code menu a new sub should appear. this looks something like:
Sub CommandButton1_onClick()
End sub
Alongside this event method, it also has a few properties. The one that is usefull here is the CommandButton1.Value, this represents the state of the button (either true or false iirc).
So build for each button (I strongly advice giving them custom names to prevent getting lost in the trouble) as sub like this:
Sub CommandButton1_onClick()
if CommandButton1.Value then
ThisWorkBook.WorkSheets("WorksheetName").Range("YourRange").Value = "Some value"
else
ThisWorkBook.WorkSheets("WorksheetName").Range("YourRange").Value = ""
end if
End sub

Excel Form pops automatically when sheet opens

I have a specific worksheet with 2 sheets(Sheet1 & Sheet2). For Sheet2 I have implemented a form for the table (Using the basic Excel Form from the top bar).
My problem is that I have to make the form appear automatically every time I open Sheet1 (even if the data from the form will be completed in Sheet2).
Is this possible? Or how can I do it? (I can also use VBA)
To show the DataForm associated with a Worksheet, you use the command Worksheet.ShowDataForm (MSDN Article)
To show the DataForm for Sheet1 whenever you go to Sheet2, you can use the Worksheet_Activate event in Sheet2, like so:
Option Explicit
Private Sub Worksheet_Activate()
Sheet1.ShowDataForm
End Sub
A quick way to figure things like this out is use the "Record Macro" button, carry out the action you want, and then hit "Stop Recording" and look at the macro

ComboBox inputbox causes reselection of range

Currently I'm working on a userform prompting an inputbox for a range whenever the combobox dropdown button is clicked.
The problem is that whenever the range is selected (selecting a cell and then clicking ok), the userform is unselected (greys out), shows an empty dropdown list and forces me to reselect a range after I click anywhere on the workbook.
Is there any way to prevent a re selection of a range when clicking the dropdown button?
Code Below:
Private Sub ComboBox1_DropButtonClick()
Dim InputCell As Range
Set InputCell = Application.InputBox("Select Lookup Cell", "Obtain Object Range", Type:=8)
ComboBox1.Text = InputCell.Address(0, 0, external:=True)
End Sub
When I've used the RefEdit object in the past, I used the real thing (which I know has it's issues) and just used the Change event.
Perhaps you could just use the Enter event (you just have to ignore it the first time, if's it the first object that gets focus when initialized)
Resources:
Using RefEdit Controls in Excel
Dialogs - Jon Peltier
RefEdits must be placed directly on the UserForm itself. If you put a
RefEdit in a frame or on a multipage, strange things will happen,
including bizarre Excel crashes.
RefEdits must not be used on modeless forms. RefEdits on modeless
forms will result in bizarre Excel crashes.
RefEdit event procedures should be avoided. RefEdit events do not
behave reliably, and they may result in VBA errors which are difficult
to debug.
References to RefEdits must be removed. When a UserForm is added to a
VB project, Excel adds a reference to the Microsoft Forms 2.0 Object
Library. This reference is required for proper operation of the
UserForms in your project. To see what references your project has,
select the project in the Project Explorer, then select References
from the Tools menu.
Alternative to Excel’s Flaky RefEdit Control - Jon Peltier
The new approach uses a TextBox in the dialog instead of the RefEdit.
The TextBox does not interact directly with a range as does the RefEdit. Instead, when this drop button is clicked, the dialog is temporarily hidden, and an InputBox appears to solicit the user’s input.
"It may be tempting to use type 8 to indicate a range object, but there
is an obscure glitch that causes it to fail when the worksheet
contains conditional formatting conditions that use formulas in their
definitions. Fortunately using Type 0 to specify a formula works just
fine."
Cannot use keyboard shortcuts to select ranges in RefEdit control in Excel
From this source: Ozgrid
Though I'll be using custom text boxes, this could also work if anyone wants to use the combo boxes.
Private Sub ComboBox1_DropButtonClick()
Static Abort As Boolean
If Abort Then Exit Sub
Abort = False
Dim InputCell As Range
Set InputCell = Application.InputBox("Select Lookup Cell", "Obtain Object Range", Type:=8)
ComboBox1.Text = InputCell.Address(0, 0, external:=True)
Abort = True
End Sub

Check if Data was entered by the User or by a macro [VBA]

In my VBA-Project I have different Buttons (Ribbon Bar with Custom UI Editor) that start Subs, which enter data into the Cells. I want to prevent the users from entering data on their own to the cells as this might destroy the routines. Is there a way to validate whether the data has been entered manually or automatically? I thought about a control sheet where I would put a variable to 1 if I am in a function and check for this variable in the worksheet_change sub. Anyhow I think this might be a risky way as a Sub can always crash and then the value is still at 1 and no values can be entered anymore.
I suggest you simply lock the sheet from user input with the Protect function.
You have to use the UserInterfaceOnly property of this function to achieve what you're trying to do.
Sheets(“sheetname”).Protect Password:="Secret", UserInterFaceOnly:=True
This will protect your sheet from user input and let VBA change values in the sheet.
EDIT - Disable alerts
You asked in the comments if it's possible to disable alerts when the user select these cells. The following code should do the trick.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Cancel = True
End Sub

Modeless MsgBox, Error trapping, .Find

I have a subroutine that searches for an occurrence of a string in another workbook. I'm trying to get an error message to pop up if the string can't be found (it's most likely due to spelling mistakes), as vbModeless, and allows to user to click on the cell in the searched sheet with the correct value. Then I'd like to resume the search with the new value.
I'm at the moment stuck on making my simple MsgBox to be modeless.
Can anyone help? So far I have (simplified):
With ...
On Error GoTo UserSelect
celladdress = .Range("a1:bb100").Find("searchstring").Address
And my error label:
UserSelect:
MsgBox("Select the cell with the correct spelling") vbModeless
newstring = ActiveCell.Value
searchstring = newstring
Resume
I think it's the Modeless MsgBox giving me grief.
I don't believe that you can use vbModeless with msgbox. That is for use with the Show method of a user form.
What you probably need to do is create a user form that has a refedit control and a button on it. They can then pick a cell with the refedit control. When the user clicks on the button set a public variable on the form with the cell reference the selected.
Then you you need to use ".Show vbModal" on the user form and read off the cell they selected from the form public variable.
Edit:
Actually, you shouldn't need the public variable as the refedit control should be a public property of the form anyway.
I'm not 100% sure on the requirements here. Given a search string of dgo and a worksheet with cells containing bird, cat and dog. Do you want the user to:
(a) edit the cell containing dog and change it to say dgo instead
This would use the modal form and RefEdit control outlined by andynormancx. Like a MsgBox, the modal form pauses the macro until the form is closed
(b) allow the user to click on the cell containg dog and then re-run the search with dog as the search term
This is more complicated. I think that you would need to look at events here. This is fine if your subroutine is pretty much standalone but if it is part of a larger program then this could require substantial rewriting