VBA Programming in Excel - vba

I am new to programming in Excel. I have done very little Visual Basic. What I would like to do is check a column on one sheet in Excel and compare all the values to a column in a different sheet in Excel. Now the problem is, is it possible that when i click on one of the cells it is "linked" to the other and takes me to the matching cell. I would like to have this implemented into the spread sheet and not be a "macro". If anyone can help it would be much appreciated.

"macro" and "implementation in spread sheet" is nearly the same. the macro is, depending on how you do it, stored in the spreadsheet-file (.xls)
you can get the content of a cell by reading
Range("A1").Value // Any cell-reference is valid here.
If you want to read an entire column, you need to use some kind of loop.
the linking you're talking about could be done with the event Worksheet.SelectionChange. e.g. following skeleton:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
you may now fill what should happen when the selection has changed. With Target.Column and Target.Row you may read the row and do the appropriate tests.
You can switch the View on a special Sheet using the Worksheet.Activate-Method which brings on top the worksheet you call the method on.
hope this clarifies a bit... if you need details, i will do some research...
regards

Related

VBA Excel - How to know if a specific cell is affected by any macro?

I have an excel file with hundreds of macros, where which macro has extensive code.
I need to change the layout of the cells and that includes moving some cells to another location.
My only problem is that after doing that i need to change the macros that interacts with that cell. Interacts as his value/formula was changed or his value is used in another operation
I can't search in the code for range("C2") for example because the cell can be affected in diferent forms like:
Range("C2")
Cells(2, 3)
Range("B1:E5")
Range(Cells(1, 1), Cells(10, 10))
Offset
Is there any whey that i can discover which macros are changing a specific cell?
Are you looking for a way to track a specific cell, or for a way to track all cells affected by VBA code? Also, "affected" as in "value was changed" or "formula was changed", or "cell was merged with another", "range was unmerged", or "borders were changed", or "backcolor was changed"? Is adding conditional formatting "affecting" a cell? Data validation?
And then, there are more ways a cell can be "affected", too. Without tracking the code as it's running, it could be hard to tell whether this myRange variable is affecting the cell you're looking for.. especially if methods like Range.Offset and Range.Resize are used.
Then ranges can be named, so Range("Foo") might be referring to a cell you're interested in, but you can't know that without verifying whether Names("Foo").RefersToRange includes that cell.
Short of carefully reviewing the code, I'm afraid you can't.
If no macro is highlighting any cell in bright yellow, you could always make a copy of the file and then handle Workbook_SheetChange in ThisWorkbook:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Target.Interior.Color = vbYellow
End Sub
You can easily add conditional logic here to only recolor modified cells from a specific sheet, or from a specific column or row.
Now remove or comment-out any Application.EnableEvents toggling everywhere in the code, and run your macros - the cells it affected (assuming a change in value is what we're after) should all be bright yellow.
If you need to know what code caused this, you can place a breakpoint there, and inspect the call stack:

Deciphering an Excel macro; Range.Select, then Range.Activate, then Selection.ClearContents?

This is the code I have in a [very involved] spreadsheet someone made at work:
Sub ClearSheet()
'
' Macro5 Macro
'
'
Range("E9,E2:F7,C14:I39,Q41:Q55,N14:N39,N41:N55").Select
Range("Q14").Activate
Range("E9,E2:F7,C14:I39,C41:I55,Q41:Q55,N14:N39,N41:N55,L41:L55").Select
Range("Q41").Activate
Selection.ClearContents
I have never so much as glanced at an excel macro before, so I had to look some things up. I get that the first range is selected and then Q14 becomes the active cell. Then that is done again, with some overlapping sections, and Q41 is made into the active cell. All to have the selections just be cleared out. I'm sure this is a simple question but I don't understand what the point is of the .Activates, or why someone would separate the sections that need to be cleared into two separate segments? From my very limited understanding, I thought Activate was something like focus, where that is now that cell that has focus for ease of use on the users side. But what good is that if the focus changes from the first cell to the second cell in a millisecond?
All I know is that I need these cells:
E9,E2:F7,C14:I39,N14:N39,C41:I55,L41:L55,N41:N55,Q41:Q55
to clear out when this code is run, and if this code is doing something in addition to that, what is it?
Is this just poorly written or am I too ignorant to understand? ~the novel~
Use
Range("E9,E2:F7,C14:I39,N14:N39,C41:I55,L41:L55,N41:N55,Q41:Q55").ClearContents
Better still specify the workbook and worksheet to do this in e.g.
ThisWorkbook.Worksheets("Sheet1").Range("E9,E2:F7,C14:I39,N14:N39,C41:I55,L41:L55,N41:N55,Q41:Q55").ClearContents
Using sheet 1 as an example. You want to be sure to be in the right sheet before clearing stuff out. If you don't specify, and leave as just range, then the currently Active sheet is used.
In the code you talked about the each selection was shifting focus from the prior making the prior selections redundant.
Using Select, in particular, is not generally a good thing, it means 'touching' the sheet which incurs potentially unnecessary performance overhead.
As mentioned in comments, and indicated by ' Macro5 Macro, this is, at least in part, likely all, macro generated code. Macro meaning "many". Many instructions in this case. The macro recorder is verbose to say the least. It records everything your are doing including scrolling, mistakes in range selections etc. It is a good learning tool, and can often give useful insights into some objects and methods. The valuable skill is learning which elements to keep and how to turn this verbose code into structured programming.
The way you interpret Select and Activate is correct, one is for the actual selection and the other is somewhat to focus.
Select as the method name suggest selects the object. This method is not limited to Range Objects alone but is shared by most of the objects in Excel. Some of the examples:
Range("A1").Select '/* selecting a Range Object */
Worksheets("Sheet1").Select '/* selecting a Sheet Object */
Activate on the other hand works when you already selected an object.
Activates a single cell, which must be inside the current selection. To select a range of cells, use the Select method.
So what happens when you activate a cell not in the current selection?
It becomes the selected cell and as you've said, Excel executes the Select first and then the Activate in mili or nano or pico seconds (God knows how fast) interval.
In Range Objects the use of Select and Activate is almost interchangeable. But you have to take note that there will be difference always with Selection and ActiveCell. For example:
Range("A1:B10").Select
Range("B5").Activate
Debug.Print Selection.Address
Debug.Print ActiveCell.Address
This means that you can actually do stuff (e.g. format, clear, add formula, add text etc.) on all cells you activate within the current selection but still preserves what Selection object points to.
There are cases that activating the object is vital. For example you want to select multiple worksheets like below and then select Range("A1") of Sheet3.
Worksheets(Array("Sheet1", "Sheet3", "Sheet5")).Select
Worksheets("Sheet3").Activate '/* vital */
Worksheets("Sheet3").Range("A1").Select
Above is the correct select command for multiple worksheet selection and selecting a range within 1 of the worksheets selected. But without the Activate part, there is a chance that it will return:
Run-time error '1004': Select method of Range class failed
because the first sheet in the array will always be the activated sheet object after the select. Now, how to avoid this troubles? Simple, avoid using select and activate. ~the novel sequel~

vba , Autofill userform from another workbook cell selection

I have a workbook that used to be one with many sheets, I have now split the sheet to different workbooks.
The problem I now have is userform population from cell selection. When all the sheets were together. This code worked great.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not (UFMJobSelectForm.ActiveControl Is Nothing) Then
Call UpdateJobSelectForm
End If
End Sub
However now the Userform is in one workbook and this code is in another. I don't want to reference library as I need it to open and close so it can be accessed for other people to use.
Thanks for any help in advance.
Edit:
What i have is 4 different workbooks with jobs on and i want to select the job and the userform populates with job details.
The code I have detects the userform is open and then calls then populates the userform using updatejobselectform. Which worked when all the sheets were in the same workbook. however no longer works now i have separated them.
When i run this code now the sheets are in there own work books i get Error: runtime erroe 424 object required.
So what i am asking is dose anyone know how i can check a userform is loaded from in a different workbook and how i can get the useform to interact with cell selection from a different workbook.
thanks again.
This looks like a code that primafacie must fire when selection change event occurs, and call a function that must update the said form.
If the code and the said form are dependent, while splitting up should they not be together.
In case there are some other constraints that do not let you do so, and are not defined in the question do feel free to update the question / comment below.
Happy to help!

VBA - Possibility of saying that SheetChange in specific Range is "something like True"?

First, I must admit that I am completely newbie here and in VBA mostly too. Thank you for this forum! :)
I have program that reacts on SheetChange to save the data. However, if there is formula added by macro, it doesn't cause the SheetChange. Copying and inserting as values isn't possible - there are 7k rows and the program acts on every SheetChange (colors and other stuff) - the time is not bearable.
Is there any possibility to have EnableEvents = False (to turn of getting SheetChange), then specify the Range of the changed cells (always rather the whole column - there are 2 columns only that interest me) and then let the program save data. The coloring of the cells and so on would remain (this coloring and so on has to stay in the program)
Is it even possible that it would work? If it could, how should I tell the macro that specific Range has SheetChange?
Apologies if the question is totally stupid.
Thank you very much for reading at least.
In the sheet change event, just specify that it should only save when Target is within the specified range. For the formulas, use the Calculate event and repeat essentially the same code.
So, if you only want it to save when the changed cell is in the first column and only within a certain row range (for example), add If Target.Column = 1 And Target.Row > 5 And Target.Row <= 10 Then to your change event.
For the Formula issue, add the following routine
Private Sub Worksheet_Calculate()
'your code here
End Sub

