Concatenating text and preserving conditional formatting as static - vba

I have a table with two rows that have conditional formating in them (rules like if lower than then colour text). I need to concatenate those two rows and preserve formatting from each row separately. Due to this I can't just concatenate values and paste formats as it will apply conditional formatting to the whole text and not just the parts of it.
I have searched for solution and found that you can convert conditional formatting to static formatting by using Range.DisplayFormat property. In my code I am basically going by each character
and copying DisplayFormat from source cell (with conditional formatting) and using the same font, size, bold and color on characters in my target range.
The result should look like this:
Unfortunately, I am getting just a concatenated string without formatting. Do you know a better way to achieve what I need? Or could you help me with fixing the existing code.
Sub Merge_Cells()
Dim i As Integer
Dim rngFrom1 As Range
Dim rngFrom2 As Range
Dim rngTo As Range
Dim lenFrom1 As Integer
Dim lenFrom2 As Integer
Set rngFrom1 = Cells(59, 1) 'first row
Set rngFrom2 = Cells(60, 1) 'second row
Set rngTo = Cells(64, 1)
lenFrom1 = Len(rngFrom1)
lenFrom2 = Len(rngFrom2)
rngTo.Value = rngFrom1.Text & " " & rngFrom2.Text 'concatenating text
For i = 1 To lenFrom1
With rngTo.Characters(i, 1).Font
.Name = rngFrom1.DisplayFormat.Characters(i, 1).Font.FontStyle
.Bold = rngFrom1.DisplayFormat.Characters(i, 1).Font.Bold
.Size = rngFrom1.DisplayFormat.Characters(i, 1).Font.Size
.ColorIndex = rngFrom1.DisplayFormat.Characters(i, 1).Font.ColorIndex
End With
Next i
For i = 1 To lenFrom2
'start from character that is after space
With rngTo.Characters(lenFrom1 + 1 + i, 1).Font
.Name = rngFrom2.DisplayFormat.Characters(i, 1).Font.Name
.Bold = rngFrom2.DisplayFormat.Characters(i, 1).Font.Bold
.Size = rngFrom2.DisplayFormat.Characters(i, 1).Font.Size
.ColorIndex = rngFrom2.DisplayFormat.Characters(i, 1).Font.ColorIndex
End With
Next i
End Sub

I have partly achieved what I wanted by copying my source range with all the conditional formatting to Word and pasting it back to Excel to another range. This way the formatting was preserved but there were no rules for conditional formatting and all the font parameters were readable by my macro. Only problem is when using non-standard colours as they are different in Excel and Word (for example red turns to pink)
Sub Merge_Cells()
Dim i As Integer
Dim rngFrom1 As Range
Dim rngFrom2 As Range
Dim rngTo As Range
Dim lenFrom1 As Integer
Dim lenFrom2 As Integer
Dim objWord As Object
Dim objDoc As Object
Dim rngcopy As Range
Dim ws As Worksheet
Set ws = Sheets("test")
ws.Visible = True
ws.Activate
Set rngcopy = Range("C51", "C53")
rngcopy.Select
' Copy Excel Selection
Selection.Copy
' Create new Word Application
Set objWord = CreateObject("Word.Application")
objWord.Visible = False
' Create new Word Document
Set objDoc = objWord.Documents.Add(Template:="Normal", NewTemplate:=False, DocumentType:=0)
' Paste Excel range into Word document
objWord.Selection.PasteExcelTable False, False, True
' Copy text from cells
If objDoc.Tables.Count >= 1 Then
objDoc.Tables(1).Select
objWord.Selection.Copy
End If
' Close Microsoft Word and not save changes
objWord.Quit False
Set objWord = Nothing
'Paste it back to Excel
ws.Range("C58").Activate
ws.Paste
'Old code
Set rngFrom1 = Cells(59, 3) 'first row
Set rngFrom2 = Cells(60, 3) 'second row
Set rngTo = Cells(64, 3)
lenFrom1 = Len(rngFrom1)
lenFrom2 = Len(rngFrom2)
rngTo.Value = rngFrom1.Text & " " & rngFrom2.Text 'concatenating text
For i = 1 To lenFrom1
With rngTo.Characters(i, 1).Font
.Name = rngFrom1.DisplayFormat.Characters(i, 1).Font.FontStyle
.Bold = rngFrom1.DisplayFormat.Characters(i, 1).Font.Bold
.Size = rngFrom1.DisplayFormat.Characters(i, 1).Font.Size
.ColorIndex = rngFrom1.DisplayFormat.Characters(i, 1).Font.ColorIndex
End With
Next i
For i = 1 To lenFrom2
'start from character that is after space
With rngTo.Characters(lenFrom1 + 1 + i, 1).Font
.Name = rngFrom2.DisplayFormat.Characters(i, 1).Font.Name
.Bold = rngFrom2.DisplayFormat.Characters(i, 1).Font.Bold
.Size = rngFrom2.DisplayFormat.Characters(i, 1).Font.Size
.ColorIndex = rngFrom2.DisplayFormat.Characters(i, 1).Font.ColorIndex
End With
Next i
End Sub

