Create images dynamically in vba and add click function to them - excel

I am trying to dynamically add images to a form in a grid like fashion. The images are from a folder for now then, I'm trying to add a click function to each dynamically created images on the form to execute something but I'm stuck on that part. I am successful in importing the images to a form and showing it in a grid like fashion with the code below I came up with.
Option Explicit
Private Sub Pic2_Click()
'not working :(
MsgBox "worked!!"
End Sub
Private Sub UserForm_Initialize()
Dim img As Object
Dim picSheet As Worksheet
'Add Dynamic Image and assign it to object 'Img'
Dim i, h, t As Integer
' Set picSheet = ThisWorkbook.Worksheets("Themes")
' Dim pictureList As Object
' Dim pics As Shapes
' Dim pic As Shape
' Set pics = ThisWorkbook.Worksheets("Themes").Shapes
Dim picPath As String
t = 10
h = 10
picPath = Dir(Environ("USERPROFILE") & "\Pictures\*pic*") 'getting pictures from picpath folder image names are ranged from "pic1.jpg" to "pic12.jpg"
Do While Not Blank(picPath) ' blank determines if a string is empty (boolean value)
i = i + 1
If i > 1 Then h = h + 90
Set img = Me.Controls.Add("Forms.image.1", picPath, True)
If i Mod 4 = 1 And i > 1 Then 'new row after first 4 images to create grid
t = t + 100
h = 10
End If
With img
.Picture = LoadPicture(Environ("USERPROFILE") & "\Pictures\" & picPath)
.PictureSizeMode = fmPictureSizeModeStretch
.Left = h
.Top = t
.name = Split(picPath, ".")(0)
Debug.Print "name is: " & .name
End With
picPath = Dir
Loop
End Sub

This is my entire solution and it worked for me. I changed a few things by using buttons instead that had the images embedded in them.
Option Explicit
Dim ColTB As Collection
Private Sub UserForm_Initialize()
Dim picPath, path As String
Dim i, h, t As Integer
Dim button As Object
Dim fso As New FileSystemObject
t = 10
h = 10
Set ColTB = New Collection
picPath = Dir(Environ("USERPROFILE") & "\OneDrive\Pictures\Themes\" & "*.jpg")
Do While Not Blank(picPath)
i = i + 1
If i > 1 Then h = h + 120
If i Mod 4 = 1 And i > 1 Then
t = t + 100
h = 10
End If
Set button = Me.Controls.Add("Forms.CommandButton.1", picPath, True)
With button
.Font.Bold = True
.Left = h
.Top = t
.Picture = LoadPicture(Environ("USERPROFILE") & "\OneDrive\Pictures\Themes\" & picPath)
.Height = 72
.Width = 100
End With
ColTB.Add EventObj(button)
picPath = Dir
Loop
End Sub
Function EventObj(obj As MSForms.CommandButton) As Class1
Dim o As New Class1
Set o.buttonClickEvent = obj
Set EventObj = o
End Function
Class1 module
Option Explicit
Public WithEvents buttonClickEvent As MSForms.CommandButton
Private Sub buttonClickEvent_Click()
Dim name, imgpath, sheetName As String
Dim answer
Dim ac As Worksheet
Set ac = ThisWorkbook.ActiveSheet
name = buttonClickEvent.name
answer = MsgBox("You want to apply the " & Split(name, ".")(0) & " theme now?", vbQuestion + vbYesNo + vbDefaultButton2, "Apply Theme")
If answer = vbYes Then
imgpath = Environ("USERPROFILE") & "\OneDrive\Pictures\Themes\" & name
ac.SetBackgroundPicture Filename:=imgpath
End If
End Sub

Related

VB.NET - Working with Excel and cannot release files once complete

I created an app that does the following:
Opens an excel spreadsheet and show a hidden sheet
Copy the data in this sheet to a temporary spreadsheet
Run some error checks on the data that's been pasted
Create a unique code in the first column based on customer no. date & time
Save the spreadsheet as a new file
Clear up to be ready for the next spreadsheet
The problem I am having is at step 6 of clearing up and releasing any excel objects in memory that can hold up moving to the next spreadsheet and so on.
The current issue I have is that an Excel object remains open and locks the tempfile.xlsx that is created which will then randomly generates the error "The file 'C:\Temp\CustOrders\Input\TempFile.xlsx' already exists." I say randomly because I can run 10 or more files through it without an issue. I could run them all again and it will produce the error after the 1st, 2nd, 3rd or later file. I cannot blame any one file for causing this.
How do I effectively close out all Excel objects ready for the next file to be processed? I have so far tried different ways to do this including trying to kill the process but this seems like a dirty sledgehammer approach.
Here's the code:
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices
Imports System.IO
Public Class Form1
Dim xlApp As Excel.Application
Dim xlNewApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
Dim range As Excel.Range
Dim rCnt As Integer
Dim cCnt As Integer
Dim Obj As Object
Dim TempFile() As String
Dim TempFiledir As String
Dim filename As String
Dim xlNewWorkBook As Excel.Workbook
Dim xlNewWorkSheet As Excel.Worksheet
Dim misValue As Object = System.Reflection.Missing.Value
Dim Cust As Object
Dim pfile As String
Dim NoProcessed As Integer = 0
Dim NoFailed As Integer = 0
Dim filecount As Integer = 0
Dim fileremaining As Integer = 0
Dim custFailed As Integer = 0
Dim files() As String = Directory.GetFiles("C:\Temp\CustOrders\Uploaded")
Dim di As New DirectoryInfo("C:\Temp\CustOrders\Uploaded")
Private Sub releaseObject(ByVal obj As Object)
Try
Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
lblProcessingFile.Visible = False
CountFiles()
lblFileCount.Text = "Files to be processed: " & filecount
End Sub
Function CountFiles()
Dim files() As String = Directory.GetFiles("C:\Temp\CustOrders\Uploaded")
Dim di As New DirectoryInfo("C:\Temp\CustOrders\Uploaded")
If files.Count > 0 Then
filecount = di.GetFiles("*.xlsx").Count()
Else
filecount = 0
lblFileCount.Text = "Files to be processed: " & filecount
End If
End Function
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles BTN_gencsv.Click
TempFiledir = ("C:\Temp\CustOrders\Input\TempFile.xlsx")
If My.Computer.FileSystem.FileExists(TempFiledir) Then
My.Computer.FileSystem.DeleteFile(TempFiledir)
End If
GetFiles()
End Sub
Sub GetFiles()
'1. Look in the UPLOADED folder for new files
Dim files() As String = Directory.GetFiles("C:\Temp\CustOrders\Uploaded")
Dim di As New DirectoryInfo("C:\Temp\CustOrders\Uploaded")
If files.Count > 0 Then
Dim arrayfi As FileInfo() = di.GetFiles("*.xlsx")
Dim fi As FileInfo
For Each fi In arrayfi
filename = fi.Name
Start(filename)
Next
Else
MsgBox("No files available in directory")
End If
End Sub
Sub Start(filename)
With BTN_gencsv
.BackColor = Color.Red
.ForeColor = Color.White
.Text = "Please wait..."
End With
'2. Get the file that has been uploaded by the customer, copy and rename as TempFile
lblProcessingFile.Visible = True
lblProcessingFile.Text = "Processing file: " & filename
IO.File.Copy("C:\Temp\CustOrders\Uploaded\" & filename, _
"C:\Temp\CustOrders\Input\TempFile.xlsx")
xlApp = New Excel.Application
xlNewApp = New Excel.Application
xlWorkBook = xlApp.Workbooks.Open("C:\Temp\CustOrders\Input\TempFile.xlsx")
xlWorkSheet = xlWorkBook.Worksheets(1)
xlWorkSheet = xlWorkBook.Worksheets("CSV")
xlWorkSheet.Visible = XlSheetVisibility.xlSheetVisible
xlWorkSheet.Unprotect("opencsv")
'3. Copy rows from the CSV worksheet including headers
xlWorkSheet.Range("A1:H100").Copy()
'4. Create new Excel workbook and worksheet so it can have have all rows pasted in
' Then perform all prep work
xlNewWorkBook = xlNewApp.Workbooks.Add(misValue)
xlNewWorkSheet = xlNewWorkBook.Worksheets(1)
xlNewWorkSheet.Select()
' Paste the rows into the new worksheet
On Error Resume Next
xlNewWorkSheet.PasteSpecial(Excel.XlPasteType.xlPasteValues)
xlApp.CutCopyMode = False
' Get current date/time
Dim dt As DateTime = DateTime.Now
Dim dt2 As String = dt
dt2 = dt2.Replace("/", "").Replace(" ", "_").Replace(":", "")
' Select customer number from worksheet
Dim xRng As Excel.Range = CType(xlNewWorkSheet.Cells(2, 5), Excel.Range)
Cust = xRng.Value().ToString()
' If the customer is not found in the spreadsheet lookup it generates "-2146826246" as a value
' This saves the cell as "Not found" to make it look friendly
If Cust.Equals("-2146826246") Then
custFailed += 1
Cust = "Cust_Not_Found_" & custFailed
failedfiles()
Else
CustNo()
End If
releaseObject(xRng)
' This now passes to two error checking subs
End Sub
Sub completeform()
'5. Generate a unique value for Netsuite based on the customer number and current date time
Dim Row As Range
Dim Index As Long
Dim Count As Long
For Index = xlNewWorkSheet.UsedRange.Rows.Count To 1 Step -1
Row = xlNewWorkSheet.UsedRange.Rows(Index)
Count = 0
On Error Resume Next
Count = Row.SpecialCells(XlCellType.xlCellTypeBlanks).Count
If Count = Row.Cells.Count Then Row.Delete(Excel.XlDirection.xlUp)
Next
Dim dt As DateTime = DateTime.Now
Dim dt2 As String = dt
dt2 = dt2.Replace("/", "").Replace(" ", "_").Replace(":", "")
pfile = (Cust + "_" + dt2)
Dim rw As Integer = 1
Do Until xlNewWorkSheet.Cells(rw, 1).Value Is Nothing
rw += 1
Loop
Dim last As String = rw - 1
With xlNewWorkSheet.Range("A1:A100")
.Range(.Cells(2, 1), .Cells(last, 1)).Value = (Cust + "_" + dt2)
End With
'6. Save the workbook with a unique name based on customer number and date/time
xlWorkBook.Saved = True
xlNewWorkBook.SaveAs("C:\Temp\CustOrders\Output\Test_" + pfile + ".csv", Excel.XlFileFormat.xlCSV, misValue, misValue, misValue, misValue, _
Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue)
'7. Close and release all Excel worksheets and workbooks so they dont remain in memory
xlNewWorkBook.Close(True, misValue, misValue)
xlWorkBook.Saved = True
xlNewWorkBook.Saved = True
releaseObject(xlNewWorkSheet)
releaseObject(xlNewWorkBook)
releaseObject(xlNewApp)
xlWorkBook.Close(False)
xlApp.Quit()
releaseObject(range)
releaseObject(xlWorkSheet)
releaseObject(xlWorkBook)
releaseObject(xlApp)
xlNewApp.Quit()
System.Threading.Thread.Sleep(2000)
'8. Move the processed workbook to the Processed folder ready for a new workbook
IO.File.Move("C:\Temp\CustOrders\Input\TempFile.xlsx", _
"C:\Temp\CustOrders\Processed\Processedfile_" + pfile + ".xlsx")
'9. Move the spreadsheet from Uploaded to OldUploaded ready for a new file
IO.File.Move("C:\Temp\CustOrders\Uploaded\" + filename, _
"C:\Temp\CustOrders\OldUploaded\Uploaded_" + filename)
NoProcessed += 1
lblProcessedCount.Text = "No. Processed..." & NoProcessed
CountFiles()
lblFileCount.Text = "Files to be processed: " & filecount
With BTN_gencsv
.BackColor = SystemColors.Control
.ForeColor = SystemColors.ControlText
.Text = "Generate CSV"
End With
lblProcessingFile.Visible = False
End Sub
Sub CustNo()
Dim c As Range
With xlNewWorkSheet.Range("A1:A100")
c = .Find("#N/A", LookIn:=XlFindLookIn.xlValues)
If Not c Is Nothing Then
custFailed += 1
Cust = "Cust_Not_Found_" & custFailed
MsgBox(Cust)
failedfiles()
Else
quantityBlanks()
End If
End With
End Sub
Sub quantityBlanks()
Dim rw As Integer = 1
Do Until xlNewWorkSheet.Cells(rw, 1).Value Is Nothing
rw += 1
Loop
Dim last As String = rw - 1
Dim rng As Excel.Range
Dim TotalBlanks As Long
TotalBlanks = 0
rng = xlNewWorkSheet.Range(xlNewWorkSheet.Cells(2, 8), xlNewWorkSheet.Cells(last, 8))
On Error Resume Next
TotalBlanks = rng.SpecialCells(XlCellType.xlCellTypeBlanks).Count
If TotalBlanks > 0 Then
Cust = "Quantity_error_"
failedfiles()
Else
referrors()
End If
rng = Nothing
End Sub
Sub referrors()
Dim c As Range
With xlNewWorkSheet.Range("A1:A100")
c = .Find("#REF!", LookIn:=XlFindLookIn.xlValues)
If Not c Is Nothing Then
Cust = "~REF!_errors_"
failedfiles()
Else
completeform()
End If
End With
End Sub
Sub failedfiles()
Dim dt As DateTime = DateTime.Now
Dim dt2 As String = dt
dt2 = dt2.Replace("/", "").Replace(" ", "_").Replace(":", "")
pfile = (Cust + "_" + dt2)
xlWorkBook.Close(False)
xlNewWorkBook.Close(False)
xlNewApp.Quit()
xlApp.Quit()
releaseObject(xlApp)
releaseObject(xlWorkBook)
releaseObject(xlWorkSheet)
releaseObject(xlNewApp)
releaseObject(xlNewWorkBook)
releaseObject(xlNewWorkSheet)
'IO.File.Delete("C:\Temp\CustOrders\Input\Newfile.xlsx")
IO.File.Move("C:\Temp\CustOrders\Input\TempFile.xlsx", _
"C:\Temp\CustOrders\Processed\ProcessedFailedfile_" + pfile + ".xlsx")
IO.File.Move("C:\Temp\CustOrders\Uploaded\" + filename, _
"C:\Temp\CustOrders\Failed\FailedFile_" + pfile + ".xlsx")
With BTN_gencsv
.BackColor = SystemColors.Control
.ForeColor = SystemColors.ControlText
.Text = "Generate CSV"
End With
NoFailed += 1
lblFailed.ForeColor = Color.Red
lblFailed.Text = "No. Failed..." & NoFailed
CountFiles()
lblFileCount.Text = "Files to be processed: " & filecount
lblProcessingFile.Visible = False
End Sub
Private Sub PictureBox1_Click(sender As System.Object, e As System.EventArgs) Handles PictureBox1.Click
CountFiles()
lblFileCount.Text = "Files to be processed: " & filecount
End Sub
End Class

The Adobe process doesn't close after the code is finished

I'm adding bookmarks after I merged pdf files. The script does the job, but because of one variant, the Adobe-process doesn’t close after.
The Variants name is "BMA". If removed, then the process will close as designed.
I made a script closing all process, but I want a more solid solution. Please help.
Option Explicit
Sub testrun()
Dim aInfo(6) As String
'True = bookmark
'False = child bookmark
aInfo(0) = "True,Index,0"
aInfo(1) = "True,Document_1,1"
aInfo(2) = "False,Attatchment_1,2"
aInfo(3) = "True,Document_2,3"
aInfo(4) = "False,Attatchment_1,4"
aInfo(5) = "False,Attatchment_2,5"
Call NewFixPDF("C:\Temp\Test.pdf", aInfo)
End Sub
Private Sub NewFixPDF(sFile As String, aInfo() As String)
Dim AcroApp As Acrobat.CAcroApp
Dim PDDoc As Acrobat.CAcroPDDoc
Dim jso As Object
Dim BMR As Object, oBMR As Object, oBMA As Object
Dim BMA As Variant
Set AcroApp = CreateObject("AcroExch.App")
Set PDDoc = CreateObject("AcroExch.PDDoc")
Dim a As Integer, b As Integer, i As Integer
Dim aBookmark() As String
Dim bHead As Boolean
Dim sName As String
Dim iPage As Integer
If PDDoc.Open(sFile) = False Then
MsgBox "Can't open file", vbCritical
GoTo Exit_Sub
End If
Set jso = PDDoc.GetJSObject
jso.bookmarkRoot.Remove
Set BMR = jso.bookmarkRoot
Set oBMR = jso.bookmarkRoot
For i = 0 To UBound(aInfo) - 1
aBookmark = Split(aInfo(i), ",")
bHead = aBookmark(0)
sName = aBookmark(1)
iPage = aBookmark(2)
If bHead Then
If InStr(sName, "-") > 0 Then sName = Mid(sName, 3 + Len(sName) - InStr(StrReverse(sName), "-"))
BMR.createchild sName, "this.pageNum = " & iPage, a
BMA = BMR.Children
Set oBMA = BMA(a)
a = a + 1
b = 0
Else
oBMA.createchild sName, "this.pageNum = " & iPage, b
b = b + 1
End If
Next i
If PDDoc.Save(PDSaveFull, sFile) = False Then
MsgBox "Can't add bookmarks", vbCritical
End If
Exit_Sub:
Set BMR = Nothing
Set oBMR = Nothing
Set oBMA = Nothing
PDDoc.Close
AcroApp.Exit
Set AcroApp = Nothing
Set PDDoc = Nothing
Debug.Print "Done"
End Sub

Dynamically created label not visible on VBA userform

i have a Userform where I have a command button to view the reports(can be any file in a folder). If this folder has n files then on click event of the command button , 'n' labels needs to be created dynamically on the UserForm with file names displayed as the caption. Below code runs without error but the labels are not displayed on the UserForm.
Private Sub cmdViewReports_Click()
Dim row_num As Long
Dim fso As Object
Dim src_path As String
Dim dest_path As String
Dim sub_folder As String
Dim theLabel1 As msforms.Label
Dim inc As Integer
Dim my_files As Object
Dim my_folder As Object
Dim i As Integer
Dim ctrl As Control
'Check if the record is selected in listbox
If Selected_List = 0 Then
MsgBox "No record is selected.", vbOKOnly + vbInformation, "Upload Results"
Exit Sub
End If
'Folder Name to be created as per the 3rd column value in the list
sub_folder = Me.lstDb.List(Me.lstDb.ListIndex, 3)
sub_folder = Replace(sub_folder, "/", "_")
dest_path = "C:\abc\xyz\Desktop\FV\" & sub_folder & "\"
Set fso = CreateObject("scripting.filesystemobject")
If Not fso.FolderExists(dest_path) Then
MsgBox "No reports are loaded"
Exit Sub
End If
Set my_folder = fso.GetFolder(dest_path)
Set my_files = my_folder.Files
i = 1
For Each oFiles In my_files
Set theLabel1 = Me.Controls.Add("Forms.Label.1", "File_name" & i, True)
With theLabel1
.Caption = oFiles.Name
.Left = 1038
.Width = 60
.Height = 12
.Top = 324 + inc
.TextAlign = 1
.BackColor = &HC0FFFF
.BackStyle = 0
.BorderStyle = 1
.BorderStyle = 0
'.Locked = True
.ForeColor = &H8000000D
.Font.Size = 9
.Font.Underline = True
.Visible = True
End With
MsgBox "Label" & i & " Created"
inc = inc + 12
i = i + 1
Next
End Sub
But when I run I am not able to see the labels. In this case I have 3 files in the folder so I should be 3 labels.
Also I want the labels to be hyperlinked, meaning that once I click the label the report/files should be displayed.
Any help will be highly appreciated. Thanks in Advance.

Dynamic checkbox to enable textbox

I have a problem about dynamic controls. I create a dynamic userform with single frames depending by a number (rngprt in my example dependent by user input). No problem till now. Now I want to enable a textbox (in order to change its value) inside a specific frame when the relative checkbox is click. I used a Class Module (Classe1), but with my code I succeeded only to enable the last textbox of the n-frames when its checkbox is clicked (e.g. if I have 3 frames with 3 textboxes and 3 checkboxes, only the third checkbox it's able to enable the third textbox, the first and the second don't work).
Class Module: Classe1
Option Explicit
Public WithEvents cmbEvent1 As MSForms.CommandButton
Public WithEvents txbEvent1 As MSForms.TextBox
Public WithEvents frmEvent1 As MSForms.Frame
Public WithEvents ckbEvent1 As MSForms.CheckBox
Private Sub cmbEvent1_Click()
UserForm3.Hide
End Sub
Private Sub frmEvent1_Click()
End Sub
Public Sub txbEvent1_Change()
End Sub
Private Sub ckbEvent1_Click()
If UserForm3.Controls("CK" & xx).Value = True Then
UserForm3.Controls("TB" & xx).Enabled = True
End If
End Sub
Module: UserForm3
Option Explicit
Dim cmdB As New Classe1
Dim txtB As New Classe1
Dim chkB As New Classe1
Dim frm As New Classe1
Dim chkBColl As New Collection
Private Sub UserForm_Initialize()
Dim x As Long
Dim c As Variant
Dim cmdB1 As MSForms.CommandButton
Dim frm1 As MSForms.Frame
Dim txtB1 As MSForms.TextBox
Dim chkB1 As MSForms.CheckBox
Set cmdB1 = UserForm3.Controls.Add("Forms.CommandButton.1")
With cmdB1
.Name = "OKButton"
.Caption = "OK"
.Top = 40 * rngprt
.Left = 120
.Width = 40
.Height = 25
End With
Set cmdB.cmbEvent1 = cmdB1
For x = cel.Row To cel.Row + rngprt - 1 '**rngprt is a number from a Module1**
xx = x - cel.Row + 1 '**for progessive name of controls Dim xx as long into the Module1**
Set frm1 = UserForm3.Controls.Add("Forms.Frame.1")
frm1.Top = 40 * (xx - 1)
frm1.Left = 10
frm1.Width = 300
frm1.Height = 35
frm1.Name = "FR" & xx
With frm1.Controls
Set txtB1 = .Add("Forms.TextBox.1")
With txtB1
.Name = "TB" & xx
.Top = 10
.Left = 160
.Width = 30
.Height = 15
.TextAlign = fmTextAlignRight
.Enabled = False
.Value=50
End With
Set txtB.txbEvent1 = txtB1
Set chkB1 = .Add("Forms.CheckBox.1")
With chkB1
.Name = "CK" & xx
.Caption = "Part"
.Top = 10
.Left = 245
.Width = 45
.Height = 15
End With
Set chkB.ckbEvent1 = chkB1
'Here I added the code below
End With
Set frm.frmEvent1 = frm1
Next x
End Sub
I tried also to add this code below the chkB1 setting, but nothing.
Set chkB = New Classe1
Set chkB.ckbEvent1 = Me.Controls(chkB.txbEvent1)
chkBColl.Add chkB
Anybody have idea. Thank in advance to all for help.
Your code will not work.
You need to create an array of classe1.
Check this changes:
Classe1
Option Explicit
Public WithEvents cmbEvent1 As MSForms.CommandButton
Public WithEvents txbEvent1 As MSForms.TextBox
Public WithEvents frmEvent1 As MSForms.Frame
Public WithEvents ckbEvent1 As MSForms.CheckBox
Public xx As Integer
Private Sub cmbEvent1_Click()
UserForm3.Hide
End Sub
Private Sub frmEvent1_Click()
End Sub
Public Sub txbEvent1_Change()
End Sub
Private Sub ckbEvent1_Click()
If UserForm3.Controls("CK" & xx).value = True Then
UserForm3.Controls("TB" & xx).Enabled = True
End If
End Sub
UserForm3
Dim cmdB() As New Classe1
Dim txtB() As Classe1
Dim chkB() As Classe1
Dim frm() As New Classe1
Dim chkBColl As New Collection
Private Sub UserForm_Initialize()
Dim x As Long
Dim c As Variant
Dim cmdB1 As MSForms.CommandButton
Dim frm1 As MSForms.Frame
Dim txtB1 As MSForms.TextBox
Dim chkB1 As MSForms.CheckBox
ReDim Preserve cmdB(1)
Set cmdB1 = UserForm3.Controls.Add("Forms.CommandButton.1")
With cmdB1
.Name = "OKButton"
.Caption = "OK"
.Top = 40 * rngprt
.Left = 120
.Width = 40
.Height = 25
End With
Set cmdB(0).cmbEvent1 = cmdB1
For x = cel.Row To cel.Row + rngprt - 1 '**rngprt is a number from a Module1**
xx = x - cel.Row + 1 '**for progessive name of controls Dim xx as long into the Module1**
ReDim Preserve txtB(xx)
Set txtB(xx) = New Classe1
Set frm1 = UserForm3.Controls.Add("Forms.Frame.1")
frm1.Top = 40 * (xx - 1)
frm1.Left = 10
frm1.Width = 300
frm1.Height = 35
frm1.Name = "FR" & xx
With frm1.Controls
Set txtB1 = .Add("Forms.TextBox.1")
With txtB1
.Name = "TB" & xx
.Top = 10
.Left = 160
.Width = 30
.Height = 15
.TextAlign = fmTextAlignRight
.Enabled = False
.Value=50
End With
txtB(xx).xx = xx
Set txtB(xx).txbEvent1 = txtB1
ReDim Preserve chkB(xx + 1)
Set chkB(xx) = New Classe1
Set chkB1 = .Add("Forms.CheckBox.1")
With chkB1
.Name = "CK" & xx
.Caption = "Part"
.Top = 10
.Left = 245
.Width = 45
.Height = 15
End With
Set chkB(xx).ckbEvent1 = chkB1
chkB(xx).xx = xx
'Here I added the code below
End With
ReDim Preserve frm(xx)
Set frm(xx).frmEvent1 = frm1
Next x
End Sub

How to add new horizontal (limit line) series to existing VBA chart

I can successfully create a pivot chart (bar) but now want to add horizontal upper & lower limit lines. I have researched and read several sites but continually receive the same error at SeriesCollection.NewLines. The error is
"Object variable or With block variable not set".
This is driving me crazy!
I am using Microsoft Office 365 ProPlus.
'Create Pivot Chart button: Creates Pivot chart on Main and PivotTable tabs.
Private Sub CommandButton7_Click()
Dim sh As Shape
Dim ws As Worksheet
Dim ch As Chart
Dim pt As PivotTable
Dim TitleText As String
Dim Sheet3 As Worksheet
Dim product As String
Dim wb As Workbook
Dim d As Double
Dim points As Long
Dim i As Long
Dim ul As Variant
Dim ch1 As ChartObject
Dim sName As String
Dim s As Series
Set Sheet3 = Sheets("FilteredData")
Set ws = Worksheets("PivotTable")
If (LChart = True) Or (FFTChart = True) Then
Set sh = ws.Shapes.AddChart2(XlChartType:=XlChartType.xlLine, Width:=903, Height:=398)
Else
Set sh = ws.Shapes.AddChart2(XlChartType:=XlChartType.xlColumnClustered, Width:=903, Height:=398)
End If
Set ch = sh.Chart
Set pt = ws.PivotTables("PivotTable")
product = Range("D4") 'Used for Chart title. User entered
ch.SetSourceData pt.TableRange1
sh.Top = pt.TableRange1.Top
sh.Left = pt.TableRange1.Left + pt.TableRange1.Width + 10
ch.Axes(xlValue, xlPrimary).HasTitle = True
ch.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = SelectedUnit
ch.Axes(xlValue, xlPrimary).AxisTitle.Font.Bold = True
ch.Axes(xlValue, xlPrimary).AxisTitle.Font.Size = 12
ch.ChartArea.Border.LineStyle = xlSolid
If (LChart = True) Then
ch.Axes(xlCategory, xlPrimary).HasMajorGridlines = False
Else
ch.Axes(xlCategory, xlPrimary).HasMajorGridlines = True
End If
ch.HasTitle = True
TitleText = ws.Range("B4")
ch.ChartTitle.Font.Bold = True
ch.ChartTitle.Text = TitleText & " " & "(" & SelectedMeas & ")" & Chr(10) & "(" & product & ")"
ch.HasLegend = True
d = 22 'Use as upper limit (ul)
points = Sheet3.Cells(Sheet3.Rows.Count, 1).End(xlUp).Row - 1
ReDim ul(0 To 0)
For i = 0 To points - 1
ul(i) = d
If i <> points - 1 Then ReDim Preserve ul(0 To i + 1)
Next i
Worksheets("PivotTable").Activate 'worked
ActiveSheet.ChartObjects("Chart 1").Activate 'worked
**Set s = ch1.Chart.SeriesCollection.NewLines** 'ERROR - Run-time'91' Object variable or With block variable not set
sName = "Upper Limit"
With s
.Name = sName
.Values = ul
End With

Resources