I need to be able to sort a protected worksheet that has locked column headers in excel (VBA)

I am working on an excel document at the moment and everything is turning out quite nicely. However, I am coming down to the very last issue that I am having a problem resolving: being able to sort my columns in ascending/descending order while the worksheet is protected and the column headers are locked. I will state some facts about my worksheet first, the goal that I am trying to accomplish, then possible solutions that I have researched and why those solutions do not seem to apply to my situation.
First, I am NOT using an excel table object (just plain
rows/columns).
The top row has AutoFilter applied (to work as column headers).
All of the cells in the worksheet are unlocked, EXCEPT for the
entire first row which is locked (aka, the column headers).
The worksheet will be protected.
I do NOT want users to be able to edit data in the first row (this
is important, these must not be editable no matter what).
For my protected sheet settings, I have "Select locked
cells","Select unlocked cells","Insert rows","Delete rows","Sort",
and "AutoFilter" checked.
I am using VBA for my worksheet.
I am using Excel 2013
Now, assuming the worksheet is protected, users are currently able to use the AutoFilter at the top to actually "filter" the data as intended. The issue is whenever they try to "sort" the data in ascending/descending order that I get an error saying that you must unprotect the sheet first.
After researching I have seen that this is due to the fact that when you sort, the AutoFilter automatically counts the column header as part of the range being sorted... but because this column header (row 1) is locked, it is causing this error. However, this row HAS to be locked, my VBA code specifically reads the values in these column headers and under no circumstances can they be changed.
So filtering works just fine, it is just the sorting I am trying to figure out now. My "ideal" solution would be to somehow capture an event when a user clicks on the AutoFilter arrow and selects "Sort" where I can then, in VBA, unprotect the sheet, sort according to their selection, then protect the sheet again. However, again upon research, it seems that there really isn't an option when it comes to an event for this AutoFilter button (I could be wrong, sometimes it can be confusing reading other's suggestions).
I am hoping someone out there can help me out with this situation, I would also LIKE to avoid using an excel table object, however if it is the only solution that works that meets all my above criteria then so-be-it.
Thanks in advance for your help.
If you already use VBA, you can plug this code into the Sheet module. This assumes the headers are in row 1. Change to suit.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("1:1")) Is Nothing Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub
The sheet now does not need to be protected.
Borrowing a bit from #Teylyn's and adapted it to disallow selection of the header row, when it is selected, it selects the cell below it directly and displays an error message. The code sits in the sheet module, if it needs to be applied to more sheets, it may be better to use Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range), in that case, replace all instances of Me with Sh in the code below.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Target, Me.Range("1:1")) Is Nothing Then
Target.Offset(1, 0).Select
MsgBox "You cannot select or edit the headerrow, please use the autofilter button to sort and filter.", vbCritical, "Invalid Selection"
End If
End Sub
Note
Unlocking the cells which is required for the sorting and then allowing unlocked cells to be selected when protecting the worksheet, which is needed to be able to edit the data, makes the worksheet protection effectively useless.
Also wit the code above, there is still a loophole through which cells can be edited. If you select an allowed cell, drag it to the header row, and choose to replace the data in the cell then the header cell to which the allowed cell was moved is selected and editable.
End of note
Select the data range which needs to be sorted and unlock the cells.
When protecting the worksheet, be sure to allow
sort
autofilter
To prevent users from changing the cell contents, disallow the selection of unlocked cells.