Copying MSProject information to Excel - excel

I have a macro-enabled Excel workbook that opens a series of MSProject files, applies filters to a specific column, and copies portions of the visible range to Excel. The code for the copy action looks like this:
For Each Task In ActiveSelection.Tasks
If Not Task Is Nothing Then
TargetWS.Cells(Row, 3) = Task.PercentComplete / 100
TargetWS.Cells(Row, 4) = Task.Name
TargetWS.Cells(Row, 5) = Task.Start
TargetWS.Cells(Row, 6) = Task.Finish
TargetWS.Cells(Row, 7) = Task.BaselineFinish
Row = Row + 1
End If
Next Task
Essentially, I am looping through every row in the filtered range and copying each column one at a time. As you can imagine, this takes a long time.
My hope is to replace this iterative method with the standard set of actions I would use in Excel VBA: define first & last rows, then use one copy action for each column I want. This would greatly reduce the number of copy actions required to complete the task, which should provide a speed increase.
In Excel VBA, the code I want would look something like this, having defined the last row:
TargetWS.Range("A2:" & LastRow).Copy Destination:= (destination cells)
I know how to find the last visible task in Project, but am unfamiliar with range selection. Could someone fill in the gaps?
Thanks!

Your current method takes a sound approach, so instead of changing the method, try improving the performance.
The slowest part of your code right now isn't that you are looping through the tasks one-by-one, it's that you are writing to Excel cell-by-cell. The first step you can take is to write all data for a single task at one:
TargetWS.Range("C" & Row & ":G" & Row) = Array(Task.PercentComplete / 100, _
Task.Name, Task.Start, Task.Finish, _
Task.BaselineFinish)
Once you are comfortable with that, then you can move on to writing blocks of data at a time. To do this, store the data in a 2-dimensional array and only write it to Excel when you are done looping through the tasks. (Note, if you have many thousands of tasks, you may need to write the data in smaller chunks.)
Also, make sure you have turned calculation off in Excel. This will improve performance as can turning off screen updates. Just make sure you reset both application settings when your code is completed (even it if finishes with an error).
One last tip, avoid naming variables the same as objects (e.g a Task object named Task).

Related

Deleting Entire rows where Range Selection is blank (Without looping)

