I have got a code to generate PowerPoint with an Excel file. I have mostly modified the code as per my requirement, but I want to add one more feature into my .ppt. I want VBA to extract Week Number from some source and do the following:
Rename my .ppt as "XXX_Weeknumber.ppt"
In one of the textboxes in the slides I want to add the same Weeknumber.
I tried getting the week number by using the function WeekNum and trying to call the function in my Main Sub but unfortunately doesn't work!
My code for function in Module 1:
Function WeekNum(D As Date) As Integer
WeekNum = CInt(Format(D, "ww", 2))
End Function
Code for the .xls to .ppt in Module 2:
Dim oPPTApp As PowerPoint.Application
Dim oPPTShape As PowerPoint.Shape
Dim oPPTShape2 As PowerPoint.Shape
Dim oPPTFile As PowerPoint.Presentation
Dim PPSlide As PowerPoint.slide
Dim SlideNum As Integer
Dim rng As Range
Dim WeekNumm$
Sub PPTableMacro()
Dim sourcexl As Workbook
Dim wk As Integer
Dim strPresPath As String, strExcelFilePath As String, strNewPresPath As String
strExcelFilePath = "C:\MySource.xls"
strPresPath = "C:\Presentation1.ppt"
Call WeekNum
WeekNumm = WeekNum()
Set wk = WeekNumm
strNewPresPath = "C:\Presentation1_" & wk & ".ppt" 'This is how I want the name
strNewPresPath = "C:\new1.ppt"
Set oPPTApp = CreateObject("PowerPoint.Application")
oPPTApp.Visible = msoTrue
Set oPPTFile = oPPTApp.Presentations.Open(strPresPath)
SlideNum = 2
oPPTFile.Slides(SlideNum).Select
Set oPPTShape = oPPTFile.Slides(SlideNum).Shapes("Table 1")
Set sourcexl = Workbooks.Open(strExcelFilePath) 'Source excel file
With sourcexl
.Sheets("Sheet1").Activate
oPPTShape.Table.Cell(1, 1).Shape.TextFrame.TextRange.Text = Cells(1, 1).Text
oPPTShape.Table.Cell(1, 2).Shape.TextFrame.TextRange.Text = Cells(1, 2).Text
oPPTShape.Table.Cell(1, 3).Shape.TextFrame.TextRange.Text = Cells(1, 3).Text
oPPTShape.Table.Cell(2, 1).Shape.TextFrame.TextRange.Text = Cells(2, 1).Text
oPPTShape.Table.Cell(2, 2).Shape.TextFrame.TextRange.Text = Cells(2, 2).Text
oPPTShape.Table.Cell(2, 3).Shape.TextFrame.TextRange.Text = Cells(2, 3).Text
End With
Set oPPTShape2 = oPPTFile.Slides(SlideNum).Shapes("TextBox 1")
Text1 = "weekXX" ' actually wanted week number here
oPPTShape2.TextFrame.TextRange.Text = Text1
oPPTFile.SaveAs strNewPresPath
'oPPTFile.Close
'oPPTApp.Quit
Set oPPTShape = Nothing
Set oPPTFile = Nothing
Set oPPTApp = Nothing
MsgBox "Presentation Created", vbOKOnly + vbInformation
End Sub
Your function asks for a data input ("D"), and it's not optional. If you want to retrieve the day of the week of today ("Date" system variable), you should call it like this:
WeekNumm = WeekNum(Date)
Also, you are using a Set statement in "Set wk = WeekNumm". As the variable isn't an object, you have to use (a preferably omitted) Let.
Also, your function will not return the day of the week, because "ww" means the week number of the year. If you want the day of the week by this approach, you have to use "w".
For a better approach, you should use the builtin function Weekday to get the weekday.
Like:
iWeekDay = Weekday(Date,vbUseSystemDayOfWeek) 'Retrieves today's day of the week (Tuesday = 3...)
Related
When I copy text from a cell in table using docCurrent.Tables(x).Cell(x, y).Range.Text, a new line is getting added along with the text in the cell.
The code I used is:
Sub tabele_trasfer()
'
' tabele_trasfer Macro
'
'
Dim docCurrent As Document
Dim docNew As Document
Dim myRange As Range
Set docCurrent = ActiveDocument
Set docNew = Documents.Add
Set myRange = docNew.Range(0, 0)
docNew.Tables.Add Range:=myRange, NumRows:=docCurrent.Tables(5).Rows.Count, NumColumns:=docCurrent.Tables(5).Columns.Count
For i = 1 To docCurrent.Tables(5).Rows.Count
docNew.Tables(1).Cell(Row:=i, Column:=1).Range.Text = docCurrent.Tables(5).Cell(i, 2).Range.Text
docNew.Tables(1).Cell(Row:=i, Column:=2).Range.Text = docCurrent.Tables(5).Cell(i, 2).Range.Text
Next i
End Sub
The reason is that the end of a table cell contains two characters: Chr(13) & Chr(7) - a paragraph mark and the end-of-cell marker. You can cut these off to retain only the text.
I've provided a function I use for this purpose that takes the cell Range and returns the string value, below. Here's one of your lines, altered to use the function
docNew.Tables(1).Cell(Row:=i, Column:=1).Range.Text = _
TrimCellText(docCurrent.Tables(5).Cell(i, 2).Range)
And the function
Function TrimCellText(r As word.Range) As String
Dim sLastChar As String
Dim sCellText As String
sCellText = r.Text
sLastChar = Right(sCellText, 1)
Do While sLastChar = Chr(7) Or sLastChar = Chr(13)
sCellText = Left(sCellText, Len(sCellText) - 1)
sLastChar = Right(sCellText, 1)
Loop
TrimCellText = sCellText
End Function
You seem to be populating both columns in the new document with the same data. Try:
Sub tabele_trasfer()
'
' tabele_trasfer Macro
'
'
Dim docCurrent As Document
Dim docNew As Document
Dim myRange As Range
Set docCurrent = ActiveDocument
Set docNew = Documents.Add
Set myRange = docNew.Range(0, 0)
docNew.Tables.Add Range:=myRange, NumRows:=docCurrent.Tables(5).Rows.Count, NumColumns:=docCurrent.Tables(5).Columns.Count
For i = 1 To docCurrent.Tables(5).Rows.Count
Set myRange = docCurrent.Tables(5).Cell(i, 2).Range
myRange.End = myRange.End - 1
docNew.Tables(1).Cell(i, 1).Range.Text = myRange.Text
docNew.Tables(1).Cell(i, 2).Range.Text = myRange.Text
Next i
End Sub
If populating both columns in the new document with the same data is not your intent, use:
Set myRange = docCurrent.Tables(5).Cell(i, 2).Range
myRange.End = myRange.End - 1
again to point to the correct source before outputting the second string.
For some reason every column with data is being stored into columnsToCopy and unionVariable. At the top levels in Locals, I can see that it recognizes the column I actually want, but when I go deeper into say Cells -> WorkSheet -> UsedRange -> Value2 it will now show that all columns in my workbook are stored. This is the piece of code that I have assigning columnsToCopy, all the way to assigning unionVariable and then Copying it:
checkOne = iq_Array(0)
hasIQs = Left(checkOne, 3) = "iq_"
Dim columnsToCopy As Collection
Set columnsToCopy = New Collection
If hasIQs Then
' paste inital column into temporary worksheet
columnsToCopy.Add ShRef.Columns(1)
End If
' loop for each iq_ in the array
For arrayLoop = LBound(iq_Array) To UBound(iq_Array)
' Take copy of potential ref and adjust to standard if required
checkStr = iq_Array(arrayLoop)
If hasIQs And Left(checkStr, 3) <> "iq_" Then checkStr = "iq_" & checkStr
' Look for existence of corresponding column in local copy array
pCol = 0
For iCol = 2 To colNumb
If checkStr = IQRef(iCol) Then
pCol = iCol
Exit For
End If
Next iCol
If pCol > 0 Then
' Paste the corresponding column into the forming table
columnsToCopy.Add ShRef.Columns(pCol)
End If
Next arrayLoop
If columnsToCopy.Count > 1 Then 'data was added
' Copy table
Dim unionVariable As Range
Set unionVariable = columnsToCopy(1)
For k = 2 To columnsToCopy.Count
Set unionVariable = xlApp.Union(unionVariable, columnsToCopy(k))
Next k
unionVariable.Copy ' all the data added to ShWork
The reason I'm looking into this, is because when I Union(unionVariable, columnToCopy(k)) I'm not getting something that would be equivalent to Range("A:A","D:D","Z:Z") , instead I'm getting Range("A:Z").
Any help is appreciated
My full code:
Option Explicit
Private Sub averageScoreRelay()
' 1. Run from PPT and open an Excel file
' 2. Start at slide 1 and find a box that contains the words "iq_", if it has those words then it will have numbers after it like so "iq_43" or "iq_43, iq_56,iq_72".
' 3. find those words and numbers in the opened Excel file after splitting and re-formating string.
' 3. Copy column into a new sheets and repeat for all "iq_'s" until sheets 2 has a table.
' 4. Copy table from xl Paste Table into ppt
' 5. Do this for every slide
'Timer start
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
'Create variables
Dim xlApp As Excel.Application
Dim xlWB As Excel.Workbook
Dim ShRef As Excel.Worksheet
Dim pptPres As Object
Dim colNumb As Long
Dim rowNumb As Long
' Create new excel instance and open relevant workbook
Set xlApp = New Excel.Application
'xlApp.Visible = True 'Make Excel visible
Set xlWB = xlApp.Workbooks.Open("C:\Users\Andre Kunz\Desktop\Gate\Macros\averageScores\pptxlpratice\dummy2.xlsx", True, False, , , , True, Notify:=False) 'Open relevant workbook
If xlWB Is Nothing Then ' may not need this if statement. check later.
MsgBox ("Error retrieving Average Score Report, Check file path")
Exit Sub
End If
xlApp.DisplayAlerts = False
'Find # of iq's in workbook
Set ShRef = xlWB.Worksheets("Sheet1")
colNumb = ShRef.Cells(1, ShRef.Columns.Count).End(xlToLeft).Column
rowNumb = ShRef.Cells(ShRef.Rows.Count, 1).End(xlUp).Row
Dim IQRef() As String
Dim iCol As Long
Dim IQRngRef() As Range
ReDim IQRef(colNumb)
ReDim IQRngRef(colNumb)
' capture IQ refs locally
For iCol = 2 To colNumb
Set IQRngRef(iCol) = ShRef.Range(ShRef.Cells(1, iCol), ShRef.Cells(rowNumb, iCol))
IQRef(iCol) = ShRef.Cells(1, iCol).Value
Next iCol
'Make pptPres the ppt active
Set pptPres = PowerPoint.ActivePresentation
'Create variables for the slide loop
Dim pptSlide As Slide
Dim Shpe As Shape
Dim pptText As String
Dim iq_Array As Variant
Dim arrayLoop As Long
Dim myShape As Object
Dim i As Long
Dim lRows As Long
Dim lCols As Long
Dim k As Long
'Loop through each pptSlide and check for IQ text box, grab avgScore values and create pptTable
For Each pptSlide In pptPres.Slides
i = 0
pptSlide.Select
'searches through shapes in the slide
For Each Shpe In pptSlide.Shapes
If Not Shpe.HasTextFrame Then GoTo nextShpe 'boom, one less nested If statement
If Not Shpe.TextFrame.HasText Then GoTo nextShpe ' boom, another nested If statement bites the dust
'Set pptText as the Text in the box, then make it lowercase and trim Spaces and Enters
pptText = Shpe.TextFrame.TextRange
pptText = LCase(Replace(pptText, " ", vbNullString))
pptText = Replace(Replace(Replace(pptText, vbCrLf, vbNullString), vbCr, vbNullString), vbLf, vbNullString)
'Identify if within text there is "iq_"
If InStr(1, pptText, "iq_") <= 0 Then GoTo nextShpe
'set iq_Array as an array of the split iq's
iq_Array = Split(pptText, ",")
Dim hasIQs As Boolean
Dim checkStr As String
Dim pCol As Long
Dim checkOne
checkOne = iq_Array(0)
hasIQs = Left(checkOne, 3) = "iq_"
Dim columnsToCopy As Collection
Set columnsToCopy = New Collection
If hasIQs Then
' paste inital column into temporary worksheet
columnsToCopy.Add ShRef.Columns(1)
End If
' loop for each iq_ in the array
For arrayLoop = LBound(iq_Array) To UBound(iq_Array)
' Take copy of potential ref and adjust to standard if required
checkStr = iq_Array(arrayLoop)
If hasIQs And Left(checkStr, 3) <> "iq_" Then checkStr = "iq_" & checkStr
' Look for existence of corresponding column in local copy array
pCol = 0
For iCol = 2 To colNumb
If checkStr = IQRef(iCol) Then
pCol = iCol
Exit For
End If
Next iCol
If pCol > 0 Then
' Paste the corresponding column into the forming table
columnsToCopy.Add ShRef.Columns(pCol)
End If
Next arrayLoop
If columnsToCopy.Count > 1 Then 'data was added
' Copy table
Dim unionVariable As Range
Set unionVariable = columnsToCopy(1)
For k = 2 To columnsToCopy.Count
Debug.Print k & " : " & unionVariable.Address & " + " & columnsToCopy(k).Address
Set unionVariable = xlApp.Union(unionVariable, columnsToCopy(k))
Debug.Print " --> " & unionVariable.Address
Next k
unionVariable.Copy ' all the data added to ShWork
tryAgain:
ActiveWindow.ViewType = ppViewNormal
ActiveWindow.Panes(2).Activate
Set myShape = pptSlide.Shapes.PasteSpecial(DataType:=ppPasteHTML, Link:=msoFalse)
On Error GoTo tryAgain
'Set position:
myShape.Left = -200
myShape.Top = 150 + i
i = i + 150
End If
nextShpe:
Next Shpe
nextSlide:
Next pptSlide
xlWB.Close
xlApp.Quit
xlApp.DisplayAlerts = True
'End Timer
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub
Output from Debugger:
2 : $A:$A + $B:$B
--> $A:$B
3 : $A:$B + $AF:$AF
--> $A:$B,$AF:$AF
2 : $A:$A + $C:$C
--> $A:$A,$C:$C
2 : $A:$A + $D:$D
--> $A:$A,$D:$D
3 : $A:$A,$D:$D + $L:$L
--> $A:$A,$D:$D,$L:$L
Here is another option doesn't have the additional overhead of creating a temporary workbook/worksheet.
Note: It may not be perfect -- in my testing it does not preserve cell background color but it does preserve text/font formats, and this appears consistent with the PasteSpecial(ppPasteHtml) method.
Note also: this assumes you can use a Table in PowerPoint to store the pasted data, and that all columns in your union range have the same number of rows. If you're just dumping the data in to a textbox or whatever sort of shape, this won't work.
But the idea is that once we have our "union", we can iterate over the Areas, and the Columns in each area, performing the Copy and Paste operation against each individual column.
Here is my data in Excel, I will create a union of the highlighted cells:
Here is the output in PowerPoint where I removed the borders from the table, note the text formatting preserved as well as cell alignment:
Option Explicit
Sub foo()
Dim ppt As PowerPoint.Application
Dim pres As PowerPoint.Presentation
Dim sld As PowerPoint.Slide
Dim shp As PowerPoint.Shape
Dim tbl As PowerPoint.Shape
Dim unionRange As Range
Dim ar As Range, c As Long, i As Long
Set unionRange = Union([A1:B2], [D1:D2], [F1:F2])
Set ppt = CreateObject("PowerPoint.Application")
ppt.Visible = True
Set pres = ppt.ActivePresentation
Set sld = pres.Slides(1)
' Create initial table with only 1 column
With unionRange
Set tbl = sld.Shapes.AddTable(.Rows.Count, 1)
End With
For Each ar In unionRange.Areas()
For c = 1 To ar.Columns.Count
i = i + 1
With tbl.Table
' Add columns as you iterate the columns in your unionRange
If .Columns.Count < i Then .Columns.Add
.Columns(i).Cells.Borders(ppBorderBottom).Transparency = 1
.Columns(i).Cells.Borders(ppBorderTop).Transparency = 1
.Columns(i).Select
ar.Columns(c).Copy '// Copy the column from Excel
ppt.CommandBars.ExecuteMso ("Paste") '// Paste the values to PowerPoint
End With
Next
Next
End Sub
Maybe more efficient to handle the Areas like so:
For Each ar In unionRange.Areas()
c = ar.Columns.Count
Dim tCol
tCol = .Columns.Count
With tbl.Table
' Add columns as you iterate the columns in your unionRange
While .Columns.Count < (tCol + c)
.Columns.Add
Wend
.Columns(tCol).Cells.Borders(ppBorderBottom).Transparency = 1
.Columns(tCol).Cells.Borders(ppBorderTop).Transparency = 1
.Columns(tCol).Select
ar.Copy '// Copy the columns in THIS Area object from Excel
ppt.CommandBars.ExecuteMso ("Paste") '// Paste the values to PowerPoint
End With
Next
But I still think performance on large data set will suffer vs the other answer.
The issue seems to be caused by the pasting of the non-contiguous range into PowerPoint.
I don't know enough PowerPoint VBA to know whether it has some other paste method you could use, but a work-around would be to create a new Excel worksheet containing just the info you want to copy, and then to copy that worksheet to PowerPoint:
'...
Next k
unionVariable.Copy ' all the data added to ShWork
'Create a temporary sheet (the workbook is being closed without saving
'so the temporary worksheet will be "lost" after we finish)
xlWB.Worksheets.Add Before:=xlWB.Worksheets(1)
'Paste the data into the temporary sheet
xlWB.Worksheets(1).Range("A1").PasteSpecial xlPasteValues
'Copy the temporary sheet
xlWB.Worksheets(1).UsedRange.Copy
tryAgain:
ActiveWindow.ViewType = ppViewNormal
'...
Hey I'm new to forums and this is my first post. I am new to vba in excel, but have written thinkscript in ThinkorSwim.
If anyone is familiar with a range stock chart, thats what Im going after.
I found code for a line chart, and am using it, but it is based on where price is at any given time. I want to modify this line chart to only plot values when they are above or below a range so that it resembles a candlestick chart with no wicks. Once data enters that range, I only want it to update whenever a new high or low is made in that range. The ranges need to be preset (ex. 50 ticks) Once the range is exceeded, I want the data plotted in the next range up, and repeat the process. Time and dates should be ignored, and only plot based on price action.
Does anyone have any ideas?
Option Explicit
'Update the values between the quotes here:
Private Const sChartWSName = "Chart"
Private Const sSourceWSName = "Sheet1"
Private Const sTableName = "tblValues"
Public RunTime As Double
Private Sub Chart_Setup()
'Create the structure needed to preserve and chart data
Dim wsChart As Worksheet
Dim lstObject As ListObject
Dim cht As Chart
Dim shp As Button
'Create sheet if necessary
Set wsChart = Worksheets.Add
wsChart.Name = sChartWSName
'Set up listobject to hold data
With wsChart
.Range("A1").Value = "Time"
.Range("B1").Value = "Value"
Set lstObject = .ListObjects.Add( _
SourceType:=xlSrcRange, _
Source:=.Range("A1:B1"), _
xllistobjecthasheaders:=xlYes)
lstObject.Name = sTableName
.Range("A2").NumberFormat = "h:mm:ss AM/PM (mmm-d)"
.Columns("A:A").ColumnWidth = 25
.Select
End With
'Create the chart
With ActiveSheet
.Shapes.AddChart.Select
Set cht = ActiveChart
With cht
.ChartType = xlLine
.SetSourceData Source:=Range(sTableName)
.PlotBy = xlColumns
.Legend.Delete
.Axes(xlCategory).CategoryType = xlCategoryScale
With .SeriesCollection(1).Format.Range
.Visible = msoTrue
.Weight = 1.25
End With
End With
End With
'Add buttons to start/stop the routine
Set shp = ActiveSheet.Buttons.Add(242.25, 0, 83.75, 33.75)
With shp
.OnAction = "Chart_Initialize"
.Characters.Text = "Restart Plotting"
End With
Set shp = ActiveSheet.Buttons.Add(326.25, 0, 83.75, 33.75)
With shp
.OnAction = "Chart_Stop"
.Characters.Text = "Stop Plotting"
End With
End Sub
Public Sub Chart_Initialize()
'Initialize the routine
Dim wsTarget As Worksheet
Dim lstObject As ListObject
'Make sure worksheet exists
On Error Resume Next
Set wsTarget = Worksheets(sChartWSName)
If Err.Number <> 0 Then
Call Chart_Setup
Set wsTarget = Worksheets(sChartWSName)
End If
On Error GoTo 0
'Check if chart data exists
With Worksheets(sChartWSName)
Set lstObject = .ListObjects(sTableName)
If lstObject.ListRows.Count > 0 Then
Select Case MsgBox("You already have data. Do you want to clear it and start fresh?", vbYesNoCancel, "Clear out old data?")
Case Is = vbYes
'User wants to clear the data
lstObject.DataBodyRange.Delete
Case Is = vbCancel
'User cancelled so exit routine
Exit Sub
Case Is = vbNo
'User just wants to append to existing table
End Select
End If
'Begin appending
Call Chart_AppendData
End With
End Sub
Private Sub Chart_AppendData()
'Append data to the chart table
Dim lstObject As ListObject
Dim lRow As Long
With Worksheets(sChartWSName)
Set lstObject = .ListObjects(sTableName)
If lstObject.ListRows.Count = 0 Then
lRow = .Range("A1").End(xlDown).Row
End If
If lRow = 0 Then
lRow = .Range("A" & .Rows.Count).End(xlUp).Offset(1, 0).Row
End If
If lRow > 2 Then
If .Range("B" & lRow - 1).Value = Worksheets(sSourceWSName).Range("C10").Value Then
'Data is a match, so do nothing
Else
'Data needs appending
.Range("A" & lRow).Value = CDate(Now)
.Range("B" & lRow).Value = Worksheets(sSourceWSName).Range("C10").Value
End If
Else
'Data needs appending
.Range("A" & lRow).Value = CDate(Now)
.Range("B" & lRow).Value = Worksheets(sSourceWSName).Range("C10").Value
End If
End With
RunTime = Now + TimeValue("00:00:01")
Application.OnTime RunTime, "Chart_AppendData"
End Sub
Public Sub Chart_Stop()
'Stop capturing data
On Error Resume Next
Application.OnTime EarliestTime:=RunTime, Procedure:="Chart_AppendData", Schedule:=False
End Sub
Take your sheet of data and filter... example would be:
Columns("A:C").Sort key1:=Range("C2"), _
order1:=xlAscending, header:=xlYes
Sort info: https://msdn.microsoft.com/en-us/library/office/ff840646.aspx
You then can define to select your desired range. Assuming column A is x-axis and B is y-axis (where your parameters for modifying need to be assessed):
Dim High1 as integer
Dim Low1 as integer
High1 = Match(Max(B:B),B:B) 'This isn't tested, just an idea
Low1 = Match(Max(B:B)+50,B:B) 'Again, not tested
and using those defined parameters:
.Range(Cells(High1,1),Cells(Low1,2).Select
This should give an idea for High1/Low1, where you can work through how you want to define the row that the max value occurs.
You then CreateObject for the Chart you want, having selected the data range you are going to use.
I need to call a word file from excel, and to create a template. Template will have 3 images UpperLeft, Upper Right and central image.
I thought that would be the best result do it through the table.
From some reason I can't create table from excel..
Private Sub CommandButton13_Click()
'Using early binding, not late-binding
Dim wsDoc As Word.Document
Dim wsApp As Word.Application
Dim wsRng As Word.Range
Dim wsTable as Word.Table
Dim intNoOfRows
Dim intNoOfColumns
Dim s As Word.InlineShape
Dim shp As Word.Shape
intNoOfRows = 4
intNoOfColumns = 2
Set wsApp = New Word.Application
wsApp.Visible = True
Set wsDoc = wsApp.Documents.Add
Set wsRange = wsDoc.Content
Set wsTable = wsDoc.Tables.Add(wsRange, intNoOfRows, intNoOfColumns)
wsTable.Borders.Enable = True
wsTable.Cell(1, 1).Range.InlineShapes.AddPicture _
UserForm1.txtImageLogoAdecco
wsTable.Cell(1, 2).Range.ParagraphFormat.Alignment = wdAlignParagraphRight
wsTable.Cell(1, 2).Range.InlineShapes.AddPicture _
UserForm1.txtImageLogoClient
Set wsRng = wsTable.Cell(2, 1).Range
With wsRng.Paragraphs.Add
wsTable.Cell(2, 1).Merge MergeTo:=wsTable.Cell(2, 2)
wsTable.Cell(2, 1).Height = 520
wsTable.Cell(2, 1).Range.Paragraphs.Add
wsTable.Cell(3, 1).Merge MergeTo:=objTable.Cell(3, 2)
wsTable.Cell(3, 1).Range.Text = "Prepared by:" & " " & UserForm1.txtPrepared
wsTable.Cell(4, 1).Merge MergeTo:=objTable.Cell(4, 2)
wsTable.Cell(4, 1).Range.ParagraphFormat.Alignment = wdAlignParagraphRight
wsTable.Cell(4, 1).Range.Text = "Belgrade," & " " & Format(Date, "MMMM DD, YYYY ")
Set wsRange = Nothing
Set wsTable = Nothing
Set wsDoc = Nothing
Set wsApp = Nothing
End Sub
Well, it's a bit clearer, but not completely. I've taken the liberty of editing your code so that it's correct, consistent and readable (without all the empty lines)!
I'll start with the part that is clear: << I want to move cursor a few lines down and to write some text. >>
To move the focus below a table, you get the table's range, then collapse it. For example:
Set wsRange = wsTable.Range
wsRange.Collapse wdCollapseEnd
'Now the range is in the paragraph following the table
wsRange.Text = "text following table"
"with background image I want to convert it to shape. I want to send iy behind the text"
This is the part that's not clear to me. Are you saying you want to insert one more image and position it behind the text? Use the Shapes.Add method and set the WrapFormat.Type to wdWrapBehind
Hi,
I have enclosed the sheet image.
My requirement is:
I want to get all the "G" column values for the organization matching to a specific organization name (Ex:360 evaluations).
I am getting null value after first loop for the G Column
Sub UsageWeekTrend()
Dim customerName As String
Dim sheetName As String
Dim dataFound As Boolean
Dim selectedCell As Range
Dim rowNumber As Integer
Dim weekMinutes As Double
Dim trendsFile As Workbook
Dim trendsSheet As Worksheet
On Error GoTo errorHandling
sheetName = ActiveSheet.Name
customerName = ActiveSheet.Range("A" & (ActiveCell.row)).Value
dataFound = False
For Each selectedCell In ActiveSheet.Range("A1:A1000")
If UCase(selectedCell.Value) = UCase(customerName) Then
weekMinutes = ActiveSheet.Range("G" & selectedCell.row).Value
Debug.Print weekMinutes
Debug.Print "G" & selectedCell.row
If dataFound = False Then
If trendsFile Is Nothing Then
Set trendsFile = Workbooks.Add()
trendsFile.Activate
Set trendsSheet = trendsFile.ActiveSheet
Else
' add a new sheet to the trends workbook
trendsFile.Activate
Set trendsSheet = Sheets.Add
End If
dataFound = True
rowNumber = 1
trendsSheet.Name = Left(customerName, 10) + " " + Format(Date, "MMDD")
trendsSheet.Cells(rowNumber, 1) = "Users"
trendsSheet.Cells(rowNumber, 2) = "Minutes"
rowNumber = rowNumber + 1
End If
' if a sheet has been created, then we have at least one non-zero value so add data
If dataFound = True Then
trendsSheet.Cells(rowNumber, 1) = customerName
trendsSheet.Cells(rowNumber, 2) = weekMinutes
rowNumber = rowNumber + 1
End If
End If
Next selectedCell
' if we have data, create the chart
If dataFound = True Then
' make sure the trends sheet is active for chart insertion
trendsSheet.Activate
Dim chtChart As ChartObject
Dim chartName As String
Dim endRange As String
' define the end of the range for the chart
endRange = "C" & CStr(rowNumber - 1)
' add chart to current sheet
Set chtChart = ActiveSheet.ChartObjects.Add(Left:=200, Top:=200, Width:=900, Height:=400)
chtChart.Activate
ActiveChart.ChartType = xlLineStacked
ActiveChart.SetSourceData Source:=trendsSheet.Range("A2", endRange)
ActiveChart.HasTitle = True
ActiveChart.ChartTitle.Text = customerName
ActiveChart.ApplyLayout (5)
Else
MsgBox ("No usage data found for customer " + customerName)
End If
Exit Sub
errorHandling:
MsgBox (Err.Description)
End Sub
When you run this line:
trendsFile.Activate
You change the Activesheet, so the 2nd time on the loop you again look at the activesheet
weekMinutes = ActiveSheet.Range("G" & selectedCell.row).Value
but the activesheet has changed. I would change those Activesheet calls to a worksheet object that you assign at the top.
This is always a good read for those new to VBA programming: How to avoid using Select in Excel VBA macros
The issue is that you're using ActiveSheet, and the active sheet is being changed in your code.
As soon as trendsFile.Activate is executed, these two references will have new meanings ActiveSheet.Range("A1:A1000") and ActiveSheet.Range("G" & selectedCell.row).Value.
You've created workbook & worksheet variables for your Trends file, and use those, you also need to create a worksheet variable for your "source" worksheet (not sure how you'd refer to it).
Also, I'd be a bit concerned about this section of code:
If trendsFile Is Nothing Then
Set trendsFile = Workbooks.Add()
trendsFile.Activate
Set trendsSheet = trendsFile.ActiveSheet
Else
' add a new sheet to the trends workbook
trendsFile.Activate
Set trendsSheet = Sheets.Add
End If
I believe you'll be adding a new sheet every time through the loop.
Try something like this:
Sub UsageWeekTrend()
Dim customerName As String
Dim sheetName As String
Dim dataFound As Boolean
Dim selectedCell As Range
Dim rowNumber As Integer
Dim weekMinutes As Double
Dim trendsFile As Workbook
Dim trendsSheet As Worksheet
Dim SourceSheet as worksheet 'this is the place where you start, call it what you will
On Error GoTo errorHandling
set SourceSheet = activesheet 'this will now always be THIS sheet, and won't change
sheetName = SourceSheet.Name
customerName = SourceSheet.Range("A" & (ActiveCell.row)).Value
dataFound = False
For Each selectedCell In SourceSheet.Range("A1:A1000")
If UCase(selectedCell.Value) = UCase(customerName) Then
weekMinutes = SourceSheet.Range("G" & selectedCell.row).Value
Debug.Print weekMinutes
Debug.Print "G" & selectedCell.row
If dataFound = False Then
If trendsFile Is Nothing Then
Set trendsFile = Workbooks.Add()
'trendsFile.Activate - never needed
Set trendsSheet = trendsFile.Sheets("Sheet1") 'use the first sheet, since you just created a brand new workbook
Else
' add a new sheet to the trends workbook
'trendsFile.Activate -- you never need this when you're working with an object instead of "Active"
'you'll find that this line will add a new sheet every time you execute the loop
'once you've created your "trendsFile" workbook. you'll need to do some tweaking here
'to prevent you getting one loop worth of data on each sheet
Set trendsSheet = Sheets.Add
End If
dataFound = True
rowNumber = 1
trendsSheet.Name = Left(customerName, 10) + " " + Format(Date, "MMDD")
trendsSheet.Cells(rowNumber, 1) = "Users"
trendsSheet.Cells(rowNumber, 2) = "Minutes"
rowNumber = rowNumber + 1
End If
' if a sheet has been created, then we have at least one non-zero value so add data
If dataFound = True Then
trendsSheet.Cells(rowNumber, 1) = customerName
trendsSheet.Cells(rowNumber, 2) = weekMinutes
rowNumber = rowNumber + 1
End If
End If
Next selectedCell
'The rest of your routine here...
End Sub