Macro not working right when called through a button - excel

Using Excel 07
Below is the code I currently have working. However when I assign it to a code the section where it clear contents does not run but everything else does. If I just F8 through it clears the contents no problem at all. I am not sure why this is and was hoping you could help.
Sub Save_Session()
Call UnProtectAll
If Worksheets("Drawing").Range("A2").Value = Worksheets("Drawing").Range("I2").Value Then
i = (Worksheets("Drawing").Range("B2").Value * 25) - 24
Worksheets("Drawing").UsedRange.Copy Destination:=Worksheets("Sessions").Range("A" & i)
Worksheets("Drawing").Range("B2").Value = Worksheets("Drawing").Range("B2").Value + 1
With Sheets("Drawing")
Range("A2").ClearContents
Range("C2:C20").ClearContents
Range("E2:H20").ClearContents
End With
Else
MsgBox "You do not have all the winners yet!!!"
End If
Sheets("Drawing").Select
Call ProtectAll
End Sub

It's probably working when you step through coincidentally because you happen to be on the sheet "Drawing" when running the macro.
To access properties or parameters of an object, you need to use the "." Since you are already declaring what you are trying to access with the WITH statement.
Here is an article from MSDN explaining how the WITH...End statement works In VBA.
With Sheets("Drawing")
.Range("A2").ClearContents
.Range("C2:C20").ClearContents
.Range("E2:H20").ClearContents
End With

Related

VBScript - Either getting object required or type mismatch errors

