Friends, I'm very poor in programming but maybe someone is willing to help.
My spreadsheet contains 18 ranges and 2 different headers in protected area. I need to copy and combine 1 header and 1 range to another, unprotected area. User should press a button and macro brings data to new position where it can be pasted.
For button operation I have an application.caller for hiding and showing rows. I think this is a good start. I also have a copy macro for 1 set of ranges. I'd like to combine these 2 in to a new macro.
Sub Macro_copy_RIVA1()
Range("RHEAD").Copy
Range("RIVA1").Copy
Application.Goto Reference:="R1120C2"
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Selection.Cut
End Sub
My application caller for hide/show rows is (thanks to Stackoverflow)
Sub ShowHideRows()
Dim arr
'split the calling button name into an array
' (array will be zero-based)
arr = Split(Application.Caller, "_")
'**EDIT** check array is expected size...
If UBound(arr) <> 3 Then Exit Sub
If IsNumeric(arr(1)) And IsNumeric(arr(2)) Then
With ActiveSheet ' "Me" if the code is in the sheet module, else "ActiveSheet"
.Unprotect Password:=""
'arr(1) determines start row
'arr(2) determines # of rows
'arr(3) determines if rows are hidden or not
.Cells(arr(1), 1).Resize(arr(2), 1).EntireRow.Hidden = (arr(3) = "H")
.Protect Password:=""
End With
End If
End Sub`
My ranges are called :
Header:
RHEAD1
RHEAD2
Ranges:
RIVA1
RIVA2
RIVA3
.....
RIVA6
RMVA1
RMVA2
.....
RMVA12
Proposed name of button : btn_RHEAD1_RIVA1 or btn_RHEAD2_RMVA12
How can I run a macro from an application caller that performs the copying task ?
Thanks
Related
I have the following form:
When user clicks the "Submit Adjustment" button, I want the information in the yellow boxes (plus the date on that line) entered into the following table
Here's the code I'm using:
Sub LOG_CHG()
Sheets("ENTER CHG").Range("B8:I8").Copy
Sheets("CHANGE LOG").Cells(Rows.Count, "A").End(xlUp).Offset(1). _
PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
MsgBox ("Your adjustment has been logged.")
Range("C8:I8").Select
Selection.ClearContents
Range("C8").Select
End Sub
This is happening somewhat successfully, but sometimes it gets lost and pastes at the bottom of the table or in random places.
How can I make sure it pastes the information in the next available row?
Sheets("CHANGE LOG").Cells(Rows.Count, "A").End(xlUp).Offset(1)
This line means Excel is checking sheet "change log" from last Excel line in column A up until it finds any symbol in cell. And offset(1) means 1 row down. For example:
You have something written in A32(space, number or letter), but from A33 to A1000000+ row is nothing --> so your code will paste everything in A33.
In other words Select A1000000 and press Ctrl+UP.
As you are using a table on the log-sheet you can access it via the listobjectwhich is pretty easy to program against.
Public Sub log_chg()
Dim rgSource As Range
Set rgSource = ThisWorkbook.Worksheets("Enter chg").Range("B8:I8")
Dim loChangeLog As ListObject
Set loChangeLog = ThisWorkbook.Worksheets("Change log").ListObjects(1)
Dim lrTarget As ListRow
Set lrTarget = lo.ListRows.Add
lrTarget.Range.Value = rgSource.Value
End Sub
No need to check for the last row or anything.
ListRowis always appended to the end of the table.
As the ranges of the source and the target are of same size you can write the value like shown in the code.
What you should do before testing: delete all the empty rows of the log table.
I'm relatively new to VBA and have some code I wrote that seems like it should be straightforward but is not behaving as expected. I am trying to separate my primary WorkSheet (GAWi) into three other worksheets (LWi, WMi, & OTi) based on the first letter in column H. Basically if the first letter is "L" I want that row to be copied and pasted onto sheet LWi and then deleted from the original sheet. Then if it is W it goes onto WMi and if it is A it goes onto OTi. It is functioning properly for the first two If statements (placing items that begin with L & W onto the correct sheets), but for the last one items that begin with P and 0 are also being placed onto sheet OTi. I'm at a complete loss, it seems pretty easy and I can't figure out where I went wrong. Any advice would be much appreciated, also I'm sure this code is pretty unelegant by most standards so any tips on how to shorten it would also be welcomed-I've just started getting into VBA in the last couple weeks. Thank so much!
Sheets("GAWi").Select
Columns("H:H").Select
Dim lwr As Range
Set lwr = ActiveSheet.UsedRange
For i = lwr.Cells.Count To 1 Step -1
If Left(lwr.Item(i).Value, 1) = "L" Then
lwr.Item(i).EntireRow.copy
Sheets("LWi").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveCell.Offset(1, 0).Select
Sheets("GAWi").Select
lwr.Item(i).EntireRow.Delete
End If
If Left(lwr.Item(i).Value, 1) = "W" Then
lwr.Item(i).EntireRow.copy
Sheets("WMi").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveCell.Offset(1, 0).Select
Sheets("GAWi").Select
lwr.Item(i).EntireRow.Delete
End If
If Left(lwr.Item(i).Value, 1) = "A" Then
lwr.Item(i).EntireRow.copy
Sheets("OTi").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ActiveCell.Offset(1, 0).Select
Sheets("GAWi").Select
lwr.Item(i).EntireRow.Delete
End If Next i
there's a main flaw in your logic: the use of UsedRange
despite being it a 2D range, its Item() property would act as if it were a 1D array with one row listed after another
so that were "A1:H10" (eight columns) the address of UsedRange, UsedRange.Item(1) would point to "A1", UsedRange.Item(8) would point to "H1" and UsedRange.Item(9) would point to "A2" …
so you have to loop through the cells of column H only
Then there's a coding flaw, which is the use of all those Select/Selection: get in the habit of always use explicit range reference qualified up to their parent worksheet and workbook
. This can be reached, for instance, with the use of With... End With construct
here's a possible code (explanations in comments):
Option Explicit
Sub TransferRows()
Dim i As Long
With Sheets("GAWi") ' reference "source" sheet
For i = .Cells(.Rows.Count, "H").End(xlUp).Row To 1 Step -1 ' loop backwards from referenced sheet column H last not empty cell row index to 1
Select Case UCase(.Cells(i, "H").Value) ' check for referenced sheet column H current row content
Case "L"
TransferRow Intersect(.UsedRange, .Rows(i)), Sheets("LWi") ' pass referenced sheet current row "used" range and "LWi" destination sheet to the helper sub
Case "W"
TransferRow Intersect(.UsedRange, .Rows(i)), Sheets("WMi") ' pass referenced sheet current row "used" range and "WMi" destination sheet to the helper sub
Case "A"
TransferRow Intersect(.UsedRange, .Rows(i)), Sheets("OTi") ' pass referenced sheet current row "used" range and "OTi" destination sheet to the helper sub
End Select
Next i
End With
End Sub
Sub TransferRow(sourceRng As Range, destSht As Worksheet)
With destSht
.Cells(.Rows.Count, 1).End(xlUp).Offset(1).Resize(, sourceRng.Columns.Count).Value = sourceRng.Value
End With
sourceRng.Delete xlUp
End Sub
As you see, other than the amendements due to the preface explanations I put in there:
the use of Select Case syntax instead of If Then End If
which I think is much clearer and would also correct a minor logic flaw of your orginal code: once a check is positive there's no need to run other ones (this you could have obtained by means of If - Then - ElseIf - Endif construct)
the use of a "helper" sub to demand the repetitive code to
which gives you much more control over your code and helps its maintenance
the use of Cells(Rows.Count, colIndex).End(xlUp) pattern
which is the most frequently used one to get the reference to the last not empty cell in some colIndex (be it a number or a letter) column
Thanks to HTH's great response I was able to clean up my code a bit and think I got it figured out. I opted to stick with the If Then Else If format since I am not too familiar with using Case yet. Here's the first section of it, I just repeated the copy, paste, delete row for each starting letter.
Set rng = Range("GAWi!H:H")
For k = rng.Cells.Count To 1 Step -1
If Left(rng.Item(k).Value, 1) = "W" Then
With rng.Item(k)
.EntireRow.copy
Sheets("WMi").Activate
ActiveCell.Offset(1, 0).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
.EntireRow.Delete
End With
ElseIf Left(rng.Item(k).Value, 1) = "L" Then....
This is running well for my purposes but if anyone has more suggestions they are much appreciated.
I have an Export to sheet button but I can't get it working correctly.
I selects the correct cells to copy but can't then transpose them on to selected sheet that appears in the drop down box in cell A1, I then also need it to paste on the next available row in that specific sheet. The problem is that I can't just list the sheets in VBA as the list in the drop down box changes. I have tried several ways to with no success. If someone could help it would be great
Sub Button2_Click()
Worksheets("Sheet1").Range("a2:x2").Copy
ActiveSheet.Paste Destination:=Worksheets("Sheet1!A1").Range("a:x")
End Sub
Here is some more code I have tried for the issue but still does not seem to work.
Sub ExportButton1()
'
' ExportButton1 Macro
' Exports Data to staff sheet from drop down box
'
' Keyboard Shortcut: Ctrl+e
'
ActiveWorkbook.Save
End Sub
Private Sub CommandButton1_Click(ByVal Target As Range)
Application.ScreenUpdating = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = Worksheets("Data")
'On Error Resume Next
'If Not (Application.Intersect(Range("H2"), Target) Is Nothing) Then _
Set pasteSheet = Worksheets(ActiveSheet.Range("H2"))
copySheet.Range("G5:AA5").Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
you need to change the sheet name in your worksheet function.
This might work.
Sub Button2_Click()
'Copying the Data
Worksheets("Sheet1").Range("a2:x2").Copy
'Pasting the data
' What we were missing was to pass the name of the tab dynamically. Now this code will pick up the name that appears in the Cell A1.
ActiveSheet.Paste Destination:=Worksheets(Worksheets("Sheet1").Range("A1").value).Range("A1")
End Sub
Also in the paste range you only need to put the first cell range to paste values.
To paste the Transposed Values check the function PasteSpecial with Transpose property set to True.
'I have found another way around the problem to copy paste cells to certain sheet then on 'staff sheet a formula in a table to tests column A value on data sheet for name and only 'transpose those rows
Sub Macro1()
Range("A2:J2").Select
Selection.Copy
Sheets("Sheet3").Select
Range("A60000").End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Sheet1").Select
End Sub
'Formula on staff sheet is -=IF(Sheet3!A:A="Column1",Sheet3!$B:$B,"")
I have tried to frankenstein a solution from different threads but I am very much a newbie to VBA and programming, so it has not been going too well...
Here's some basic info:
I have 2 Sheets within the same workbook (Database and Data entry)
They contain the same headers, but are transposed (Database has the headers in the columns while Data entry has them in the rows)
Now, I am looking for 3 things (ideally in one compact solution)
Have a Command Button that copies and transposes the most recent range (leftmost column) from Data Entry to Database. (This is done in the code below)
This should be done depending on a certain cell value on the data entry sheet (ideally that cell could stay part of the copied range, however this is not crucial)
Delete the original range from the data entry sheet.
As I said I'm just starting to work with VBA so I am completely unsure how to go about this, I have attached what I gathered so far (excludes Nr.2 and feels very cumbersome overall). Any help is very much appreciated!
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim xSheet As Worksheet
Set xSheet = ActiveSheet
If xSheet.Name <> "Definitions" And xSheet.Name <> "fx" And xSheet.Name <> "Needs" Then
xSheet.Range("E6:E200").Copy
Worksheets("Sheet1").Range("E6:AZ6").PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
End If
Application.ScreenUpdating = True
End Sub
Check this one. It checks the value of E10. If it's "Y", then data is copied and deleted from original place. Otherwise, it shows a message to the user.
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim xSheet As Worksheet
Set xSheet = ActiveSheet
If xSheet.Name <> "Definitions" And xSheet.Name <> "fx" And xSheet.Name <> "Needs" Then
If xSheet.Range("E10")="Y"
xSheet.Range("E6:E200").Copy
Worksheets("Sheet1").Range("E6:AZ6").PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
xSheet.Columns("E").Delete
Else
MsgBox("Data entry not ready!")
End If
End If
Application.ScreenUpdating = True
End Sub
I have this macro which works ok on the first row, but once it has completed I want it to run again on the next row down and paste the result on the next row down on the "results" sheet and continue the process through the whole document until it reaches the last record - (there are approx. 5300 records in my spreadsheet)
Sub Macro2()
' Macro2 Macro
Range("A2:BW2").Select
Selection.Copy
Sheets("Lookup").Select
Range("F3").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("F3:V3").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Result").Select
Range("A2").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
So basically I am copying the first row of data on sheet named "amps_job_history", it them pastes this data into a sheet called "lookup", once the data is pasted there a formula does a calculation that marries the data up with data from another worksheet. I then want to copy the original data plus the extra 3 columns that have been connected to the data with the formulas and the paste it into the sheet called "result". I then want it to go back to the first sheet "amps_job_hisotry" move down to the next row of data and repeat the process and when it pastes the data into the "result" page it need to past on the next row down and so on and so on until it reaches the last record.
I think this loop is what you are looking for.
Sub Macro2()
' Macro2 Macro
Dim rw As Long
With Worksheets("amps_job_history")
For rw = 2 To .Cells(Rows.Count, "A").End(xlUp).Row
With Intersect(.Range("A:BW"), .Rows(rw))
Worksheets("Lookup").Range("F3").Resize(.Rows.Count, .Columns.Count) = .Value
End With
With Worksheets("Lookup")
With .Range("F3:V3")
Worksheets("Result").Range("A1").Offset(rw - 1, 0).Resize(.Rows.Count, .Columns.Count) = .Value
End With
End With
Next rw
End With
End Sub
The rows from the source data in the amps_job_history and the destination Result worksheet are shifted down one more row on each loop. The transitional F3:V3 range in the Lookup worksheet remains the same through out.
I've use direct value transfer rather than copy, paste special, values and the With ... End With statement provide explicit parent worksheet referencing without the use of the Range .Select or Range .Activate methods.