I have problem with IF's, when I checked checkbox which is disable then function still color my row. The solution which I'm trying get is that for checked checkbox row is green and for unchecked is blank or other color.
here is my code:
Sub CheckBoxDate()
Dim ws As Worksheet
Dim chk As CheckBox
Dim lColD As Long
Dim lColChk As Long
Dim lRow As Long
Dim rngD As Range
lColD = 0 'number of columns to the right for date
Set ws = Sheets("MA Template_VBack-End")
Set chk = ws.CheckBoxes(Application.Caller)
lRow = chk.TopLeftCell.Row
lColChk = chk.TopLeftCell.Column
Set rngD = ws.Cells(lRow, lColChk + lColD)
Select Case chk.Value
Case 1 'box is checked
For Each chk In ws.CheckBoxes
If ws.Range("C" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("D" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("E" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("f" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("g" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("i" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("t" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("u" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("z" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ab" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ac" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ap" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("at" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bs" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bt" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bu" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
ElseIf ws.Range("bv" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bx" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bz" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ca" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cc" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cd" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ce" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ci" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ck" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cl" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cm" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cn" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("co" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cp" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cq" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cs" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
ElseIf ws.Range("ea" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ed" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ee" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("eg" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("eh" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ei" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ej" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
Else
rngD.EntireRow.Interior.Color = vbGreen
chk.Value = True
End If
Next chk
Case Else 'box is not checked
chk.Enabled = True
rngD.ClearContents
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
End Select
End Sub
Main problem should be here, i'm not sure if i use correct if in case
Select Case chk.Value
Case 1 'box is checked
For Each chk In ws.CheckBoxes
If ws.Range("C" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("D" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("E" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("f" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("g" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("i" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("t" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("u" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("z" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ab" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ac" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ap" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("at" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bs" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bt" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bu" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
ElseIf ws.Range("bv" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bx" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bz" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ca" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cc" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cd" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ce" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ci" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ck" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cl" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cm" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cn" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("co" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cp" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cq" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cs" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
ElseIf ws.Range("ea" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ed" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ee" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("eg" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("eh" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ei" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ej" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
Else
rngD.EntireRow.Interior.Color = vbGreen
chk.Value = True
End If
Next chk
Case Else 'box is not checked
chk.Enabled = True
rngD.ClearContents
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
End Select
Thanks for help!
The issue may be with the Case statement. You may need to adjust it to say:
Select Case chk.Value
Case Is = 1
instead of
Case 1
when checking against the value of chk
Thanks so much for your help and lots of words which help me find my mistakes and also you teach me a lot things about VBA.
The way which solve my problem (maybe it's not the best, according to #Variatus I could do this much better, but I need more practices to understand VBA)
Working code:
Select Case chk.Value
Case Is = 1 'box is checked
If ws.Range("C" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("D" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("E" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("f" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("g" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("i" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("t" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("u" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("z" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ab" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ac" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ap" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("at" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bs" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bt" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bu" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
ElseIf ws.Range("bv" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bx" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("bz" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ca" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cc" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cd" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ce" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ci" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ck" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cl" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cm" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cn" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("co" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cp" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cq" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("cs" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
ElseIf ws.Range("ea" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ed" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ee" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("eg" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("eh" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ei" & chk.TopLeftCell.Row).Value = vbNullString Or ws.Range("ej" & chk.TopLeftCell.Row).Value = vbNullString Then
chk.Value = False
rngD.EntireRow.Interior.Color = vbRed
Else
rngD.EntireRow.Interior.Color = vbGreen
End If
Case Else 'box is not checked
chk.Enabled = True
rngD.ClearContents
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
End Select
Scenario:
1. Checked checkbox - row is green and checkbox checked
2. Unchecked Checkbox - row is default color and checkbox is unchecked
3. Required cell in row is empty - unchecked checkbox, row is red
Thanks so much for your assistance!
Here's my stab at it. From what I can tell, part of your problem may be in how you are approaching dynamic updates. I noticed, in rewriting your code, that you have this little tidbit here:
Set rngD = ws.Cells(lRow, lColChk + lColD)
If my hunch is correct, you are thinking of this as a formula. Worth noting here, once this reference is set, it isnt going to change it's target as the variables used to set it change. So for example, if lRow is 5, you set rngD, and then lRow changes to 6 rngD will still be pointing at row 5.
I could be mistaken, but this may be part of the issue.
See my version of your code below:
Sub CheckBoxDate()
Dim lColD As Long
lColD = 0 'number of columns to the right for date
Dim ws As Worksheet
Set ws = Sheets("MA Template_VBack-End")
Dim chk As CheckBox
Set chk = ws.CheckBoxes(Application.Caller)
Dim lRow As Long
lRow = chk.TopLeftCell.Row
Dim lColChk As Long
lColChk = chk.TopLeftCell.Column
' From what I can tell, you want this to dynamically update the row. As is, it will only ever be this row.
' Set rngD = ws.Cells(lRow, lColChk + lColD)
Dim ColArray_1 As Variant
ColArray_1 = Array("C", "D", "E", "F", "G", "I", "T", "U", "Z", "AB", "AC", "AP", "AT", "BS", "BT", "BU")
Dim ColArray_2 As Variant
ColArray_2 = Array("BV", "BX", "BZ", "CA", "CC", "CD", "CE", "CI", "CK", "CL", "CM", "CN", "CO", "CP", "CQ", "CS")
Dim ColArray_3 As Variant
ColArray_3 = Array("EA", "ED", "EE", "EQ", "EH", "EI", "EJ")
Dim col As Variant
Dim LoopRow As Long
Dim LoopCheck As CheckBox
Dim ConditionCheck As Boolean
Dim rngD As Range
If chk.value = 1 Then
For Each LoopCheck In ws.CheckBoxes
ConditionCheck = False
LoopRow = chk.TopLeftCell.Row
For Each col In ColArray_1
If ws.Range(col & LoopRow).value = vbNullString Then
LoopCheck.value = False
Set rngD = ws.Cells(LoopRow, lColChk + lColD)
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
ConditionCheck = True
Exit For
Next
If Not ConditionCheck Then
For Each col In ColArray_2
If ws.Range(col & LoopRow).value = vbNullString Then
LoopCheck.value = False
Set rngD = ws.Cells(LoopRow, lColChk + lColD)
rngD.EntireRow.Interior.Color = vbRed
ConditionCheck = True
Exit For
Next
End If
If Not ConditionCheck Then
For Each col In ColArray_3
If ws.Range(col & LoopRow).value = vbNullString Then
LoopCheck.value = False
Set rngD = ws.Cells(LoopRow, lColChk + lColD)
rngD.EntireRow.Interior.Color = vbRed
ConditionCheck = True
Exit For
Next
End If
If Not ConditionCheck Then
Set rngD = ws.Cells(LoopRow, lColChk + lColD)
rngD.EntireRow.Interior.Color = vbGreen
chk.value = True
End If
Next
Else
LoopCheck.Enabled = True
rngD.ClearContents
rngD.EntireRow.Interior.ColorIndex = xlColorIndexNone
End If
End Sub
I use loops to overcome the otherwise really ugly and incredibly bug prone Or statements. In this case, as soon as it finds something that meets the condition it will set the format and move on. This also demonstrates how you set a single control variable for looping. Also worth noting that the third and fourth loops have the same effect on the rows, so you could merge these, and merge ColArray's 2 and 3 as well.
I can't test this code since I dont have your worksheet and CheckBox doesn't show up in Intellisense for me (at least not when I declare the variables, I can see the methods that belong to it). Hopefully it does the trick for you though, or at least gets us closer.
Disclaimer: The following code is most probably not what you want, but it might help you get there.
Sub CheckBoxDate()
' 17 Apr 2017
Dim Ws As Worksheet
Dim Chk As CheckBox
Dim DateShift As Long ' shift number of columns to the right for date
Dim Rng As Range
Dim RngColor As Long
Dim Clms As String
DateShift = 0
Set Ws = Sheets("MA Template_VBack-End")
' This line of code has wrong syntax: What do you want?
' Set Chk = Ws.CheckBoxes(Application.Caller)
Set Chk = Ws.CheckBoxes("Check Box 4")
' Chk.TopLeftCell is already a range object: no need to re-define it
Set Rng = Chk.TopLeftCell.Offset(0, DateShift)
Chk.Value = 1 ' default
RngColor = vbGreen
Clms = "C,D,E,F,G,I,T,U,Z,AB,AC,AP,AT,BS,BT,BU"
If IsNullString(Clms, Chk.TopLeftCell.Row, Ws) Then
Chk.Value = -4146 ' not checked
RngColor = 16777215 ' no color
End If
Clms = "BV,BX,BZ,CA,CC,CE,CI,CK,CL,CM,CN,CO,CP,CQ,CS,EA,ED,EE,EG,EH,EI,EJ"
If IsNullString(Clms, Chk.TopLeftCell.Row, Ws) Then
Chk.Value = -4146 ' not checked
RngColor = vbRed
End If
Rng.EntireRow.Interior.Color = RngColor
' Chk.Enabled = True ' can't tell the intention of this
' Rng.ClearContents ' can't tell when this should be done
End Sub
Private Function IsNullString(Clms As String, _
R As Long, _
Ws As Worksheet) As Boolean
' 17 Apr 2017
Dim C() As String
Dim i As Integer
C = Split(Clms, ",")
For i = UBound(C) To 0 Step -1
If Ws.Cells(R, Columns(C(i)).Column).Value = vbNullString Then Exit For
Next i
IsNullString = (i = Not True)
End Function
There are many parts of your code which are simply not understandable. Therefore I have tried to bring a concept to your idea which is understandable and can, therefore, perhaps be modified to do what you want.
The problem I found was that you are both asking the Value of your checkboxes and setting their Value. That can only work under very strictly controlled conditions, which don't exist. Therefore my code tries to bring an order to the action. First, set a default. Then make changes to the default. I think you might want to make changes only under specific conditions. The above code will allow you to easily do that.
The code can also easily be put into a loop to go through all the checkboxes in your sheet. I intentionally didn't try to implement that because it should be done only after a single loop works successfully, including the method of calling which assuredly doesn't work the way you programmed it. Also, the range you want coloured appear ill defined.
I hope you will find the little function I added helpful. It takes a lot of volume out of your code and also works faster because it doesn't need to check all the columns: if one NullString is found the condition is already met. I suggest you try to modify this code to meet more of your requirements and then, perhaps, come back with another question to fine-tune the final result.
As promised in my comments above, this is intended as an indirect solution, a way to get at the questions in an orderly and timely fashion, such as determining the method of calling your procedure before writing it. Much of what you have already done can be incorporated eventually. Those code snippets can be added in this "procedure" as concepts are replaced with code and questions with decisions. My point here is to create a blueprint which will lead to questions that can be researched and answered and keep you on a clear path to success.
Private Sub ProjectPlan()
' 18 Apr 2017
Dim Ws As Worksheet
Dim Chk As CheckBox
' Set Ws = Sheets("MA Template_VBack-End")
Set Ws = Sheets("Ttrx")
' determine how to call this procedure
' create and test the calling process
' ===== my inclination is to say that you will need ActiveX controls for that =====
' Create a macro to set the OnAction property of all checkboxes
' in the worksheet to point to this procedure. (don't do this manually: unreliable)
' determine whether to run the proc manually or with one of
' the worksheet events (such as Open or Save)
' You will need to have access to the clicked Chk object
' assign a meaningful name to this Chk
' test setting its Value property
' I presume that you will want to know the row in the
' worksheet on which the Chk was clicked.
' ===== Could there be more than 1 Chk in a row? =====
' create the functionality and test it
' assign a meaningful variable name to this important row
' Define the range in this row which would be subject to coloring
' Assign a meaningful name to this range
' Determine colours: Default = no colour, Check = Green, Uncheck = Red
' devise a method by which to create all THREE colours
' ===== How will you create 3 colours with True & False? =====
' test the system you have devised on one Chk
' test colouring the range you have determined by the system
' you have devised: one Chk only at this time, meaning one row only.
' +++++++++++++++++++++++++++++++++++++++++++++
' Create a written description of your basic system,
' if you haven't done so already
' Resolve these problems:-
' 1. When the sheet is loaded it is white, red and green as saved (correct?)
' You might change that status using the Workbook Open event.
' 2. When a Chk is clicked it changes from True to False or v.v. (of course)
' ===== This action calls the macro (correct?)
' 3. Then the macro evaluates certain cells in the same row
' ==== Does it change the Chk to something else? ====
' 4. Then the macro looks at the final setting of the Chk
' and colours the row according to the Chk.Value
' ==== But the Chk has only True & False, red and green.
' ==== When to colour white?
' The way I understand your idea now is that checking the Chk
' indicates your wish to check which results in red or green colouring
' while the Chk.Value is actually revised by the code.
' ==== Careful not to create a loop where the change made by the code
' calls the same procedure. =====
' If your intention is to just check and colour, returning the
' Chk to unchecked in every case, consider using a button instead.
' Either way, it isn't clear how you can return a row to "no colour"
' unless you remove all colouring on Save or Close or Open.
' +++++++++++++++++++++++++++++++++++++++++++++
' You seem to want to loop through all Chks in the worksheet
' whenever one of the Chks is clicked. ===== Is that correct? =====
' This will be very, very slow.
' Consider not checking the entire sheet on every click.
' Create a loop to call other Chks you want to call
' test the loop first with one, then with 2, then 3 Chks
' Any mopping up to do?
' Consider returning certain cells to their original, colourless state
' only after the program has run its course.
' This is an alternative to doing so before it runs.
End Sub
Related
I would like to somehow get the value from the different controls on the user form and then write them on the sheet after that if the user form is closed down and re opened if a name is selected in the combobox then load all data in the form back ready to change values. I have 13 rows that a user can use on the user form.
In my code the writing the data to the sheet will write all item selected i want but it takes too long because all of the loops and ifs. Is there a better way to achieve what i want?
Private Sub FillingInForm()
Dim i As Long
Dim WS As Worksheet
Dim ctl As MSForms.Control
Dim lbl As MSForms.Label
Dim cmb As MSForms.ComboBox
Dim txtbox As MSForms.TextBox
Dim optbtn As MSForms.OptionButton
Set WS = ActiveSheet
With WS
For i = 1 To ItemsListFrame.Controls.Count
For Each ctl In ItemsListFrame.Controls
If TypeName(ctl) = "Label" Then
If ctl.Tag = "GroupItem" & i Then
Set lbl = ctl
If Controls("Item" & i).Value <> vbNullString Then
.Range("A" & i + 6).Offset(0, 0).Value = Me.OrderNo.Value
.Range("A" & i + 6).Offset(0, 1).Value = Me.NextCollectionDate.Text
.Range("A" & i + 6).Offset(0, 1).Value = Format(.Range("A" & i + 6).Offset(0, 1).Value, "dd/mm/yyyy")
.Range("A" & i + 6).Offset(0, 8).Value = Me.DateReturnBy.Value
.Range("A" & i + 6).Offset(0, 8).Value = Format(.Range("A" & i + 6).Offset(0, 8).Value, "dd/mm/yyyy")
Controls("OrderLbl" & i).Enabled = True
End If
End If
ElseIf TypeName(ctl) = "ComboBox" Then
If ctl.Tag = "GroupItem" & i Then
Set cmb = ctl
If Controls("Item" & i).Value <> vbNullString Then
Controls("Item" & i).Enabled = True
End If
If Controls("Item" & i).Value <> vbNullString Then
.Range("A" & i + 6).Offset(0, 2).Value = Controls("Item" & i).Text
End If
End If
ElseIf TypeName(ctl) = "TextBox" Then
If ctl.Tag = "GroupItem" & i Then
Set txtbox = ctl
If Controls("Item" & i).Value <> vbNullString Then
.Range("A" & i + 6).Offset(0, 3).Value = Controls("Qty" & i).Value
.Range("A" & i + 6).Offset(0, 4).Value = Controls("UnitPrice" & i).Value
.Range("A" & i + 6).Offset(0, 5).Value = Controls("SubTotal" & i).Value
.Range("A" & i + 6).Offset(0, 7).Value = Controls("Comments" & i).Value
Controls("Qty" & i).Enabled = True
Controls("UnitPrice" & i).Enabled = True
Controls("SubTotal" & i).Enabled = True
Controls("Comments" & i).Enabled = True
End If
End If
ElseIf TypeName(ctl) = "OptionButton" Then
If ctl.Tag = "GroupItem" & i Or ctl.Tag = "InOut" & i Then
Set optbtn = ctl
If Controls("Item" & i).Value <> vbNullString Then
.Range("A" & i + 6).Offset(0, 6).Value = Controls("OptionOut" & i).Value
Controls("OptionIn" & i).Enabled = True
Controls("OptionOut" & i).Enabled = True
End If
End If
End If
Next ctl
Next i
End With
End Sub
I have the following code, that basically copies databases from some files in a folder and pastes in my workbook.
It is supposed to clean everything before starting, and it does when I run from console, hitting F8 and going through it, but when I click the button to which I have assigned the Macro, it does not clean the old base before getting the new ones, then I get old data and then new data below it.
Do you know what can cause it?
Thank you!
Sub Atualizar_B_Un_Time()
Application.ScreenUpdating = False 'speed up macro execution
Application.EnableEvents = False 'turn off other macros for now
Application.DisplayAlerts = False 'turn off system messages for now
Dim base_5 As Workbook
Dim plan_5 As Worksheet
Dim aux As String
Dim caminho As String
Dim nome_arquivo_5 As String
Dim destino_5 As Worksheet
Dim dia As String
Set destino_5 = ThisWorkbook.Worksheets("B_Un_Time")
caminho = Application.ActiveWorkbook.Path
nome_arquivo_5 = Dir(caminho & "\IC_Reports_AgentUnavailableTime*.xlsx")
destino_5.Range("H2:L" & Cells(Rows.Count, "I").End(xlUp).Row).UnMerge
destino_5.Range("F2:F" & Cells(Rows.Count, "F").End(xlUp).Row).ClearContents
destino_5.Range("H2:L" & Cells(Rows.Count, "I").End(xlUp).Row).ClearContents
Do While nome_arquivo_5 <> ""
aux = caminho & "\" & nome_arquivo_5
Set base_5 = Workbooks.Open(aux, Local:=True)
Set plan_5 = base_5.Sheets(1)
dia = Mid(nome_arquivo_5, InStr(nome_arquivo_5, "-") + 1, 2)
plan_5.Range("A2:E" & plan_5.Cells(Rows.Count, "B").End(xlUp).Row).Copy _
Destination:=destino_5.Range("H" & (destino_5.Cells(Rows.Count, "I").End(xlUp).Row + 1))
destino_5.Range("F" & (destino_5.Cells(Rows.Count, "F").End(xlUp).Row + 1) & ":" & "F" & _
(destino_5.Cells(Rows.Count, "I").End(xlUp).Row)).Value = Format(Now, "mm/") & dia & Format(Now, "/yyyy")
base_5.Close savechanges:=False
nome_arquivo_5 = Dir
Loop
If IsEmpty(destino_5.Range("A" & destino_5.Cells(Rows.Count, "I").End(xlUp).Row)) Then
destino_5.Range("A2:E2").Copy Destination:=destino_5.Range("A" & (destino_5.Cells(Rows.Count, "A").End(xlUp).Row + 1) _
& ":" & "E" & destino_5.Cells(Rows.Count, "I").End(xlUp).Row)
destino_5.Range("G2").Copy Destination:=destino_5.Range("G" & (destino_5.Cells(Rows.Count, "G").End(xlUp).Row + 1) & ":" & _
"G" & destino_5.Cells(Rows.Count, "I").End(xlUp).Row)
ElseIf Not IsEmpty(destino_5.Range("A" & (destino_5.Cells(Rows.Count, "I").End(xlUp).Row + 1))) Then
destino_5.Rows((destino_5.Cells(Rows.Count, "I").End(xlUp).Row + 1) & ":" & destino_5.Cells(Rows.Count, "A") _
.End(xlUp).Row).EntireRow.Delete
End If
destino_5.Cells.Font.Name = "Calibri"
destino_5.Cells.Font.Size = 8
destino_5.Rows.RowHeight = 11.25
Application.DisplayAlerts = True 'turn system alerts back on
Application.EnableEvents = True 'turn other macros back on
Application.ScreenUpdating = True 'refreshes the screen
End Sub
It's probably because you haven't added a sheet references everywhere. and hence are referencing the active sheet. Try amending that section thus (note the dots):
With destino_5
.Range("H2:L" & .Cells(.Rows.Count, "I").End(xlUp).Row).UnMerge
.Range("F2:F" & .Cells(.Rows.Count, "F").End(xlUp).Row).ClearContents
.Range("H2:L" & .Cells(.Rows.Count, "I").End(xlUp).Row).ClearContents
End With
I have the following code to copy yearly precipitation data from 132 different excel files to one large dataset. I have precipitation data from multiple different sites which I am placing in different columns hence the different col values. I also want to match the dates hence the rw value. However, I am getting that my sub is not defined and I am not sure why.
Sub f()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim directory As String, fileName As String
directory = "C:\Working-Directory\Precipdata"
fileName = Dir(directory & "*.csv")
Do While fileName <> ""
Workbooks.Open (directory & fileName)
With (Workbooks(directory & fileName))
If Range("B2").Value = "GJOA HAVEN A" Then col = "B & rw :D & rw+lngth-27"
If Range("B2").Value = "TALOYOAK A" Then col = "E & rw :G & rw+lngth-27"
If Range("B2").Value = "GJOA HAVEN CLIMATE" Then col = "H & rw :J & rw+lngth-27"
If Range("B2").Value = "HAT ISLAND" Then col = " & rw :M & rw+lngth-27"
If Range("B2").Value = "BACK RIVER (AUT)" Then col = "N & rw :P & rw+lngth-27"
yr = Range("B27").Value
lngth = (Range("B27").End(xlDown).Row)
End With
Workbook(Macroforprecip.xlsm).Activate
rw = Cells.Find("01/01/" & yr).Row
Workbooks(fileName).Range("P&R&T" & (Range("B27").End(xlDown).Row)).Copy_Workbooks(Macroforprecip.xlsm).Range (col)
Workbooks(fileName).Close
fileName = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Also I really wanted to use the cells function so I could make col a numeric value and just add two but I can't find how to do the equivalent of Range(""A"& i : "G" & i") with it.
OK so I updated it to be slightly more simple. I am only copying one column at a time and I did change the workbook() function to workbooks() my new code looks like this.
Sub precipitation()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim directory As String, fileName As String
directory = "C:\Working-Directory\Precipdata\"
fileName = Dir(directory & "*.csv")
Do While fileName <> ""
sheetName = Left(fileName, Len(fileName) - 4)
Workbooks.Open (directory & fileName)
Workbooks(fileName).Activate
If Range("B1").Value = "GJOA HAVEN A" Then
col = "B"
End If
If Range("B1").Value = "TALOYOAK A" Then
col = "E"
End If
If Range("B1").Value = "GJOA HAVEN CLIMATE" Then
col = "H"
End If
If Range("B1").Value = "HAT ISLAND" Then
col = "K"
End If
If Range("B1").Value = "BACK RIVER (AUT)" Then
col = "N"
End If
yr = Range("B27").Value
lngth = (Range("B27").End(xlDown).Row)
Workbooks("Macroforprecip.xlsm").Activate
Set rw = ActiveSheet.Cells.Find(what:=DateValue("01/01/" & yr))
r = rw.Row
Workbooks(fileName).Range("P27", "P" & lngth).Copy_Workbooks("Macroforprecip.xlsm").Range (col & r)
Workbooks(fileName).Close
fileName = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
My new error is that I get "Run-time error '438':
Object doesn't support this property or method."
This happens at the Line that actually does the copying over `
(Workbooks(fileName).Range("P27", "P" & lngth).Copy_Workbooks("Macroforprecip.xlsm").Range (col & r)`
I do not fully understand what this means and even more so I do not understand what to do about it. Thank you all for the help so far.
This line fails:
Workbook(Macroforprecip.xlsm).Activate
because there's no function called Workbook. You probably meant to use the application workbooks collection, like this:
Workbooks("Macroforprecip.xlsm").Activate
I made a lot of changes because there were a lot of problems. See if this gets you a little closer:
Sub f()
Dim wb As Workbook ' define workbook object
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim directory As String, fileName As String
directory = "C:\Working-Directory\Precipdata\" ' added backslash
fileName = Dir(directory & "*.csv")
Do While fileName <> ""
Set wb = Workbooks.Open(directory & fileName) ' set a workbook object
With wb ' use workbook object instead
If Range("B2").Value = "GJOA HAVEN A" Then col = "B" & rw & ":D" & rw + lngth - 27 ' fixed
If Range("B2").Value = "TALOYOAK A" Then col = "E" & rw & ":G" & rw + lngth - 27 ' fixed
If Range("B2").Value = "GJOA HAVEN CLIMATE" Then col = "H" & rw & ":J" & rw + lngth - 27 ' fixed
'If Range("B2").Value = "HAT ISLAND" Then col = " & rw :M & rw+lngth-27" ' missing column so removed
If Range("B2").Value = "BACK RIVER (AUT)" Then col = "N" & rw & ":P" & rw + lngth - 27
yr = Range("B27").Value
lngth = (Range("B27").End(xlDown).Row)
.Activate
'Workbook(Macroforprecip.xlsm).Activate ' moved into the With
rw = Cells.Find("01/01/" & yr).Row
wb.Range("P&R&T" & (Range("B27").End(xlDown).Row)).Copy wb.Range(col) ' not sure what you are trying to do here
End With
wb.Close
fileName = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I currently have a VBA Code written to ask for a users input of a string as well as a certain directory, and it searches through each folder, subfolder, workbook and worksheets until it finds the string the user put in. The issue I'm running into is that after it finds the string, it continues to search the rest of the folders. The application I'll be using this in, there is only one of that string being searched. I have tried debugging, and using an if statement with "c" to match str but it keeps throwing an error. The code is attached below, any help is appreciated.
Public WS As Worksheet
Sub SearchWKBooksSubFolders(Optional Folderpath As Variant, Optional Str As Variant)
Dim myfolder As String
Dim a As Single
Dim sht As Worksheet
Dim Lrow As Single
Dim Folders() As String
Dim Folder As Variant
ReDim Folders(0)
If IsMissing(Folderpath) Then
Set WS = Sheets.Add
With Application.FileDialog(msoFileDialogFolderPicker)
.Show
myfolder = .SelectedItems(1) & "\"
End With
Str = Application.InputBox(prompt:="Search string:", Title:="Search all workbooks in a folder", Type:=2)
If Str = "" Then Exit Sub
WS.Range("A1") = "Search string:"
WS.Range("B1") = Str
WS.Range("A2") = "Path:"
WS.Range("B2") = myfolder
WS.Range("A3") = "Folderpath"
WS.Range("B3") = "Workbook"
WS.Range("C3") = "Worksheet"
WS.Range("D3") = "Cell Address"
WS.Range("E3") = "Link"
Folderpath = myfolder
Value = Dir(myfolder, &H1F)
Else
If Right(Folderpath, 2) = "\\" Then
Exit Sub
End If
Value = Dir(Folderpath, &H1F)
End If
Do Until Value = ""
If Value = "." Or Value = ".." Then
Else
If GetAttr(Folderpath & Value) = 16 Then
Folders(UBound(Folders)) = Value
ReDim Preserve Folders(UBound(Folders) + 1)
ElseIf (Right(Value, 3) = "xls" Or Right(Value, 4) = "xlsx" Or Right(Value, 4) = "xlsm") And Left(Value, 1) <> "~" Then
On Error Resume Next
Dim wb As Workbook
Set wb = Workbooks.Open(Filename:=Folderpath & Value, Password:="zzzzzzzzzzzz")
On Error GoTo 0
'If there is an error on Workbooks.Open, then wb Is Nothing:
If wb Is Nothing Then
Lrow = WS.Range("A" & Rows.Count).End(xlUp).Row + 1
WS.Range("A" & Lrow).Value = Value
WS.Range("B" & Lrow).Value = "Password protected"
Else
For Each sht In wb.Worksheets
'Expand all groups in sheet
sht.Unprotect
sht.Outline.ShowLevels RowLevels:=8, ColumnLevels:=8
Set c = sht.Cells.Find(Str, After:=sht.Cells(1, 1), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not c Is Nothing Then
firstAddress = c.Address
Do
Lrow = WS.Range("A" & Rows.Count).End(xlUp).Row + 1
WS.Range("A" & Lrow).Value = Folderpath
WS.Range("B" & Lrow).Value = Value
WS.Range("C" & Lrow).Value = sht.Name
WS.Range("D" & Lrow).Value = c.Address
WS.Hyperlinks.Add Anchor:=WS.Range("E" & Lrow), Address:=Folderpath & Value, SubAddress:= _
"'" & sht.Name & "'" & "!" & c.Address, TextToDisplay:="Link"
Set c = sht.Cells.FindNext(After:=c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
Next sht
wb.Close False
End If
End If
End If
Value = Dir
Loop
For Each Folder In Folders
Call SearchWKBooksSubFolders(Folderpath & Folder & "\", Str)
Next Folder
Cells.EntireColumn.AutoFit
End Sub
Add a boolean variable that you set to True to indicate that you've found what you're looking for. Something like this:
Sub SearchWKBooksSubFolders(Optional Folderpath As Variant, Optional Str As Variant)
Dim myfolder As String
Dim a As Single
Dim sht As Worksheet
Dim Lrow As Single
Dim Folders() As String
Dim Folder As Variant
ReDim Folders(0)
If IsMissing(Folderpath) Then
Set WS = Sheets.Add
With Application.FileDialog(msoFileDialogFolderPicker)
.Show
myfolder = .SelectedItems(1) & "\"
End With
Str = Application.InputBox(prompt:="Search string:", Title:="Search all workbooks in a folder", Type:=2)
If Str = "" Then Exit Sub
WS.Range("A1") = "Search string:"
WS.Range("B1") = Str
WS.Range("A2") = "Path:"
WS.Range("B2") = myfolder
WS.Range("A3") = "Folderpath"
WS.Range("B3") = "Workbook"
WS.Range("C3") = "Worksheet"
WS.Range("D3") = "Cell Address"
WS.Range("E3") = "Link"
Folderpath = myfolder
value = Dir(myfolder, &H1F)
Else
If Right(Folderpath, 2) = "\\" Then
Exit Sub
End If
value = Dir(Folderpath, &H1F)
End If
'---Add this:
Dim TimeToStop As Boolean
'---Change this:
Do Until TimeToStop
If value = "." Or value = ".." Then
Else
If GetAttr(Folderpath & value) = 16 Then
Folders(UBound(Folders)) = value
ReDim Preserve Folders(UBound(Folders) + 1)
ElseIf (Right(value, 3) = "xls" Or Right(value, 4) = "xlsx" Or Right(value, 4) = "xlsm") And Left(value, 1) <> "~" Then
On Error Resume Next
Dim wb As Workbook
Set wb = Workbooks.Open(fileName:=Folderpath & value, Password:="zzzzzzzzzzzz")
On Error GoTo 0
'If there is an error on Workbooks.Open, then wb Is Nothing:
If wb Is Nothing Then
Lrow = WS.Range("A" & Rows.Count).End(xlUp).Row + 1
WS.Range("A" & Lrow).value = value
WS.Range("B" & Lrow).value = "Password protected"
Else
For Each sht In wb.Worksheets
'Expand all groups in sheet
sht.Unprotect
sht.Outline.ShowLevels RowLevels:=8, ColumnLevels:=8
Set c = sht.Cells.Find(Str, After:=sht.Cells(1, 1), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext)
If Not c Is Nothing Then
'---Add this
TimeToStop = True 'since we found what we're looking for
firstAddress = c.Address
Do
Lrow = WS.Range("A" & Rows.Count).End(xlUp).Row + 1
WS.Range("A" & Lrow).value = Folderpath
WS.Range("B" & Lrow).value = value
WS.Range("C" & Lrow).value = sht.Name
WS.Range("D" & Lrow).value = c.Address
WS.Hyperlinks.Add Anchor:=WS.Range("E" & Lrow), Address:=Folderpath & value, SubAddress:= _
"'" & sht.Name & "'" & "!" & c.Address, TextToDisplay:="Link"
Set c = sht.Cells.FindNext(After:=c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
Next sht
wb.Close False
End If
End If
End If
value = Dir
'---Add these 3 lines
If Len(value) = 0 Then
TimeToStop = True
End If
Loop
For Each Folder In Folders
Call SearchWKBooksSubFolders(Folderpath & Folder & "\", Str)
Next Folder
Cells.EntireColumn.AutoFit
End Sub
Do note that you're calling your routine recursively:
For Each Folder In Folders
Call SearchWKBooksSubFolders(Folderpath & Folder & "\", Str)
Next Folder
Once you've gone through all your searching routine, you're going to start all over again because you're calling your Sub from within your Sub. Don't know if this is what you're after, and it may be an additional cause of further unexpected looping.
"If Str = c.Value Then GoTo 85"
Change to
"If Str = c.Value Then End"
I am using this to try and copy photos that exist in the list within a list in excel. it seems check but doesn't see anything in the source folder and returns the "Does N" from the code below. I have enabled macros and the folders don't see locked. any help would be much appriciated
Option Explicit
Sub CopyFiles()
Dim iRow As Integer ' ROW COUNTER.
Dim sSourcePath As String
Dim sDestinationPath As String
Dim sFileType As String
Dim bContinue As Boolean
bContinue = True
iRow = 1
' THE SOURCE AND DESTINATION FOLDER WITH PATH.
sSourcePath = "C:\Users\username\Desktop\source\"
sDestinationPath = "C:\Users\username\Desktop\TARGET\"
sFileType = ".jpg" ' TRY WITH OTHER FILE TYPES LIKE ".pdf".
' LOOP THROUGH COLUMN "A" TO PICK THE FILES.
While bContinue
If Len(Range("A" & CStr(iRow)).Value) = 0 Then ' DO NOTHING IF THE COLUMN IS BLANK.
MsgBox "Process executed" ' DONE.
bContinue = False
Else
' CHECK IF FILES EXISTS.
If Len(Dir(sSourcePath & Range("A" & CStr(iRow)).Value & sFileType)) = 0 Then
Range("B" & CStr(iRow)).Value = "Does N"
Range("B" & CStr(iRow)).Font.Bold = True
Else
Range("B" & CStr(iRow)).Value = "On Hand"
Range("B" & CStr(iRow)).Font.Bold = False
If Trim(sDestinationPath) <> "" Then
Dim objFSO
Set objFSO = CreateObject("scripting.filesystemobject")
' CHECK IF DESTINATION FOLDER EXISTS.
If objFSO.FolderExists(sDestinationPath) = False Then
MsgBox sDestinationPath & " Does Not Exists"
Exit Sub
End If
'*****
' HERE I HAVE INCLUDED TWO DIFFERENT METHODS.
' I HAVE COMMENTED THE SECOND METHOD. TO THE SEE THE RESULT OF THE
' SECOND METHOD, UNCOMMENT IT AND COMMENT THE FIRST METHOD.
' METHOD 1) - USING "CopyFile" METHOD TO COPY THE FILES.
objFSO.CopyFile Source:=sSourcePath & Range("A" & CStr(iRow)).Value & _
sFileType, Destination:=sDestinationPath
' METHOD 2) - USING "MoveFile" METHOD TO PERMANENTLY MOVE THE FILES.
'objFSO.MoveFile Source:=sSourcePath & Range("A" & CStr(iRow)).Value & _
sFileType, Destination:=sDestinationPath
'*****
End If
End If
End If
iRow = iRow + 1 ' INCREMENT ROW COUNTER.
Wend
End Sub
You shouldn’t be creating a new FileSystemObject on every iteration. Also, the destination folder can only be checked once - no need to check it every time.
See below your code with a few changes.
Option Explicit
Sub CopyFiles()
On Error GoTo Errproc
Const sSourcePath As String = "C:\Users\username\Desktop\source\"
Const sDestinationPath As String = "C:\Users\username\Desktop\TARGET\"
Const sFileType As String = ".jpg"
'validate destination folder
If Len(Dir(sDestinationPath)) = 0 Then
MsgBox "Destination path does not exist..."
Exit Sub
End If
Dim iRow As Integer
iRow = Range("A" & Rows.Count).End(xlUp).Row
Dim rr As Range, r As Range
Set rr = Range("A1:A" & iRow)
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
For Each r In rr
With objFSO
If Not .FileExists(sSourcePath & r.Value & sFileType) Then
r.Offset(0, 1).Value = "Does N"
r.Offset(0, 1).Font.Bold = True
Else
r.Offset(0, 1).Value = "On Hand"
r.Offset(0, 1).Font.Bold = False
objFSO.CopyFile sSourcePath & r.Value & sFileType, sDestinationPath, True 'Overwrite
'objFSO.MoveFile Source:=sSourcePath & r.Value & sFileType , Destination:=sDestinationPath
End If
End With
Next r
Leave:
Set objFSO = Nothing
On Error GoTo 0
Exit Sub
Errproc:
MsgBox Err.Description, vbCritical
Resume Leave
End Sub