I have scoured the web and this site looking for an answer on this, so I would really appreciate some help.
I'm creating a VBScript to do some modifications to a user-specified Excel spreadsheet. I have the first part of my script working fine, but the second part is driving me nuts. I need it to search the first column for a value and, if found, delete the row. Right now I'm not worrying about the deletion statement--I'm doing testing by seeing if I can get the For Each statement to run properly as well as the If Then statement. Here's the specific block of code:
For Each cell in objSheet.Columns("A:A").Cells
Set cell = objSheet.Columns("A:A").Cells
If cell.Value = "60802400040000" then
cell.font.bold = True
End If
Next
I have tried many variations of this and cannot find the right combination. Initially I was getting an "Object Required" messages, and after reading a number of posts, found that I needed to put in a Set statement for cell, which I did. Now I am getting a Mismatch Type error message.
The funny thing is, before I put in the Set statement, the code would execute, but it would throw the Object Required error when I closed the spreadsheet. After adding it, the error for the Type Mismatch pops up immediately.
Most examples I keep finding on the web are for VBA, and I try to modify them for VBS, which I don't know very well. Any assistance anyone can give me will be greatly appreciated.
You are redefining cell, cell is defined automatically in the For Each statement.
Delete this line
Set cell = objSheet.Columns("A:A").Cells
This is an example from Help, unfortunately Help doesn't have any examples that uses For Each, only For x = n to n and other means. For Each is the right thing to do.
Set r = Range("myRange")
For n = 1 To r.Rows.Count
If r.Cells(n, 1) = r.Cells(n + 1, 1) Then
MsgBox "Duplicate data in " & r.Cells(n + 1, 1).Address
End If
Next n
For vba to vbs, you have to create the object and use, as some objects are automatically available in VBA (like app object) - Set exceldoc = CreateObject("c:\blah\blah.xls) then to use Set r = exceldoc.worksheets(0).range("MyRange").
Also you have to use constant values not names as vbscript can't look them up.

Using an if statement within a for loop- Excel VBA

I'm having trouble using an if statement inside a for loop in excel vba. The output of the debugger is not what I expect. I can post the full code of what I am trying to accomplish, but I think I have narrowed it down to what I don't understand. Here is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
For i = 9 To 60 Step 3
If Cells(i, "DR").Value < Cells(i, "EB").Value Then
Debug.Print i & "-ifloopstart"
Cells(i, "DR").Value = 999999
Debug.Print i & "-ifloopend"
End If
Next i
End Sub
The output of the debugger is:
9-ifloopstart
33-ifloopstart
51-ifloopstart
51-ifloopend
33-ifloopend
9-ifloopend
However, I expected:
9-ifloopstart
9-ifloopend
33-ifloopstart
33-ifloopend
51-ifloopstart
51-ifloopend
Can someone explain how this works? It seems to be looping back to the beginning of the if statement instead of finishing the if statement. How can I modify the code to get the output I expect? I've been struggling with this for hours and it seems so simple :( .
Each time the worksheet is updated with Cells(i, "DR").Value = 999999, Worksheet_Change gets called again.
Think of it this way. Each time that above code gets called, you modify a cell, which triggers the worksheet change method again.
So you are effectively nesting three calls of this function:
called once, with i = 9
called again, with i = 33
called again, with i = 51
finishes i = 51 call
finishes i = 33 call
finishes i = 9 call
VBA then goes backwards from each of these to get back to the first time your method was run.
Edit: as Tim says you can disable this with Application.EnableEvents=False

EXCEL VBA: calling an event with onclick property of a button which is being created on the fly

I am creating a excel VBA userform which requires many buttons to be created on the fly (ie as the requirement may be, runtime). I want to assign a subroutine to these buttons so that when they are clicked a subroutine should execute.
this is what I want to do
Set obj4 = usrform.Controls.Add("forms.commandbutton.1")
obj4.Height = 17
obj4.Left = 450
obj4.Top = 75
obj4.Font.Size = 11
obj4.Name = "compare" & (j - i) 'j and i are some variables in the code
obj4.Caption = "Compare!"
obj4.onclick = abcd
public sub abcd()
'some code here
end sub
but this code is not running. I read somewhere that here I cannot call a subroutine but a function. My problem is that I want a subroutine only as I dont intend to get something in return from it. But still for trial purpose I made abcd() a function in the above code and then my code was running but unsuccessfully as it was executing the function abcd without the need of button getting pressed.
Can anyone help me with this? I have searched a lot for this on internet in various forums.
Don't get hung up on subroutine v. function: if you don't set the return value of a function, it's the same as a subroutine.
When you set the onClick property, you give it the name of the function as a string obj4.onclick = "abcd" otherwise it will execute the function and save the return value.

VBA Code in Excel randomly stops executing. No error messages occur

Essentially, I have an Updata button that takes information from two columns, in two spreadsheets (within 1 book). The overall goal of this code is to take all the values from one column, and then append the values from the other column below it.
Worksheets("Overall Flow").Range("A4:A1004").Value = Worksheets("Active").Range("A2:A1002").Value
Dim i As Integer
For i = 4 To 1004
If Worksheets("Overall Flow").Range("A" & Trim(str(i))) = "" Then
Worksheets("Overall Flow").Range("A" & Trim(str(i)) & ":A" & Trim(str(1000 + i))).Value = Worksheets("Inactive").Range("A2:A1002").Value
i = 1005
End If
Next
For some reason, the first line executes, and then finishes. When I put break points, then do step-by-step, no other steps happen afterwards.
When I run the first line individually, it appears to work fine, but not when:
Worksheets("Overall Flow").Range("A" & Trim(str(i)) & ":A" & Trim(str(1000 + i))).Value = Worksheets("Inactive").Range("A2:A1002").Value
or
Worksheets("Overall Flow").Range("A4:A1004").Value = Worksheets("Inactive").Range("A2:A1002").Value
is present aftwards.
Solution to this is very unusual.
CTRL+BREAK CTRL+BREAK CTRL+BREAK ESC
It just happened to me againg after long time, I was looking for a solution and I came here then this sequence came back to my mind and I tried.
It worked for me, I hope this will help someone.
Update: Tweaked code (now with error checking!)
Main points concerning the current code:
When copying the ACTIVE range, check for last consecutive cell used. This is faster and more effecient than a loop.
Why are you trimming a number you know will not contain spaces?
There's no need to set i = 1005, just use Exit For. This is more effecient and clear to the reader what the intention is. I don't use this in the code below since I avoided looping altogether.
Here's a different way you can do this without any looping, which I think is more clear and effecient. Try this and see if it works for you:
Sub test()
Dim lastRow As Long, offSet As Long
lastRow = Worksheets("Active").Range("A2").End(xlDown).row
'Sanity checks
If IsEmpty(Worksheets("Active").Range("A2")) = True Then offSet = 1: lastRow = 2
If lastRow > 1001 Then lastRow = 1002
Worksheets("Overall Flow").Range("A4:A" & lastRow + 2).Value = _
Worksheets("Active").Range("A2:A" & lastRow).Value
If lastRow < 1002 Then
Worksheets("Overall Flow").Range("A" & lastRow + (3 - offSet) & _
":A1004").Value = Worksheets("Inactive").Range("A2:A1002").Value
End If
End Sub
Notes:
Sanity check 1 is for if A2 is blank in the Active sheet.
Sanity check 2 is for if there are cells beyond A1002 with values in Active sheet.
This is what I am using to test your code. Since I don't know what's in the spreadsheets, I can't reproduce exactly what you're seeing so I'm first putting dummy data into the ranges.
For me it is running fine every time, and I've tried it on 2 different computers - Excel 2003, and Excel 2010.
I set a breakpoint and stepped with F8, and also Shift F8 and both worked fine.
Something may be different with your data (i.e. the first cell being copied over from the inactive sheet is blank and therefore execution stops after processing the first cell -- check that column A4 is not blank), or perhaps some memory has gotten corrupted from having Office being killed.
In a Module I have:
Sub test()
Worksheets("Active").Range("A2:A1002").Value = "active"
Worksheets("Active").Range("A5").Value = ""
Worksheets("Inactive").Range("A2:A1002").Value = "inactive"
Worksheets("Overall Flow").Range("A4:A1004").Value = Worksheets("Active").Range("A2:A1002").Value
Dim i As Integer
For i = 4 To 1004
If Worksheets("Overall Flow").Range("A" & Trim(Str(i))) = "" Then
Worksheets("Overall Flow").Range("A" & Trim(Str(i)) & ":A" & Trim(Str(1000 + i))).Value = Worksheets("Inactive").Range("A2:A1002").Value
i = 1005
End If
Next
End Sub
Have you tried the same code on another computer?
I had this issue and I tracked it down to custom VBA functions used in Conditional Formatting that was processed while application.screenupdating was still set to True.
I'm not sure how consistent this behaviour is but, when a custom VBA function is referred to in a conditional formatting rule, when the screen updates, it will not step through the code even when employing break points or the debug.assert method. Here's the breakdown of what happened:
Context:
2 open workbooks.
Conditional formatting and custom function in question were in workbook1.
The code I was attempting to execute was in workbook2.
Process
I call a procedure in workbook2.
Workbook2's procedure reaches a line executing an autofilter command.
Autofilter command triggers a screen update in all open workbooks (any command that triggers a Worksheet_Change or Worksheet_Calculate event can apply here).
Screen update processes the conditional formatting rules, including the rule in workbook1 calling workbook1's custom function.
Custom function is run in a 'silent' state (i.e. with no interaction with user, ignoring break points and "debug.assert" calls; this appears to be by design as part of the conditional formatting feature)
Custom function finishes execution and ceases all other active code execution.
I fixed my problem by adding a Application.ScreenUpdating = False line at the start to prevent screen updates and, by extension, conditional format processing (but it's best to keep custom functions away from conditional formatting to begin with).
I'm not sure if this is relevant to your situation at all but I hope it helps somebody.
It has already been mentioned in transistor1's answer, but only as a side comment.
I had a similar problem, that VBA code simply stopped executing in the middle of a function. Just before that it also jumped back a few lines of code. No Error Message was shown.
I closed all open Excel programs, and upon reopening the File everything worked fine again.
So my confirmed Answer to this problem is: Corrupted Memory, restart Excel.
Edit: after doing this, I also encountered the Problem that Visual Basic Editor crashed when I tried uncommenting a particular line. So I created a New Excel file and copied my code. Now I don't have any problems anymore.
I ran into the same problem. I had a sub routine that gave random errors throughout the code without giving error messages. By pressing F8, the code would resume.
I found someone had posted a Subroutine he called "ThatCleverDevil" I do not remember the resource or who posted it. It would warn you an error was about to occur. The routine is posted below.
I split the code into component sub-routines. The short snippits ran with no interruption or erros. I created a subroutine that called each snippit. Errors resumed.
They would run individually, but not all together.
RESOLUTION: Between called sub-routines, I ran the following line of code:
Application.Wait Second(Now) + 1
The code then ran without error.
Thanks to whomever it was that wrote ThatCleverDevil. And special thanks to the coder who wrote about Application.Wait.
Sub ThatCleverDevil()
On Error GoTo err
MsgBox "About to error"
err.Raise 12345
MsgBox "Got here after the error"
Exit Sub
err:
Stop: Resume
End Sub
Robert
VBA simply is prone to this issue. I have used it for years in corproate workflows because it is so hardcoded into lots of things, but if possible I would just consider alternatives. If this an ad-hoc project R will be faster and offer more flexibility. If this is more production oriented and meant to handle large volumes I would consider informatica.
To improve the performance I called the function DoEvents inside the loop. It solved the problem for me.

Can't close userform

Let me set up the environment.
This is VBA code running in Excel.
I have a userform that contains a msflexgrid. This flexgrid shows a list of customers and the customer', salesperson, csr, mfg rep, and territories, assignments. When you click in a column, let's say under the Territory column, another userform opens to show a list of Territories. You then click on the territory of your choice, the userform disappears and the new territory takes the place of the old territory.
This all works great until you click on the territory of your choice the 'Territory' userform does not disappear (it flickers) and the new territory does not transfer the underlying userform.
I should mention that when I'm stepping through the code it works great.
I'm assuming it has something do to with the flexgrid as all the other userform (that don't have flexgrids) that open userform work just fine.
Following is the some code sample:
** Click event from flexgrid that shows Territory userform and assignment of new territory when territory userform is closed.
Private Sub FlexGrid_Customers_Click()
With FlexGrid_Customers
Select Case .Col
Case 0
Case 2
Case 4
Case 6
UserForm_Territories.Show
Case Else
End Select
If Len(Trim(Misc1)) > 0 Then
.TextMatrix(.Row, .Col) = Trim(Misc1)
.TextMatrix(.Row, .Col + 1) = Trim(Misc2)
End If
End With
End Sub
** The following Subs are used in the Territory userform
Private Sub UserForm_Activate()
Misc1 = ""
Misc2 = ""
ListBox_Territory.Clear
Module_Get.Territories
End Sub
Private Sub UserForm_Terminate()
Set UserForm_Territories = Nothing
End Sub
Private Sub ListBox_Territory_Click()
With ListBox_Territory
Misc1 = Trim(.List(.ListIndex, 0))
Misc2 = Trim(.List(.ListIndex, 1))
End With
Hide
UserForm_Terminate
End Sub
I know this a long winded explanation but I'm a fairly decent VBA programmer and this has me stumped.
Any help would be greatly appreciated.
I'm not going to say what you're doing is wrong (in that it won't ever work), but it scares the heck out of me. This is not the way I'd deal with forms.
Firstly, you're using UserForm_Territories (the class/form name) to refer to an implicitly-created instance of the form. This is something I've always avoided doing. I would always create an instance of a form explicitly, so instead of:
UserForm_Territories.Show
I would do:
Dim oTerritoriesForm As UserForm_Territories
Set oTerritoriesForm = New UserForm_Territories
oTerritoriesForm.Show vbModal
' get the values from the form here
Unload oTerritoriesForm
Next, and much more worryingly, you're subverting the UserForm_Terminate behaviour by calling it explicitly. Why you're doing this I can't imagine, unless you thought that it would work around your stated problem. My advice: don't do that.
Worse, you're attempting to assign to the implicitly-created instance of the form within that Terminate method. You shouldn't be doing that, either. I'm surprised that even compiles.
It seems like you're trying to force the implicitly-created instance of the form to mimic an explicitly-created one. In which case, create it explicitly, as shown above.

Resources