As the title says, It seems obvious but I can't seem to find a one-liner to it without looping. Is there a method able to do this task with a fast execution time ?
Here is my failed attempt (It crashes my excel file) :
Worksheets("Iso_Journal").Range("A:P").EntireRow.SpecialCells(xlBlanks).EntireRow.Delete
Any knowledge would be appreciated !
Edit:
Found this method but it filters instead of deleting (much faster), it does the job but it still not what I truly need
Worksheets("Iso_Journal").Range("A:P").AutoFilter Field:=1, Criteria1:="<>"
Edit 2: (Response to #FaneDuru)
Please, try the next adapted code. If the target is to delete all empty ROWS, it is enough to use a single column. And also to limit the number of rows to be processed:
Dim wsJ As Worksheet
Set wsJ = Worksheets("Iso_Journal")
wsJ.Range("A1:A" & wsj.Range("A" & wsJ.rows.count).End(xlup).row).SpecialCells(xlBlanks).EntireRow.Delete
If the range to be processed is huge, and the workbook contains many formulas, you can make the code a little faster placing Application.Calculation = xlCalculationManual before the deletion line, followed by Application.Calculation = xlCalculationAutomatic. Even if the rows are deleted in block, Excel needs to update the formulas row by row, and no good to calculate after each...

Using variables to select a range of cells

I'm trying to make a section of a small macro in Excel that copies info from some inputs between cells AE13 and AI13. The thing is that I want to make it so that the next row is selected by Excel once the program does its thing (so, once the program copies the content for AE13:AI13 and does some processing, it'll jump to copy the contents of AE14:AE14 and so on as long as it encounters data (for this example, let that be until the variable I'm using reaches 20)). For this I'm doing the following:
Do while Active < 20
Active = 13
'The code that does the cleanup from the prior run goes here
Range("AE" & Active & ":AI" & Active).Select
Selection.Copy
'Then here goes the rest code that does the actual program, which has been running fine prior to implementing this "Active" variable (which is not used anywhere else in the code).
Active = Active + 1
Loop
To me that's how it's supposed to go, but when I try to run this, Excel selects rows AE:AI, it activates all the cells in those columns instead of the ones in the row I'm specifying.
Could anyone help me see if I'm doing something wrong?
Kudos from a ramdon, troubled gen z trying to survive in the workplace.

How to copy specific parts of a table from a sheet to another

I'm trying to get some details copied in Excel from Sheet 1 columns 1-5 to Sheet 2 columns 1-4, but only for lines that include text or values on sheet one under a specific column (in this case, Column 2). There are other columns in between, so I need to be able to use exact columns rather than A:D for example.
Example of what I'm trying to achieve:
I have tried using a simple IF function with A:A<>"" so it would include any rows that have any data in them, however this does not seem to copy as I need and occasionally based on my attempts i also get circular reference errors. Additionally, I’m not sure how to make sure this gets pasted at the bottom of a table that will expand with each addition.
I realize a probably easier option would be to simply copy Sheet 1 entirely and use a filter on row 1 to deselect Blanks on A:A, but the sheet has so much more info that it would be a waste, and additionally info is constantly added so I need something scale-able. It also occurred to me now that by doing this i would include info from the "header" and "footer", basically a frozen pane - which I do not need.
Could this be done via a simple function, or would it require a Macro?
Please keep in mind I'm rubbish at programming, just trying to make my life easier and learn as I go. A lot of excel forums help but still I'm no coder. I can understand to a pretty big degree what the code does and can adjust accordingly though :)
As suggested, this cannot be done with formulas. There are different ways to achieve this.. below is one approach:
Sub CopyFilteredRows()
Dim oSourceSheet As Worksheet: Set oSourceSheet = ThisWorkbook.Worksheets("Sheet3") ' Set your source sheet here
Dim oRng As Range: Set oRng = oSourceSheet.Range("A2:E" & oSourceSheet.Range("C" & oSourceSheet.Rows.Count).End(xlUp).Row)
' Set filter on column B
oRng.AutoFilter
oRng.AutoFilter 2, "<>"
' Copy to specified sheet
oRng.SpecialCells(xlCellTypeVisible).EntireRow.Copy ThisWorkbook.Worksheets("Sheet4").Range("A2") ' Change your destination sheet here
' Clear objects
Set oRng = Nothing
Set oSourceSheet = Nothing
End Sub
Paste the above UDF in a Module and then run it whenever you want to perform the copy. I suspect you would have to modify it a bit so that you can cater for your particular scenario but it should give you a start

Macro Code to delete rows untill defined column

How do I limit a Macro to function only within certain range let's say until certain column?
I have a case where macro needs to delete the rows based on condition. I also want to put some instructions on the right and a form control button for macro but it seems like every time the code is activated, it deletes everything in that row, including the instructions and button I made. So I want to define a range where macro should be active.
I have following logic active.
First flag the item to be checked.
In loop, keep checking and deleting the rows.
Delete the rows based on an extra condition.
The code is working fine, but I want to add limitation until certain column like said.
Where do i define the range? In three separate logic, or at once on top?
Any help would be appreciated.
BR,
Manny
It sounds like you have told your code to delete the entire row. If you only want the macro to delete the data in columns A to G, for example, then use code along the lines of
Range("A" & rownumber & ":G" & rownumber).Delete Shift:=xlUp
you need to replace the line of code that deletes the whole row with code that deletes only set range. So for example instead of
Rows("12:12").Delete Shift:=xlUp
you will have
Range("A12:N12").Delete Shift:=xlUp

Simulate paste action in excel using vba

I am trying to populate an excel spreadsheet using VBA (is actually something different using a COM server but it is the same syntax). Thisis a report generated that I want to write in Excel for formatting and presentation purpose. CSV exports and other techniques are out of the equation because of the technology involved.
So, I am able to do it writing each value in each cell, but it is painfully slow, so, I decided I could write a bunch of values at once (let's say 250 records each time). So I store those values delimited by a carriage return and if I copy/paste that using VBA it works perfectly.
Problem is, I can't use the clipboard (as the report is executed many times simultaneously), so can I simulate the paste action (or some other similar) from a list of values in Excel without using the clipboard?
Thanks,
The fastest way to copy values in VBA I know is
Range("destrange") = Range("srcrange")
destrange and srcrange should be the same size. Also no formatting data etc. will be copied.
edit: here is something that could be usefull.
You can create an array of Variants and assign it to a range:
Dim v() As Variant
ReDim v(1 To 20, 1 To 10)
'Fill v
v(5, 5) = 42
'...
Range("a1:j20").Value = v

Resources