Related

I want to copy all highlighted and shaded text from Word file to Excel along with the colors through VBA

I want to copy all Highlighted and Shaded text from Word file to Excel with same color in Word file through VBA.
I was able to copy only highlighted text from word to word. But the actual task is to copy all highlighted and shaded text to Excel and sort all the data according to color in Excel.
I use this code and it works fine to just copy from word to word but there is no formatting this code copies only text no colors;
Sub ExtractHighlightedText()
Dim oDoc As Document
Dim s As String
With Selection
.HomeKey Unit:=wdStory
With .Find
.ClearFormatting
.Text = ""
.Highlight = True
Do While .Execute
s = s & Selection.Text & vbCrLf
Loop
End With
End With
Set oDoc = Documents.Add
oDoc.Range.InsertAfter s
End Sub
Code for converting from Shaded to Highlighted:
Sub ConvertTextsFromShadedToHighlighted()
Dim objParagraph As Paragraph
Dim objCharacterRange As Range
For Each objParagraph In ActiveDocument.Paragraphs
If objParagraph.Range.Information(wdWithInTable) = False Then
If objParagraph.Range.Shading.BackgroundPatternColor <> wdColorAutomatic
Then
objParagraph.Range.Shading.BackgroundPatternColor = wdColorAutomatic
objParagraph.Range.HighlightColorIndex = wdPink
End If
End If
Next objParagraph
For Each objCharacterRange In ActiveDocument.Characters
if objCharacterRange.Font.Shading.BackgroundPatternColor <>
wdColorAutomatic Then
objCharacterRange.Font.Shading.BackgroundPatternColor = wdColorAutomatic
objCharacterRange.HighlightColorIndex = wdPink
End If
Next objCharacterRange
End Sub
May try something like this
Edit: Tried to include Extraction of Shaded text (Any color) along with Highlighted text by using tow finds. Following workaround methods are adopted
For finding Shaded text (of any color) find is executed for .Font.Shading.BackgroundPatternColor = wdColorAutomatic and the range excluding that selection was picked up as shaded text and color. Method somehow crudely performing when selection contain pure text characters but still picking up wrong color value when selection contain non text characters (i.e. paragraph marks etc). Otherwise it is working up to expectation. Otherwise there is always another option open to iterate through all the characters in the documents. But that option was left out as it is very slow and impractical for large documents.
As no simple method (or property) found by me to convert HighlightColorIndex to RGB color value, The same was applied to one character's Font.ColorIndex and later extracted as Font.Color
So finally the solution become messy and somehow crude, I am not at all satisfied with and more answers are invited from experts for simple direct solutions in these regards.
Code:
Option Explicit
Sub ExtractHighShadeText()
Dim Exc As Excel.Application
Dim Wb As Excel.Workbook
Dim Ws As Excel.Worksheet
Dim s As String, Rw As Long
Set Exc = CreateObject("Excel.Application")
Exc.Visible = True
Set Wb = Exc.Workbooks.Add
Set Ws = Wb.Sheets(1)
Rw = 0
Dim Rng As Range, StartChr As Long, EndChr As Long, OldColor As Long, Clr As Long
''''''''''''''''''''HiLight''''''''''''''''''
Set Rng = ActiveDocument.Characters(1)
OldColor = Rng.Font.Color
Selection.HomeKey Unit:=wdStory
With Selection.Find
.ClearFormatting
.Text = ""
.Highlight = True
Do While .Execute
'These two line Converting HighlightColorIndex to RGB Color
Rng.Font.ColorIndex = Selection.Range.HighlightColorIndex
Clr = Rng.Font.Color
Rw = Rw + 1
Ws.Cells(Rw, 1).Value = Selection.Text
'Ws.Cells(Rw, 1).Interior.ColorIndex = Selection.Range.HighlightColorIndex
Ws.Cells(Rw, 1).Interior.Color = Clr
'For sorting on HighlightColorIndex
'Ws.Cells(Rw, 2).Value = Selection.Range.HighlightColorIndex
'For sorting on HighlightColorIndex RGB value
Ws.Cells(Rw, 2).Value = Clr
Loop
End With
Rng.Font.Color = OldColor
'''End Hilight''''''''''''''''''''''''''''''
'WorkAround used for converting highlightColorIndex to Color RGB value
StartChr = 1
EndChr = 0
Set Rng = ActiveDocument.Characters(1)
Selection.HomeKey Unit:=wdStory
With Selection.Find
.ClearFormatting
.Text = ""
'.Highlight = True
.Font.Shading.BackgroundPatternColor = wdColorAutomatic
Do While .Execute
EndChr = Selection.Start
Debug.Print Selection.Start, Selection.End, StartChr, EndChr, IIf(EndChr > StartChr, "-OK", "")
If EndChr > StartChr Then
Set Rng = ActiveDocument.Range(Start:=StartChr, End:=EndChr)
Clr = Rng.Font.Shading.BackgroundPatternColor
Rw = Rw + 1
Ws.Cells(Rw, 1).Value = Rng.Text
Ws.Cells(Rw, 1).Interior.Color = Clr
Ws.Cells(Rw, 2).Value = Clr
End If
StartChr = Selection.End
Loop
If EndChr > StartChr Then
Set Rng = ActiveDocument.Range(Start:=StartChr, End:=EndChr)
Clr = Rng.Font.Shading.BackgroundPatternColor
Rw = Rw + 1
Ws.Cells(Rw, 1).Value = Rng.Text
Ws.Cells(Rw, 1).Interior.Color = Clr
Ws.Cells(Rw, 2).Value = Clr
End If
End With
If Rw > 1 Then
Ws.Range("A1:B" & Rw).Sort Key1:=Ws.Range("B1"), Order1:=xlAscending, Header:=xlNo
Ws.Range("B1:B" & Rw).ClearContents
End If
End Sub

new line is getting added in table().cell().range.text in word macro

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.

Run Time Error '1004': Paste Method Of worksheet Class Failed error

Copy pasting 1 line of text from word to excel using VBA.
When the code reaches the below line I am getting the below error.
ActiveSheet.Paste
Run Time Error '1004': Paste Method Of worksheet Class Failed error
But if I click Debug button and press F8 then it's pasting the data in excel without any error.
This error occurs each time the loop goes on and pressing debug and F8 pasting the data nicely.
I did several testing and unable to find the root cause of this issue.
Also used DoEvents before pasting the data code but nothing worked.
Any suggestions?
EDIT:-
I am posting the code since both of you are saying the same. Here is the code for your review.
Sub FindAndReplace()
Dim vFR As Variant, r As Range, i As Long, rSource As Range
Dim sCurrRep() As String, sGlobalRep As Variant, y As Long, x As Long
Dim NumCharsBefore As Long, NumCharsAfter As Long
Dim StrFind As String, StrReplace As String, CountNoOfReplaces As Variant
'------------------------------------------------
Dim oWord As Object
Const wdReplaceAll = 2
Set oWord = CreateObject("Word.Application")
'------------------------------------------------
Application.ScreenUpdating = False
vFR = ThisWorkbook.Sheets("Sheet1").Range("A1").CurrentRegion.Value
On Error Resume Next
Set rSource = Cells.SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If Not rSource Is Nothing Then
For Each r In rSource.Cells
For i = 2 To UBound(vFR)
If Trim(vFR(i, 1)) <> "" Then
With oWord
.Documents.Add
DoEvents
r.Copy
.ActiveDocument.Content.Paste
NumCharsBefore = .ActiveDocument.Characters.Count
With .ActiveDocument.Content.Find
.ClearFormatting
.Font.Bold = False
.Replacement.ClearFormatting
.Execute FindText:=vFR(i, 1), ReplaceWith:=vFR(i, 2), Format:=True, Replace:=wdReplaceAll
End With
.Selection.Paragraphs(1).Range.Select
.Selection.Copy
r.Select
ActiveSheet.Paste'Error occurs in this line pressing debug and F8 is pasting the data
StrFind = vFR(i, 1): StrReplace = vFR(i, 2)
NumCharsAfter = .ActiveDocument.Characters.Count
CountNoOfReplaces = (NumCharsBefore - NumCharsAfter) / (Len(StrFind) - Len(StrReplace))
.ActiveDocument.UndoClear
.ActiveDocument.Close SaveChanges:=False
If CountNoOfReplaces Then
x = x + 1
ReDim Preserve sCurrRep(1 To 3, 1 To x)
sCurrRep(1, x) = vFR(i, 1)
sCurrRep(2, x) = vFR(i, 2)
sCurrRep(3, x) = CountNoOfReplaces
End If
CountNoOfReplaces = 0
End With
End If
Next i
Next r
End If
oWord.Quit
'Some more gode goes here... which is not needed since error occurs in the above loop
End Sub
If you want to know why I have chosen word for replacement then please go through the below link.
http://www.excelforum.com/excel-programming-vba-macros/1128898-vba-characters-function-fails-when-the-cell-content-exceeds-261-characters.html
Also used the code from the below link to get the number of replacements count.
http://word.mvps.org/faqs/macrosvba/GetNoOfReplacements.htm
Characters(start, length).Delete() method really seems not to work with longer strings in Excel :(. So a custom Delete() method could be written which will work with decoupled formating informations and texts. So the text of the cell can be modified without loosing the formating information. HTH.
Add new class named MyCharacter. It will contain information about text and
formating of one character:
Public Text As String
Public Index As Integer
Public Name As Variant
Public FontStyle As Variant
Public Size As Variant
Public Strikethrough As Variant
Public Superscript As Variant
Public Subscript As Variant
Public OutlineFont As Variant
Public Shadow As Variant
Public Underline As Variant
Public Color As Variant
Public TintAndShade As Variant
Public ThemeFont As Variant
Add next new class named MyCharcters and wrap the code of the new
Delete method in it. With Filter method a new collection of MyCharacter is created. This collection contains only the characters which should remain. Finally in method Rewrite the text is re-written from this collection back to target range along with formating info:
Private m_targetRange As Range
Private m_start As Integer
Private m_length As Integer
Private m_endPosition As Integer
Public Sub Delete(targetRange As Range, start As Integer, length As Integer)
Set m_targetRange = targetRange
m_start = start
m_length = length
m_endPosition = m_start + m_length - 1
Dim filterdChars As Collection
Set filterdChars = Filter
Rewrite filterdChars
End Sub
Private Function Filter() As Collection
Dim i As Integer
Dim newIndex As Integer
Dim newChar As MyCharacter
Set Filter = New Collection
newIndex = 1
For i = 1 To m_targetRange.Characters.Count
If i < m_start Or i > m_endPosition Then
Set newChar = New MyCharacter
With newChar
.Text = m_targetRange.Characters(i, 1).Text
.Index = newIndex
.Name = m_targetRange.Characters(i, 1).Font.Name
.FontStyle = m_targetRange.Characters(i, 1).Font.FontStyle
.Size = m_targetRange.Characters(i, 1).Font.Size
.Strikethrough = m_targetRange.Characters(i, 1).Font.Strikethrough
.Superscript = m_targetRange.Characters(i, 1).Font.Superscript
.Subscript = m_targetRange.Characters(i, 1).Font.Subscript
.OutlineFont = m_targetRange.Characters(i, 1).Font.OutlineFont
.Shadow = m_targetRange.Characters(i, 1).Font.Shadow
.Underline = m_targetRange.Characters(i, 1).Font.Underline
.Color = m_targetRange.Characters(i, 1).Font.Color
.TintAndShade = m_targetRange.Characters(i, 1).Font.TintAndShade
.ThemeFont = m_targetRange.Characters(i, 1).Font.ThemeFont
End With
Filter.Add newChar, CStr(newIndex)
newIndex = newIndex + 1
End If
Next i
End Function
Private Sub Rewrite(chars As Collection)
m_targetRange.Value = ""
Dim i As Integer
For i = 1 To chars.Count
If IsEmpty(m_targetRange.Value) Then
m_targetRange.Value = chars(i).Text
Else
m_targetRange.Value = m_targetRange.Value & chars(i).Text
End If
Next i
For i = 1 To chars.Count
With m_targetRange.Characters(i, 1).Font
.Name = chars(i).Name
.FontStyle = chars(i).FontStyle
.Size = chars(i).Size
.Strikethrough = chars(i).Strikethrough
.Superscript = chars(i).Superscript
.Subscript = chars(i).Subscript
.OutlineFont = chars(i).OutlineFont
.Shadow = chars(i).Shadow
.Underline = chars(i).Underline
.Color = chars(i).Color
.TintAndShade = chars(i).TintAndShade
.ThemeFont = chars(i).ThemeFont
End With
Next i
End Sub
How to use it:
Sub test()
Dim target As Range
Dim myChars As MyCharacters
Application.ScreenUpdating = False
Set target = Worksheets("Demo").Range("A1")
Set myChars = New MyCharacters
myChars.Delete targetRange:=target, start:=300, length:=27
Application.ScreenUpdating = True
End Sub
Before:
After:
To make it more stable, you should:
Disable all events while operating
Never call .Activate or .Select
Paste directly in the targeted cell with WorkSheet.Paste
Cancel the Copy operation with Application.CutCopyMode = False
Reuse the same document and not create one for each iteration
Do as less operations as possible in an iteration
Use early binding [New Word.Application] instead of late binding [CreateObject("Word.Application")]
Your example refactored :
Sub FindAndReplace()
Dim dictionary(), target As Range, ws As Worksheet, cell As Range, i As Long
Dim strFind As String, strReplace As String, diffCount As Long, replaceCount As Long
Dim appWord As Word.Application, content As Word.Range, find As Word.find
dictionary = [Sheet1!A1].CurrentRegion.Value
Set target = Cells.SpecialCells(xlCellTypeConstants)
' launch and setup word
Set appWord = New Word.Application
Set content = appWord.Documents.Add().content
Set find = content.find
find.ClearFormatting
find.Font.Bold = False
find.replacement.ClearFormatting
' disable events
Application.Calculation = xlManual
Application.ScreenUpdating = False
Application.EnableEvents = False
' iterate each cell
Set ws = target.Worksheet
For Each cell In target.Cells
' copy the cell to Word and disable the cut
cell.Copy
content.Delete
content.Paste
Application.CutCopyMode = False
' iterate each text to replace
For i = 2 To UBound(dictionary)
If Trim(dictionary(i, 1)) <> Empty Then
replaceCount = 0
strFind = dictionary(i, 1)
strReplace = dictionary(i, 2)
' replace in the document
diffCount = content.Characters.count
find.Execute FindText:=strFind, ReplaceWith:=strReplace, format:=True, Replace:=2
' count number of replacements
diffCount = diffCount - content.Characters.count
If diffCount Then
replaceCount = diffCount \ (Len(strFind) - Len(strReplace))
End If
Debug.Print replaceCount
End If
Next
' copy the text back to Excel
content.Copy
ws.Paste cell
Next
' terminate Word
appWord.Quit False
' restore events
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
How about change it from: activesheet.paste
to:
activesheet.activate
activecell.pastespecial xlpasteAll
This post seems to explain the problem and provide two solutions:
http://www.excelforum.com/excel-programming-vba-macros/376722-runtime-error-1004-paste-method-of-worksheet-class-failed.html
Two items come to light in this post:
Try using Paste Special
Specify the range you wish to paste to.
Another solution would be to extract the targeted cells as XML, replace the text with a regular expression and then write the XML back to the sheet.
While it's much faster than working with Word, it might require some knowledge with regular expressions if the formats were to be handled. Moreover it only works with Excel 2007 and superior.
I've assemble an example that replaces all the occurences with the same style:
Sub FindAndReplace()
Dim area As Range, dictionary(), xml$, i&
Dim matchCount&, replaceCount&, strFind$, strReplace$
' create the regex object
Dim re As Object, match As Object
Set re = CreateObject("VBScript.RegExp")
re.Global = True
re.MultiLine = True
' copy the dictionary to an array with column1=search and column2=replacement
dictionary = [Sheet1!A1].CurrentRegion.Value
'iterate each area
For Each area In ActiveSheet.Cells.SpecialCells(xlCellTypeConstants)
' read the cells as XML
xml = area.Value(xlRangeValueXMLSpreadsheet)
' iterate each text to replace
For i = 2 To UBound(dictionary)
If Trim(dictionary(i, 1)) <> Empty Then
strFind = dictionary(i, 1)
strReplace = dictionary(i, 2)
' set the pattern
re.pattern = "(>[^<]*)" & strFind
' count the number of occurences
matchCount = re.Execute(xml).count
If matchCount Then
' replace each occurence
xml = re.Replace(xml, "$1" & strReplace)
replaceCount = replaceCount + matchCount
End If
End If
Next
' write the XML back to the sheet
area.Value(xlRangeValueXMLSpreadsheet) = xml
Next
' print the number of replacement
Debug.Print replaceCount
End Sub
DDuffy's answer is useful.
I found the code can run normally at slowly cpu PC .
add the bellow code before paste, the problem is sloved:
Application.Wait (Now + TimeValue("0:00:1"))'wait 1s or more
ActiveSheet.Paste

Generating dynamic charts with VBA

I have to create almost 200 charts of time series. So I tried to write a macro that finishes most of the work I need to do.
I generated names for the time series like this as an example:
Name:= AKB_ExampleA
The name refers to a dynamic range which I declared with this formula:
=OFFSET('sheet1'!$C$7:$C$137;0;0;COUNT('sheet1'!$C$7:$C$206))
So now to the macro I coded so far:
Sub graphik_erstellen()
Call graphik1("AKB")
End Sub
Sub graphik(Name As String)
'
Dim Ch As Chart
Dim RngToCover As Range
Set Ch = charts.Add
Set Ch = Ch.Location(Where:=xlLocationAsObject, Name:="Charts")
With Ch
.ChartType = xlLine
.SetSourceData Source:=Range(Name & "_ExampleA")
.SeriesCollection(1).XValues = Range("Datum_Volumen")
.SeriesCollection(1).Name = "SERIES1"
.FullSeriesCollection(1).Select
With Selection.Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(192, 0, 0)
.Transparency = 0
End With
.HasTitle = True
.ChartTitle.Text = Name & ", Volumen (nach Korrektur)"
.HasLegend = True
.Legend.Position = xlLegendPositionBottom
.Legend.Select
Selection.Format.TextFrame2.TextRange.Font.Size = 11
Selection.Format.TextFrame2.TextRange.Font.Bold = msoTrue
With .Parent
.top = 100
.left = 100
.height = 287.149606299
.width = 543.685039370078
.Name = Name & "_chart"
End With
End With
End Sub
My problem is, that if I do that, the dynamic range is not really considered. It takes the range of the name (which is $C$7:$C$137) but it should refer to the name itself (in order to be dynamic).
So if I click on the chart to see the series, the series values are declared as: ='sheet1'!$C$7:$C$137 instead of ='sheet1'!ExampleA.
I would be really, really grateful if somebody could help me out.
Best
Elio
I have rearranged a few lines of code and tried to place comments refering to them as well.
Let me know what works. Youjust might need to change SeriesCollection to FullSeriesCollection. Other than that the code works in my Excel 2010.
The first Sub I just get the Range size according to the data available in Column "C" from Row 7.
Let me know.
Option Explicit
Sub graphik_erstellen()
'You always want to use direct reference to a sheet/range chart
'Refering to the WorkBook they are in and the worksheet as well.
'especially if you are opening multiple WorkBooks / Sheets
Dim CurrentWorkSheet As Worksheet
Set CurrentWorkSheet = Workbooks("Book1").Worksheets("Sheet1")
'Dynamically finding the end of the data in Column C
Dim LastRow As Long
LastRow = CurrentWorkSheet.Cells(CurrentWorkSheet.Rows.Count, "C").End(xlUp).Row
'Setting the range using the document reference aswell
Dim AKB As Range
Set AKB = Workbooks("Book1").Worksheets("Sheet1").Range(Cells(7, "C"), Cells(LastRow, "C"))
Call graphik(AKB)
End Sub
Sub graphik(Name As Range)
Dim DataChart As Chart
Dim RngToCover As Range
Set DataChart = Workbooks("Book1").Charts.Add
'With Excel 2010 the line above will automatically add the chart as a sheet and not aobject in a sheet
'Set DataChart = DataChart.Location(Where:=xlLocationAsObject, Name:="Charts")
With DataChart
.Name = "Charts" ' This will be the Name of the CHart Tab
.ChartType = xlLine
.SetSourceData Source:=Name
'You can see below I avoided the Select and Selection
With .SeriesCollection(1)
'Using Offset I just used the data one cell to the left of the range
.XValues = Name.Offset(0, -1)
.Name = "SERIES1"
With .Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(192, 0, 0)
.Transparency = 0
End With
End With
.HasTitle = True
.ChartTitle.Text = "MIDDEL TOP TEXT" 'Name & ", Volumen (nach Korrektur)"
.HasLegend = True
With .Legend
.Position = xlLegendPositionBottom
.Format.TextFrame2.TextRange.Font.Size = 11
.Format.TextFrame2.TextRange.Font.Bold = msoTrue
End With
'Not sure about this, it doesnt work in my Excel 2010
'
With .Parent
.Top = 100
.Left = 100
.Height = 287.149606299
.Width = 543.685039370078
.Name = Name & "_chart"
End With
End With
End Sub
Let me know what your intention is for the Sheet and Chart names and then I can help with getting that to what you need as well.

Automatic Excel Acronym finding, Definition and Classification Adding

I have been working with code that I found HERE but I am having difficulty getting it to do one more task for me. I have added another column (3) to my excel document that has the "classification" of the acronym & definition and I want to add that to the newly created word doc in column 1, before the acronym. I have tried several different ways of moving the provided code around but it always results in an error. Any help is appreciated. I have included the working code below. Like I said, it works I just want it to do one more thing. Thank you!
Sub ExtractACRONYMSToNewDocument()
Dim oDoc_Source As Document
Dim oDoc_Target As Document
Dim strListSep As String
Dim strAcronym As String
Dim strDef As String
Dim oTable As Table
Dim oRange As Range
Dim n As Long
Dim m As Long
m = 0
Dim strAllFound As String
Dim Title As String
Dim Msg As String
Dim objExcel As Object
Dim objWbk As Object
Dim rngSearch As Object
Dim rngFound As Object
Dim targetCellValue As String
' message box title
Title = "Extract Acronyms to New Document"
' Set message box message
Msg = "This macro finds all Acronyms (consisting of 2 or more " & _
"uppercase letters, Numbers or '/') and their associated definitions. It " & _
"then extracts the words to a table at the current location you have selected" & vbCr & vbCr & _
"Warning - Please make sure you check the table manually after!" & vbCr & vbCr & _
"Do you want to continue?"
' Display message box
If MsgBox(Msg, vbYesNo + vbQuestion, Title) <> vbYes Then
Exit Sub
End If
' Stop the screen from updating
Application.ScreenUpdating = False
'Find the list separator from international settings
'May be a comma or semicolon depending on the country
strListSep = Application.International(wdListSeparator)
'Start a string to be used for storing names of acronyms found
strAllFound = "#"
' give the active document a variable
Set oDoc_Source = ActiveDocument
'Create a variable for excel and open the definition workbook
Set objExcel = CreateObject("Excel.Application")
Set objWbk = objExcel.Workbooks.Open("C:\Users\USERNAME\Documents\Test_Definitions.xlsx")
'objExcel.Visible = True
objWbk.Activate
'Create new document to temporarily store the acronyms
Set oDoc_Target = Documents.Add
' Use the target document
With oDoc_Target
'Make sure document is empty
.Range = ""
'Insert info in header - change date format as you wish
.PageSetup.TopMargin = CentimetersToPoints(3)
.Sections(1).Headers(wdHeaderFooterPrimary).Range.Text = _
"Acronyms extracted from: " & oDoc_Source.FullName & vbCr & _
"Created by: " & Application.UserName & vbCr & _
"Creation date: " & Format(Date, "MMMM d, yyyy")
'Adjust the Normal style and Header style
With .Styles(wdStyleNormal)
.Font.Name = "Arial"
.Font.Size = 10
.ParagraphFormat.LeftIndent = 0
.ParagraphFormat.SpaceAfter = 6
End With
With .Styles(wdStyleHeader)
.Font.Size = 8
.ParagraphFormat.SpaceAfter = 0
End With
'Insert a table with room for acronym and definition
Set oTable = .Tables.Add(Range:=.Range, NumRows:=2, NumColumns:=4)
With oTable
'Format the table a bit
'Insert headings
.Range.Style = wdStyleNormal
.AllowAutoFit = False
.Cell(1, 1).Range.Text = "Classification"
.Cell(1, 2).Range.Text = "Acronym"
.Cell(1, 3).Range.Text = "Definition"
.Cell(1, 4).Range.Text = "Page"
'Set row as heading row
.Rows(1).HeadingFormat = True
.Rows(1).Range.Font.Bold = True
.PreferredWidthType = wdPreferredWidthPercent
.Columns(1).PreferredWidth = 15
.Columns(2).PreferredWidth = 25
.Columns(3).PreferredWidth = 55
.Columns(4).PreferredWidth = 5
End With
End With
With oDoc_Source
Set oRange = .Range
n = 1 'used to count below
' within the total range of the source document
With oRange.Find
'Use wildcard search to find strings consisting of 3 or more uppercase letters
'Set the search conditions
'NOTE: If you want to find acronyms with e.g. 2 or more letters,
'change 3 to 2 in the line below
.Text = "<[A-Z][A-Z0-9/]{1" & strListSep & "}>"
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = True
.MatchWildcards = True
'Perform the search
Do While .Execute
'Continue while found
strAcronym = oRange
'Insert in target doc
'If strAcronym is already in strAllFound, do not add again
If InStr(2, strAllFound, "#" & strAcronym & "#") = 0 Then
'Add new row in table from second acronym
If n > 1 Then oTable.Rows.Add
'Was not found before
strAllFound = strAllFound & strAcronym & "#"
'Insert in column 1 in oTable
'Compensate for heading row
With oTable
.Cell(n + 1, 2).Range.Text = strAcronym
'Insert page number in column 4
.Cell(n + 1, 4).Range.Text = oRange.Information(wdActiveEndPageNumber)
' Find the definition from the Excel document
With objWbk.Sheets("Sheet1")
' Find the range of the cells with data in Excel doc
Set rngSearch = .Range(.Range("A1"), .Range("A" & .Rows.Count).End(-4162))
' Search in the found range for the
Set rngFound = rngSearch.Find(What:=strAcronym, After:=.Range("A1"), LookAt:=1)
' if nothing is found count the number of acronyms without definitions
If rngFound Is Nothing Then
m = m + 1
' Set the cell variable in the new table as blank
targetCellValue = ""
' If a definition is found enter it into the cell variable
Else
targetCellValue = .Cells(rngFound.Row, 2).Value
End If
End With
' enter the cell varibale into the definition cell
.Cell(n + 1, 3).Range.Text = targetCellValue
End With
' add one to the loop count
n = n + 1
End If
Loop
End With
End With
'Sort the acronyms alphabetically - skip if only 1 found
If n > 2 Then
With Selection
.Sort ExcludeHeader:=True, FieldNumber:="Column 2", SortFieldType _
:=wdSortFieldAlphanumeric, SortOrder:=wdSortOrderAscending
'Go to start of document
.HomeKey (wdStory)
End With
End If
' update screen
Application.ScreenUpdating = True
'If no acronyms found set message saying so
If n = 1 Then
Msg = "No acronyms found."
' set the final messagebox message to show the number of acronyms found and those that did not have definitions
Else
Msg = "Finished extracting " & n - 1 & " acronymn(s) to a new document. Unable to find definitions for " & m & " acronyms."
End If
' Show the finished message box
On Error Resume Next
AppActivate Application.Caption
On Error GoTo 0
MsgBox Msg, vbOKOnly, Title
'Close Excel after
objWbk.Close Saved = True
'Clean up
Set oRange = Nothing
Set oDoc_Source = Nothing
Set oDoc_Target = Nothing
Set oTable = Nothing
Set objExcel = Nothing
Set objWbk = Nothing
End Sub
If anyone is looking for this solution, I was able to figure it out by duplicating the following lines. It then counts how many definitions and classifications it was unable to find and reports at the end.
' Find the definition from the Excel document
With objWbk.Sheets("Sheet1")
' Find the range of the cells with data in Excel doc
Set rngSearch = .Range(.Range("A1"), .Range("A" & .Rows.Count).End(-4162))
' Search in the found range for the
Set rngFound = rngSearch.Find(What:=strAcronym, After:=.Range("A1"), LookAt:=1)
' if nothing is found count the number of acronyms without definitions
If rngFound Is Nothing Then
m = m + 1
' Set the cell variable in the new table as blank
targetCellValue = ""
' If a definition is found enter it into the cell variable
Else
targetCellValue = .Cells(rngFound.Row, 2).Value
End If
End With
' enter the cell varibale into the definition cell
.Cell(n + 1, 3).Range.Text = targetCellValue
End With