The "View Side By Side" and "Synchronous Scrolling" made the comparison of 2 spreadsheets easier than ever. However, there isn't a "Synchronous Switching tab" feature, so if I switch to a different tab in one of the workbooks and continue scrolling, the sync'ed scrolling become quite funny.
Well, I shouldn't complain, because it's all done manually, and I should use this feature wisely.
As a lazy developer, I would like to write some code to dig myself out: Can I write a macro to automate the worksheet switching on the peer window in side-by-side mode?
It breaks down to 2 steps:
how do I know if a window, most likely the ActiveWindow, is in side-by-side mode?
if it is, how do I tell which window is its peer?
I did my homework. It seems Excel is not very programming friendly on this feature. There are 3 methods
BreakSideBySide()
CompareSideBySideWith(WindowName)
ResetPositionsSideBySide()
and 1 Boolean property
SyncScrollingSideBySide
on the Windows collection related to this feature, but are insufficient to solve my questions.
Does anyone have any idea how to achieve this? Or, is it indeed impossible? Thank you in advance.
You can achieve this using the Workbook_SheetActivate event:
http://msdn.microsoft.com/en-us/library/office/ff195710.aspx
if you put this code in your ThisWorkbook Object, then each time you change the active worksheet, it will...
Cycle through all open workbooks with a different name
Look for a worksheet with the same name as the sheet you just clicked on
Activate the worksheet in the other Workbook
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
For i = 1 To Application.Workbooks.Count
If Application.Workbooks(i).Name <> ThisWorkbook.Name Then
Dim otherWB As Workbook
Set otherWB = Application.Workbooks(i)
otherWB.Sheets(Sh.Name).Activate
End If
Next
End Sub
Note that this requires the worksheet to exist in all open workbooks. An error will result if it does not. However, you could easily add error handling to ignore workbooks with unfound corresponding worksheets.
Also note that it's probably best to use this when only two workbooks are open. I have not looked into the other methods you mentioned, but there may exist a way to identify the two workbooks that are currently in side-by-side mode, at which point the code could shed its for loop and become more concise.
Related
I have a rather large list of macros in my Personal.XLSB Workbook in Excel and I am wondering if there is a way to group them in some way so that when I search for a macro to run, I don't have to read through ~50 options. I understand that I can create the shortcut to run these macros, but it is not easy to store 50 shortcuts in the forefront of my mind. Is there a way to group similar macros in the Excel list. See the image below for the beginning of my list being referenced.
I cannot remove them from the personal workbook either as the macros are required to be accessed from most files I work with.
Workbooks saved in the %AppData%\Roaming\Microsoft\Excel\XLSTART will be opened invisible when the Excel.Application opens. By moving the macros into multiple workbooks and saving them to this location, you will in effect be "Grouping the Macros".
I would start by grouping the macros into their modules within the personal macro workbook. Next I would create the destination workbooks, copy the modules over and optionally delete the original modules. Next close Excel saving all the changes and then reopen the Application.
Public Sub AddMacroWorkbook(WBName As String)
WBName = Replace(Workbooks(1).FullName, "PERSONAL", WBName)
Workbooks.Add.SaveAs Filename:=WBName, FileFormat:=xlExcel12, CreateBackup:=False
End Sub
No, the only way that you can group them, is by being careful with how you name them (which looks like you're doing already).
Might I suggest adding them to a custom Ribbon, instead of running them from the Macro Dialog? That way you could organize them, and even show/hide certain buttons, when you need to, by what workbooks are open or worksheet is active.
I have some large files that I need to open (but I don't need to write a loop (otherwise, I will definitely go for DoEvents)). These files contain many data and calculations, and possibly many links to be updated (if I opened them manually, I can wait for some time). Then should I add DoEvents whenever I opened a large file as below,
Sub Test()
...
Dim wb As Workbook
Set wb = Workbooks("Large Workbook.xlsm", 3)
DoEvents
Dim wb2 As Workbook
Set wb2 = Workbooks("Large Workbook2.xlsm", 3)
DoEvents
....
End Sub
It depends on what you are trying to achieve. I generally only add DoEvents in processor intensive loops so that, if I need to interrupt the code, I can. It largely is beneficial for preventing Excel from crashing, or for preventing the 'Not Responding' screen.
That said, Excel has it's own way of opening large files. If it truly is a large file, chances are you've seen a download percentage. This is Excel loading and setting up the file.
Generally speaking, if you're getting a whitewashed screen, or Excel is crashing consistently, and you want to get some control back from your application, add a DoEvents command. Otherwise, just let your code do what it needs to do.
I have a workbook with lots of sheets and several macros. When I enter VBA and try to write a new Sub into ThisWorkbook module, I see:
"This will reset your project, proceed anyway?"
assuming, that some project is currently running.
If I press Ctrl + L right after opening the file to check the Call Stack, it just shows nothing.
I did non run any macro myself and there's not a macro, which would handle any event (as far as I checked all sheets and modules in the project) except a little sub for saving event:
Workbook_BeforeSave (ByVal SaveAsUI As Boolean, Cancel As Boolean)
but this one AFAIK should be activated only before saving, thanks to Captain Obvious.
Another mysterious thing with this book is abnormally slow filtering for structured tables, which may be cured by turning off event handler:
Application.EnableEvents = False
Since both these facts are related to Events, I guess they might be somehow connected to each other.
Updated to include comments below.
Well, the problem still exists and I appreciate any idea that may help to locate this pesky macro running totally hidden.
Hm. Anyone with any ideas?
One way to reproduce the behavior that you describe is as follows:
1) Have a public variable which is initialized in Workbook_Open()
2) Have the option Notify Before State Loss enabled (under Tools/Options/General)
In this case when you first open the workbook and try to create a sub you see the warning about resetting the project even though no macro is currently running.
If this is the case, a simple fix (if it still bothers you) is to disable Notify Before State Loss.
On the other hand, it seems that your project has more general problems. VBA projects can become inexplicably corrupt and this might be the case here. A fix which sometimes works is to export all modules, userforms, etc., delete them, and then reimport them. Rob Bovey (a highly respected VBA guru) has written an add-in called Code Cleaner to automate the process. I haven't used it personally but it might be worth a try.
I don't know why this doesn't work...
Sheets("SampleSheet").Select
ActiveWorkbook.SelectedSheets.Delete
But this works...
Sheets("SampleSheet").Select
ActiveWindow.SelectedSheets.Delete
In both situations, the sheet "SampleSheet" was selected, right?
As GSerg commented, it doesn't work because there is no ActiveWorkbook.SelectedSheets property. Someone on the Excel team wanted to make a property that returned an array of all the selected sheets. But where to put it? They could have put it at the Workbook level, but what if the user had two windows open for the same workbook? They could have different sheets selected in each window. Which window to use? So they decided to make it a property of the Window object instead.
A fine idea, maybe, but they could have put it in both places. Both the Workbook and Window object have an ActiveSheet property. When you reference ActiveWorkbook.ActiveSheet it appears to be the same as ActiveWorkbook.Windows(1).ActiveSheet and Windows(1) is always the active window. They could have done the same thing for SelectedSheets and I'd argue that they should have.
In the meantime, you can use ActiveWorkbook.Windows(1).SelectedSheets to overcome the Excel team's lack of consistency.
I have a sub that I am calling by clicking a button. I've chosen to use a regular button (aka Form Control), not an ActiveX one, because I've been seeing the text size on ActiveX controls fluctuating and regular buttons don't have this problem. I want the sub to be able to use the worksheet that the button is on. I was thinking of something like this:
Sub showSheetName()
Dim sht As Worksheet
'this would work if the code was in the worksheet's module
Set sht = Me
msgbox sht.Name
End Sub
But this sub is in a shared module, not the worksheet's module, because I want several sheets to be able to use it. So Me doesn't point to the worksheet, and this approach just gives an Invalid use of Me keyword.
How can I get a reference to the worksheet that the button is on?
EDIT: If it wasn't clear, the reason why it's important that it's not an ActiveX control is because that means there's no myButton_Click() event in the worksheet that I can use to get the worksheet object and pass to a version of showSheetName() that takes a worksheet argument.
Set sht = ActiveSheet...
This of course assumes that the procedure is being invoked manually (i.e., the user is actively clicking the button) rather than being invoked through a Call or Application.Run statement.
The button can only be clicked by the user when the worksheet is active view.
There is no such thing as a regular button. Nor anymore are there ActiveX controls.
ActiveX is a marketing terminology by MS that described controls using COM. It, as a terminology, was retired years ago (the technology is still current).
Therefore it is hard to know what you are referring to.
Use names that HELP uses. List code that specifies the objects/etc that you are using.