I couldn't find this asked anywhere. In Visual Basic (excel), I can hit F8 and cycle through each line. But lets say I want to begin the sub procedure, and then after executing the first 2 lines, I'd like to skip to line 200. Until now, I've always just dragged the yellow arrow to the desired line. This is really time consuming and I was wondering if there's any command to simply say "run current line where selected" or something.
Additionally, even if I could begin to run through line by line, and quickly move the yellow selected arrow to the desired line, that would also work.
If you have a 200-liner procedure that does so many things you'd like to skip most of it, it looks like you need to refactor a bit.
Extract "things the procedure is doing" into their own Sub procedures and Function scopes. If you have banner-like comments that say things like '*** do something *** then that's a chunk to extract into its own procedure already.
Stepping through that procedure could then involve stepping over (Shift+F8) the smaller procedures that do one thing, or break and skip the call altogether.
Right click on the line you want to jump to. Hit the Set Next Statement option in the menu. That's equivalent to dragging the arrow to that line. (Ctrl-F9 is the hotkey for this action.)
If you want it to quickly execute every line up to a certain line, set a breakpoint then hit run instead of stepping through the code line by line. Do this by clicking on the gray bar to the left side where the yellow arrow appears. A dark red dot should appear and the line should be highlighted in dark red. This tells visual basic to stop when it hits that line.
You can also comment lines out by starting them with an apostrophy.
Finally, you can break code into subroutines and execute them independently of eachother.
Sub Subroutine1()
'This is a commented out line. It does nothing.
MsgBox "Do stuff here"
End Sub
Sub Subroutine2()
Subroutine1 'This will run all the code in subroutine 1
MsgBox "Do more stuff here"
End Sub
In the above example, if you run Subroutine1 you'll get one message box popping up. If you run Subroutine2 you'll get two message boxes.
Unfortunately it is not possible to do what you ask directly.
However, you may comment out the lines of code above the code you want to be executed for example:
Sub Workbook_Open()
'Application.DisplayFullScreen = True
'Application.DisplayFormulaBar = False
'ActiveWindow.DisplayWorkbookTabs = False
''ActiveWindow.DisplayHeadings = False
Application.EnableEvents = True
Password = "1234"
ActiveWorkbook.Protect
ThisWorkbook.Protect (Password = "1234")
End Sub
You may use GoTos, but however this is not considered good practice and may actively harm your code:
Sub Workbook_Open()
GoTo ExecuteCode
Application.DisplayFullScreen = True
Application.DisplayFormulaBar = False
ActiveWindow.DisplayWorkbookTabs = False
ActiveWindow.DisplayHeadings = False
Application.EnableEvents = True
ExecuteCode:
Password = "1234"
ActiveWorkbook.Protect
ThisWorkbook.Protect (Password = "1234")
End Sub
This is how I do it - basically if I know that my code up to line 200 is working properly but I'm pretty sure there's an error between 200-300 then before compiling - scroll down to line 200 and mark it (to the left of the code). Then compile it - click F5 and it will execute everything up to line 200 - then you can step through each line thereafter individually.
I normally comment out lines of code that I don't want to run with apostrophes. Alternatively, you can break up your code into smaller procedures so that you can easily pick and choose what you want to test/run.
I found adding a module for testing and copy pasting snippets of code in it as a best way for troubleshooting.
Related
I'm working on a Word Macro to streamline doing my University Mathematics and Statistics Coursework. Basically, selecting a group of equations and running it changes font size, line height and formats the paragraph in the way that I want to be common to all my maths/equations sections. It's great, but there's one little bit which I still have to do "manually", so to speak, which is right clicking and selecting "Align at equals".
Now the reason I'm asking this here and not on Super User is that I think I've exhausted all ways of doing this at the "record macro" stage. I found out how to access the right click menu without right clicking and accessed the "align at equals" option during record. Nothing was recorded.
Truth be told I'd prefer to code the lot anyway as it gives me more control. So, I'll post my code here and if anyone knows what line(s) of code I need to add to get it to replicate the "align at equals" command I would be extremely grateful.
Sub Equationiser()
'
' Equationiser Macro
'
'
With Selection.ParagraphFormat
.SpaceBefore = 12
.SpaceAfter = 12
.LineSpacingRule = wdLineSpace1pt5
End With
Selection.Font.Size = 20
End Sub
So, ideally just before the "With Selection.ParagraphFormat" section there would be some kind of "AlignAtEquals" command or whatever is needed so that, on one keypress, I would be able to align all the equals, set the line height to 1.5, place a 12 point space before and after the paragraph and change the font size to 20.
My absolute ideal would also be to programatically select all equation boxes that are in the same block, as "align at equals" is notoriously fussy and finicky as to when it will execute. That might also mean there may be a try and catch needed depending on whether trying to run "align at equals" when it wouldn't normally be available from the right click menu would do nothing or cause an error.
Any help on these two implementations would be gratefully appreciated but I'd happily settle for just the first.
I've built a solution that should address your needs, based on:
Looking through the equation to find the equal-sign.
Get the location of that equal-sign
Use that location to set the AlignPoint property of the OMath object
that is your equation
Use this MSDN reference if you want to explore more
Sub Equationiser()
'
' Equationiser Macro
'
'
Dim equationCounter As Long, charLoc As Long, FormattedTextLoc As Long
With Selection
For equationCounter = 1 To .OMaths.Count:
FormattedTextLoc = 0
For charLoc = 1 To Len(.OMaths(equationCounter).Range.FormattedText):
FormattedTextLoc = FormattedTextLoc + Len(.OMaths(equationCounter).Range.FormattedText.Characters(charLoc))
If .OMaths(equationCounter).Range.FormattedText.Characters(charLoc) = "=" Then
.OMaths(equationCounter).AlignPoint = (FormattedTextLoc - 1)
Exit For
End If
Next charLoc
Next equationCounter
End With
With Selection.ParagraphFormat
.SpaceBefore = 12
.SpaceAfter = 12
.LineSpacingRule = wdLineSpace1pt5
End With
Selection.Font.Size = 20
End Sub
I've done some brief testing that from what I can see this should be able to manage several code-blocks, i.e. when selecting 2 code-blocks it will align-at-equals all equations in the first block, then align-at-equals all equations in the second block (both blocks are not aligned with each oter) - is this your desired outcome to your request: My absolute ideal would also be to programatically select all equation boxes that are in the same block, as "align at equals" is notoriously fussy and finicky as to when it will execute.
Any idea why inserting break points and stop no longer stops my vba code from running?
The code runs ok all the way to the end (I tested it) but ignores break points and Stop.
Also step into just makes the code run in it's entirety, ignoring break points and stops.
When I close the workbook where the issue seems to originate from the same issue occurs in other macro workbooks.
if I completely close excel and re-open it with a normally working macro workbook the issue doesn't occur until I re-open the problem work book.
I added breakpoints on:
TotP1 = 0
of the following code:
Option Explicit
Private Country As String
Private Measure As String
Private P1 As String
Private P2 As String
Private TotP1 As Double
Private TotP2 As Double
Sub VennDisplayIt()
Dim SI() As String
Dim SICount As Integer
Dim x As Integer
Dim OSh As Worksheet
Dim BrandListBox As Object
Dim VennGroup As Shape
TotP1 = 0
TotP2 = 0
Set OSh = ThisWorkbook.Sheets("Venn")
Set BrandListBox = OSh.OLEObjects("BrandListBox").Object
ReDim SI(2, 0)
For x = 0 To BrandListBox.ListCount - 1
If BrandListBox.Selected(x) = True Then
'If UBound(SI) < 4 Then
ReDim Preserve SI(2, UBound(SI, 2) + 1)
SI(1, UBound(SI, 2)) = BrandListBox.List(x)
SI(2, UBound(SI, 2)) = x + 1
'End If
End If
Next x
If UBound(SI, 2) < 2 Then
BrandListBox.Selected(BrandListBox.ListIndex) = True
Exit Sub
ElseIf UBound(SI, 2) > 4 Then
BrandListBox.Selected(BrandListBox.ListIndex) = False
Exit Sub
End If
For x = 1 To UBound(SI, 2)
OSh.Range("o8").Offset(x, 0).Value = SI(1, x)
OSh.Range("o8").Offset(x + 5, 0).Value = SI(1, x)
Next x
For x = UBound(SI, 2) + 1 To 4
OSh.Range("o8").Offset(x, 0).Value = ""
OSh.Range("o8").Offset(x + 5, 0).Value = ""
Next x
SICount = UBound(SI, 2)
For x = 1 To OSh.Shapes.Count
If Right(OSh.Shapes(x).Name, 5) = "Group" Then
If LCase(OSh.Shapes(x).Name) = SICount & "waygroup" Then
Set VennGroup = OSh.Shapes(x)
OSh.Shapes(x).Visible = True
Else
OSh.Shapes(x).Visible = False
End If
End If
Next x
For x = 1 To SICount
VennGroup.GroupItems.Item(SICount & "WayBrand" & x).DrawingObject.Text = SI(1, x)
Next x
Country = ThisWorkbook.Sheets("Venn").Range("D4").Value
Measure = ThisWorkbook.Sheets("Venn").Range("E32").Value
P2 = ThisWorkbook.Sheets("Venn").Range("E31").Value
P1 = ThisWorkbook.Sheets("Selections").Range("B5").Value
End Sub
I've never heard of Stop not working, but I've heard about and experienced the breakpoint thing many times. When you compile VBA, it creates a p-code, which is used by the interpreter. You have the VBA syntax layer that you can see and the p-code layer that you can't see. When breakpoints stop working, it's because the p-code was corrupted. I don't know how or why it happened, but it did.
The fix is to export, remove, and reimport all of your modules. Exporting them creates a .bas file (plain text, really). When you re-import, the p-code is regenerated from scratch. If you have more than a couple of modules, get CodeCleaner (free add-in) and it will export and reimport automatically.
If one of the settings is unchecked then breakpoints will not work. "File/options/Current database/Application options/use access special keys" should be checked
Just to 'second' Tibo's comment: I had a problem where I had a form with about 5 different subroutines. One of them (attached to a button event) would not stop when I set a breakpoint. in 10 years of VBA writing, I've never seen that happen. Interestingly, breakpoints worked on all of the other subroutines in that form. After much head-scratching and searching, I came upon this post and Tibo's comment. I added a "Stop" command to the affected subroutine, ran the procedure (it stopped as it should have) and then breakpoints began working again! Hope this helps someone in the future.
If the breakpoints are in your code, then the code should stop running as soon as it hits that line. Possible causes of your problem:
a) The code never gets to the Breakpoint.
Seems highly unlikely seeing as you're breaking on the first line of your code. Maybe step through the sub (F8) just to check it's running as it should.
b) Your breakpoints have been wiped. Any line with a breakpoint should display as highlighted in red on your IDE. Your breakpoints can easily be wiped through, e.g. closing and opening the workbook (a screenshot would be really useful).
c) your workbook is broken in some way. It would be unlikely to break something as fundamental as stopping at breakpoints and still function normally. Are you sure your code is actually running?
Just sharing a funny thing which happened to me in case it helps someone. The mistake I did was that I simply took someone's method code meant for workbook open event and pasted it on Sheet1 excel object code area. So there was no possibility of Workbook_Open method getting fired ever.
Private Sub Workbook_Open()
Stop
On Error Resume Next
Call ActiveSheet.Worksheet_Activate
On Error GoTo 0
End Sub
What I was supposed to do is paste this method after double clicking ThisWorkbook node under Microsoft Excel Objects in Project pane as shown below:
Note: Side effect of copy-pasting others code can be freaky at times.
a) Double check that your breakpoints got disabled or not.
b) Double check that you added a conditional breakpoint or not
c) If you run your macro using C# code (using, the _Run2 command), breakpoints and stop doesn't work sometimes.
I have the problems as described above:
Stop and Breakpoints not working
Single step F8 worked, but code was not highlighted in yellow
Closing VBA editor did not help
My remedy: close VBA editor again, save Excel-file, open editor, back to normal
I've never faced this problem for years. Today for the first time I started using watch expressions with stopping when true.
This happens to me once in a while and the following solves the problem for me every time:
Create a Sub with only the command Stop in it. Run it. Then try your routine, the breakpoints and Stop commands should now work correctly.
Make sure that you do not have a named Range that matches the name of the Function or Subroutine you are calling. This will look like the Function or Subroutine is failing, but it is actually failing before the routine is ever called with an 'invalid cell reference'.
I had this problem as well. My solution was put an error in the code and run it. After I cleared the error the breakpoints started working again. That was weird.
I been writing code in VBA for many years but today I came across this problem for the first time. None of the solutions I found on the web worked but here's something simply you can use instead of Stop:
ErrCatch = 1 / 0
Still doesn't solve the breakpoints not working though...
I went int my vba code, added an enter (new blank line), then ran it again.
Voila! It ran the code and stopped at the breakpoint!
Not just me then! On a few occasions the yellow hi-lite stops a few lines beyond the breakpoint! I guess the code is running so fast it can't stop in time. :) As suggested above, I find adding "stops" here and there and also exporting & re-importing helps too.
Something we can just put break point on while making sure it doesn't do anything else.
In c, that would be while(false);
What to do in vb.net?
If you always need it to break there you can put
Stop or Debugger.Break()
If you really want a No-Op for some reason (could this turn into a contest for the most ineffectual single line of code?!), how about these?
System.Threading.Thread.Sleep(1) - 1ms is unlikely to have a huge impact outside of a loop
Debug.Write("") - doesn't appear to output anything.
There is a legitimate use-case for this.
When a temporary breakpoint is required after the statement of interest and this is the last line inside an if statement, an extra no-op type statement is required to place the temporary breakpoint on.
In this case I use:
If someCondition >0 Then
doSomething
Space (1) 'Dummy line to place breakpoint
End If
This returns a string containing one space, but does not assign it to anything. I use it in VBA, but it's also supported in .net
My two cents...
You can combine any series of commands onto one line with colons:
If False Then : End If
Select Case False : Case Else : End Select
I've also made it into a sub. Then it gets a recognizable name of own:
'Definition...
Public Sub noop () 'Or Private, Protected, etc.
End Sub
'Usage...
Sub Main()
If sometest Then
noop
Else
MsgBox "test is false"
End If
End Sub
Very strange question, you could place a BreakPoint about anywhere in the code. But here are some useless lines :
Do While False
Loop
While False
End While
Even the following :
Dim hello = Nothing
Or this :
Format("", "")
A no-op statement is also useful as an aid to document code nicely and make it more easily understandable. You could for example put in a statement like A = A.
For example:
If MyNumber => 100 then A = A
Else:
I know this is an old query, but for what it is worth, my preferred solution to the original question is
Debug.Assert (vbTrue)
If you wanted, you could use a variable instead of vbTrue and then enable/disable all breakpoints in your code by changing one variable
Dim bDisableBreakpoints as Boolean: bDisableBreakpoints = vbTrue
'your code here
Debug.Assert (bDisableBreakpoints)
'rest of your code
Simply change bDisableBreakpoints to vbFalse and the breakpoints will be set wherever you have used Debug.Assert
My personal favorite is
dim b=1
Then I put a breakpoint there.
I have a VBA sub that makes a call to a sub that was written by someone else. occasionally, the other sub opens a MsgBox with an OK button. The other sub takes a long time to run, and I am calling it hundreds of times, so I want to be able to run this overnight. Unfortunately, I can't figure out a way to automatically click OK on the MsgBox.
I have tried
Application.DisplayAlerts = False
but this doesn't suppress message boxes.
Is there any way to do this?
Thanks
One way to do this is slightly modifying the code of the original sub. You will need to have the necessary permissions tough...
Modify the header of the original sub by throwing in an extra optinal parameter at the end setting the default value to True. This will result in something like Sub OriginalSubName(original set of parameters, Optional ShowMessages = True)
At the point where the msgbox is called, modify the code this way:
If showMessages = True Then 'The = True part is important here - see below.
showMessages is a Variant type
'The original statement that calls the msgBox
End If
Leave the rest of the code of the original sub unchanged
Modify the line where you call the original sub by throwing in False as an extra parameter. This results in OriginalSubNameyour set of parameters, False. This way you don't suppress the dialog box by default, but you do when you use it in your sub.
Wonder why I use an optional Variant type parameter?
The optional part: this prevents other existing subs from crashing when they call the modified sub
The Variant type part: optional parameters are always Variant type. That's also why you need to use If showMessages = True Then instead of just If showMessages Then.
I have some code which intercepts the Before_Print event in excel to make sure that the user has filled in all the required fields before they print the sheet. However, I only want this code to fire when the user is actually printing, not when they are just calling the print preview.
Is there any way to tell in the Before_Print code whether the user is actually printing or just previewing?
The code that I currently have is (event stub was generated by excel):
Private Sub Workbook_BeforePrint(Cancel As Boolean)
If Not Sheet2.CheckAllFieldsFilled Then
Cancel = True
End If
End Sub
I don't think there is a neat way to determine if the event is a print preview or print request.
The solution below is not particularly neat and inconveniences the user slightly, but it works.
The code cancels the event and then prompts the user, based on their response it displays the print preview or prints.
Private Sub Workbook_BeforePrint(Cancel As Boolean)
Dim Print_or_Preview As XlYesNoGuess
Application.EnableEvents = False
Cancel = True
Print_or_Preview = MsgBox("Show Print Preview?", vbYesNo)
If Print_or_Preview = True Then
ActiveWindow.ActiveSheet.PrintPreview
Else
ActiveWindow.ActiveSheet.PrintOut
End If
Application.EnableEvents = True
End Sub
I think I would provide a very visible button for the user to push when wanting to Print Preview.
Make the button hide for printing (in the options for the button), and have the code simply say:
ActiveWindow.ActiveSheet.PrintPreview
To print you could do something like this:
ActiveWindow.SelectedSheets.PrintOut Copies:=1, Collate:=True
To Print Preview as was suggested:
ActiveWindow.ActiveSheet.PrintPreview
Each one would would require a different button, but either way I would strongly suggest testing if you really need both, because the preview button may work for your print option, especially since you would in most cases be able to print straight from the preview.
I may be wrong here, but I don't think so.
Just a heads up, the print option I posted here will directly print, it won't request options, because they have been coded into the script, if you want to change how many copies you wish to print, change the copies:= to whatever number you wish...
Enjoy :)