New Drawing Sheets Base off Excel Table?

New Drawing Sheets Base off Excel Table?

brianmD486F
Enthusiast Enthusiast
1,366 Views
19 Replies
Message 1 of 20

New Drawing Sheets Base off Excel Table?

brianmD486F
Enthusiast
Enthusiast

So i dont know if this is possible or if its just a lot of backend work, but im hoping someone might be able to lead me in the right direction for coding. 

 

Some projects I work on can have a lotttt of sheets and pages. I use Excel to make the basic table as most of the info i need is already in another excel. What i would like is to make a script that would read this table and create new sheets in my IDW based on the Page number/Room Tags (i didnt show entire room for privacy reasons). 

 

Is this something that would be doable or would it be a lot to do. Just trying to speed up some processes I constantly have to go through. 

 

THanks!

 

brianmD486F_0-1690980549337.png

Example of my table i use. This is inside my IDW but referencing a table from Excel i saved out. 

0 Likes
Accepted solutions (3)
1,367 Views
19 Replies
Replies (19)
Message 2 of 20

WCrihfield
Mentor
Mentor

Hi @brianmD486F.  Just to make sure fully I understand the task...You want an iLogic rule, that when you run it, you want it to find this specific Excel file in your file system, then read all of its data from the first two columns, and an unknown number of rows, then use that data to create a series of new Sheets within the already 'active' drawing, and each sheet will be named somehow using the data of those two pieces of data from a row in the Excel data (Page Number & Room Tag?  Does that sound correct?  How do you want to specify where to find this Excel file?  Is including the full path, file name, and extension of the file within the code OK, or do you need something more dynamic?  Also, what about the name of the worksheet/tab within the Excel file?  Should that simply be a static String within the code, or do you need the code to present you with a list of available tabs, so you can choose one.  Will there be more than one worksheet/tab within the Excel file?   How should the sheet's name be formatted using those two pieces of data...could you give some examples?  Will the number of rows be known, or will that need to be determined by the code when the rule runs?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 3 of 20

brianmD486F
Enthusiast
Enthusiast

Hi @WCrihfield Sure let me see if i can add more details for you 🙂

 

Heres an example of how its written out on the sheet names when we make new ones:

 

brianmD486F_0-1690983115722.png

Note: I'm not concerned about the .1 .2 .3 pages as those are added as needed based on my elevation and need for details. 

 

So they will go Sheet (Excel page number) - (excel room tag) 

 

For file location: It'll generally be saved into a job folder that I don't mind going in and directing where that might be per project. If its easier to keep all the separate excel files in a single folder that can be arranged too. This is open to what's easiest or best recommended. Not picky about this part.

 

The quantity of rows is going to be constantly different per project, so I won't ever know till I'm getting ready to start my IDW up. I don't mind going into a code to add the quantity if needed. Whatever would make it easier. 

 

For the excel file format I was figuring this would be very basic. Just 1 sheet and 2 columns. Rows will be the variable. 

 

brianmD486F_2-1690983500687.png

 

I don't plan on having these change or adding more. The tables are just basic and keep me from having to retype every sheet over and over. 

 

If you need more details or if i missed a question let me know! Appreciate your help on it!

 

0 Likes
Message 4 of 20

WCrihfield
Mentor
Mentor

Hi @brianmD486F.  There are likely a lot of possible code paths to make something like that happen, but here is something I customized to your needs.  I put most of the complicated Excel related stuff down into a separate custom Function for you, to make the main routine shorter and less complicated looking.  You will need to edit few things within the Sub Main area of the code though, like the sExcelFile variable's value (the full path, name, & extension of the Excel file), and optionally the sheet name, and the two index numbers.  I put comments after the two index numbers, to clarify what they represent, but they may not need to be changed.  Those are needed because sometimes folks have column headers and sometimes they do not, so this allows us to ignore the first row if it is just column headers.  The same for rows.  Sometimes you may have row labels in the first column, and sometimes you may not, and this column index allows us to ignore that row if set right.  The code basically opens the Excel file.  Then gets the bounds of the data present on the sheet, starting with those specified indices for where the data starts, and inspecting how many rows & columns are being used.  Then it copies all that data into a 2 dimensional Array of Object (because the data may be String, Double, or other data types), then closes the Excel file, because it is no longer needed.  Then it loops through that array of data by each row, gets the two pieces of data for the row, then uses them to form a sheet name.  Then first tries to find an existing sheet by that name first, so it will not try to duplicate one, then if that fails, it creates a new sheet, then renames it to the name it formed.

Give this a try, and let me know how it works for you.

AddReference "Microsoft.Office.Interop.Excel.dll"
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Excel
Sub Main
	If ThisDoc.Document.DocumentType <> DocumentTypeEnum.kDrawingDocumentObject Then
		MsgBox("A Drawing document must be active for this code to work. Exiting.", vbCritical, "iLogic")
		Exit Sub
	End If
	Dim oDDoc As DrawingDocument = ThisDoc.Document
	Dim oSheets As Inventor.Sheets = oDDoc.Sheets
	Dim sExcelFile As String = "C:\Temp\Testing123.xlsx"
	Dim sExcelSheetName As String = "Sheet1"
	Dim iFirstRowOfData As Integer = 2 'second row is first row of data (not column headers)
	Dim iFirstColumnOfData As Integer = 1 'first column contains data (not row labels)
	Dim oData(,) As Object = Get2DArrayOfDataFromExcel(sExcelFile, iFirstRowOfData, iFirstColumnOfData, sExcelSheetName)
	If oData Is Nothing OrElse oData.Length = 0 Then
		Logger.Info("No data returned from the Function.")
		Exit Sub
	End If
	Logger.Info("You retrieved " & oData.Rank & " columns and " & oData.GetLength(0) & " rows of data.")
	For iRow As Integer = LBound(oData,1) To UBound(oData, 1)
		Dim sPageNo As String = oData(iRow, 1).ToString
		Dim sRoomTag As String = oData(iRow, 2).ToString
		Dim sSheetName As String = "Sheet " & sPageNo & " - " & sRoomTag
		Dim oNewSheet As Inventor.Sheet = Nothing
		Try
			oNewSheet = oSheets.Item(sSheetName)
		Catch
			oNewSheet = oSheets.Add()
			oNewSheet.Name = sSheetName
		End Try
	Next 'iRow
End Sub

Function Get2DArrayOfDataFromExcel(sFullFileName As String, iStartRow As Integer, _
iStartColumn As Integer, Optional sSheetName As String = vbNullString) As Object(, )
	If sFullFileName = "" Then Exit Function
	If System.IO.File.Exists(sFullFileName) = False Then Exit Function
	Dim oExcel As Excel.Application = Nothing
	Dim bAppStarted As Boolean = False
	Try
		oExcel = GetObject("", "Excel.Application")
	Catch
		oExcel = CreateObject("Excel.Application")
		bAppStarted = True
	End Try
	If oExcel Is Nothing Then Exit Function
	oExcel.DisplayAlerts = False
	oExcel.Visible = False
	Dim oWB As Excel.Workbook = Nothing
	Try : oWB = oExcel.Workbooks.Open(sFullFileName) : Catch : End Try
	If oWB Is Nothing Then Exit Function
	Dim oWS As Excel.Worksheet = Nothing
	If String.IsNullOrEmpty(sSheetName) Then
		Try : oWS = oWB.Sheets.Item(1) : Catch : End Try
	Else
		Try : oWS = oWB.Sheets.Item(sSheetName) : Catch : End Try
	End If
	If oWS Is Nothing Then Exit Function
	Dim iLastColumnUsed As Integer = oWS.UsedRange.Columns.Count
	Dim iLastRowUsed As Integer = oWS.UsedRange.Rows.Count
	Dim oFirstCell As Excel.Range = oWS.Cells.Item(iStartRow, iStartColumn)
	Dim oLastCell As Excel.Range = oWS.Cells.Item(iLastRowUsed, iLastColumnUsed)
	Dim oRange As Excel.Range = oWS.Range(oFirstCell.Address, oLastCell)
	Dim oData(, ) As Object = oRange.Value
	oWB.Close
	If bAppStarted = True Then oExcel.Quit
	Return oData
End Function

...and if needed, the main routine can be greatly improved upon with things like the ability to browse for the Excel file, use an InputBox type prompt for you to enter any needed data, ask preliminary question(s) before proceeding, and other such functionality later on.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 20

brianmD486F
Enthusiast
Enthusiast

@WCrihfield 

 

Wow thank you for this!!!

 

I am getting hung up on line 48. Updated line 11 with the pathing/file name. 

 

brianmD486F_0-1690998159987.png

brianmD486F_1-1690998179145.png

 

Unfortunately, this goes over my head as to what's wrong or how to mess with it to work haha. 

0 Likes
Message 6 of 20

WCrihfield
Mentor
Mentor

OK, I have definitely see that error before many times.  Some folks have that problem, and some do not.  The first, and simplest think I would have you try is to change this line:

Dim oExcel As Excel.Application = Nothing

...to this:

Dim oExcel As Object = Nothing

Sometimes that will help some.  However, that will also cause the object type recognition to stop working for that object variable, which means when you hover your mouse over those variables that represent that object, there will not be any Intellisense suggestions to help you identify what they are, and nothing will pop-up after you type in a dot after one of them, to show you what options are available.  But the code should still work, even though that Type may not be recognized.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 7 of 20

brianmD486F
Enthusiast
Enthusiast
Ok so I made the change and the script is running through. I can see it take a few to probably process and read the file, but after its done nothing got added.
0 Likes
Message 8 of 20

WCrihfield
Mentor
Mentor

OK.  I am not sure what might be causing that.  When I ran the code on a new drawing document, and pointed it at a test Excel file with two columns of data, it also paused for a few seconds, but then created about 27 sheets for me.  Maybe I should have left all of the lines code in there for providing feedback data through the iLogic Logger, and/or MsgBox's, because that might have given us a better idea about where it is encountering a problem.  Did you check in your iLogic Log tab to see if it wrote anything in there when you ran the rule?  It should have reported about how many rows and columns of data it returned from the custom Function, or if no data was returned from the function.  Even if those sheets already existed, it should have still created them, because it allows duplicate sheet names, since it automatically adds the little sheet number after the name.  I did not think of that when I originally created that rule, but that should not hurt anything other than maybe having to click the UNDO button a bunch, or delete a bunch of sheets if you accidentally ran the rule twice in a row.

 

Have you tried forcing the document to do an update, by going to the Manage tab, Update panel, and clicking the Update All Sheets button after running the rule, just to see if that causes them to show up?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 20

brianmD486F
Enthusiast
Enthusiast

 So I did check to see if the update pages would work but now seeing that no data returned for me, im thinking it possible didn't actually create anything for me.  I tried making a new document to test in case the old was backlogged or something hidden but same results.  It runs and thinks for a little and then nothing. Checked the log and heres what i got. 

 

INFO| 9: >>---------------------------
INFO|No data returned from the Function.
INFO| 10: >>---------------------------
INFO|No data returned from the Function.

 

I went and tried to run a Trace from this and results:

 

TRACE|Entering rule: Sheet Write (in Drawing3)
INFO|No data returned from the Function.
TRACE|Exiting rule: Sheet Write (in Drawing3)

 

I see the lines saying that if no data to return 0 info so thinking its getting caught up there? Should i mess around with the integers for row/column data and see if that fixes anything? Dont know if it matters either but in my excel file all the info is set to 'Text' And not general. Let me know if that might have something to do with it too. 

 

Minus the Location for the file was there anything more I needed to go in and update? I was reading through it but didnt see if there was more that i needed to input as well.

 

0 Likes
Message 10 of 20

WCrihfield
Mentor
Mentor
Accepted solution

Hi @brianmD486F.  Sorry for the delay.  Here is a very simplified version of my previous code, which exclusively uses the iLogic GoExcel functionality, instead of the Excel API and those external references.  In this version, since those tools do not have a good way of retrieving a 2-dimensional array of data (other than the NamedRangeValue tool), I chose to get the data from those two columns into two parallel IList collections instead.  I just hope that the two lists stay in the same order that the column data was in.  They did seem to be OK in my brief testing.  I also included a 'Transaction', which will wrap all the sheet creations up into one item in the UNDO list for you, just in case you want to undo what the rule did.  Give this a try, and let me know how this works for you.

Sub Main
	If ThisDoc.Document.DocumentType <> DocumentTypeEnum.kDrawingDocumentObject Then
		MsgBox("A Drawing document must be active for this code to work. Exiting.", vbCritical, "iLogic")
		Exit Sub
	End If
	Dim oDDoc As DrawingDocument = ThisDoc.Document
	Dim oSheets As Inventor.Sheets = oDDoc.Sheets
	Dim sExcelFile As String = "C:\Temp\Testing123.xlsx"
	Dim sExcelSheetName As String = "Sheet1"
	If System.IO.File.Exists(sExcelFile) = False Then
		Logger.Debug("Specified Excel file does not exist.")
		Exit Sub
	End If
	GoExcel.Open(sExcelFile)
	GoExcel.DisplayAlerts = False
	'<<< Change 100 to something else if needed >>>
	Dim oColAVals, oColBVals As IList
	Try
		oColAVals = GoExcel.CellValues("A2", "A100")
	Catch
		Logger.Error("Error getting column A values.")
	End Try
	If oColAVals Is Nothing OrElse oColAVals.Count = 0 Then Exit Sub
	Try
		oColBVals = GoExcel.CellValues("B2", "B100")
	Catch
		Logger.Error("Error getting column B values.")
	End Try
	GoExcel.ClearCache
	GoExcel.Close
	If oColBVals Is Nothing OrElse oColBVals.Count = 0 Then Exit Sub
	Dim oTrans As Inventor.Transaction
	oTrans = ThisApplication.TransactionManager.StartTransaction(oDDoc, "Create Sheets From Excel")
	For iRow As Integer = 0 To oColAVals.Count - 1
		Dim sPageNo As String = oColAVals.Item(iRow).ToString
		Dim sRoomTag As String = oColBVals.Item(iRow).ToString
		Dim sSheetName As String = "Sheet " & sPageNo & " - " & sRoomTag
		Dim oNewSheet As Inventor.Sheet = Nothing
		Try
			oNewSheet = oSheets.Add()
			oNewSheet.Name = sSheetName
		Catch
			Logger.Error("Error adding a new Sheet named:  " & sSheetName)
		End Try
	Next 'iRow
	oTrans.End
	oDDoc.Update2(True)
	MsgBox("Sheet Creation Process Done", vbInformation, "DONE")
End Sub

If this solved your problem, or answered your question, please click ACCEPT SOLUTION .
Or, if this helped you, please click (LIKE or KUDOS) 👍.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 11 of 20

brianmD486F
Enthusiast
Enthusiast

@WCrihfield 

Yup this works beautifully you are amazing! So just 2 additions if plausible. 

 

1. Is there a way for it to autoload a specific title block/border when it makes the new sheet?

2. Is there a way to set it to a default size when it makes the new sheets? (this one isnt that bad as i can just select all and right click edit sheet) 

 

brianmD486F_0-1691088643566.png

 

I was messing with it to see if i could figure out where to place some extra lines to adjust the Sheet Size/Boarder/Add Title Block, but probably not putting in the right spot or have the right code to switch it.

 

ActiveSheet.ChangeSize("ArchD-Format", moveBorderItems := True)

ActiveSheet.TitleBlock = "ArchD-Titleblock"

ActiveSheet.Border = "ArchD-Border"

 

But really ty for the help this will save so much time and energy with some of these big projects. 

0 Likes
Message 12 of 20

WCrihfield
Mentor
Mentor

Definitely possible, but leaving for the day right now.  Hopefully I will remember to look at this again tomorrow.  The 'ActiveSheet' term is a special iLogic term, and will only work on the currently 'active' sheet, so not the best for this situation.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 13 of 20

brianmD486F
Enthusiast
Enthusiast
No worries im going to keep messing with this and figure it out! This was a big help and no biggy. Worst case if its okay and after a few days i cant get it Ill reach out again hahaha.

Thank you for this and all the help you have been doing here.
0 Likes
Message 14 of 20

WCrihfield
Mentor
Mentor
Accepted solution

Hi @brianmD486F.  Within 'try' side of the last Try...Catch block of code, where it is creating the new sheet, that is using the Sheets.Add method (using the "oSheets" variable that was declared near the start of that code, not the 'ActiveSheet' term).  When using that method, you can specify what sheet size you want it to be as a variation of the DrawingSheetSizeEnum.  And you can specify what page orientation you want it to be as a variation of the PageOrientationTypeEnum.  And you can specify sheet name.  And then, only if you specified the 'custom' variation for the sheet size, you can then specify the sheet width, then the sheet height, as the last two inputs into that method.  On the other hand, there is also a Sheets.AddUsingSheetFormat method, which will allow you to specify a SheetFormat to use when it creates the new sheet, which can be really useful at times, but requires a pre-existing SheetFormat that is the way you want it.  You can read about its requested inputs at the link provided, if you are interested in that route.

As for Border and TitleBlock...after that line of code, we now have the 'oNewSheet' variable, representing that new Sheet that was just created, so we will use that as our reference for adding a Border & TitleBlock  in some additional lines of code just after that line.  There are two methods available for adding a Border (AddBorder & AddDefaultBorder).  If you have a pre-existing BorderDefinition  in your drawing that you want to use, then you will want to use the regular AddBorder method, otherwise you will want to use the AddDefaultBorder method.  Then, there is just one method for adding a TitleBlock (AddTitleBlock).  The first requested input for both the AddBorder and the AddTitleBlock methods, will accept either the 'definition' type object (BorderDefinition or TitleBlockDefinition) or a String representing the name of the definition.  Then the second input for the AddTitleBlock method is to specify its location (which corner of the sheet), which is specified as a variation of the TitleBlockLocationEnum.  The last optional input for both methods is only for if your border or title block contained any prompted entries, and allows you an opportunity to supply the input values for those, but if you do not have them, you do not need to supply anything there.

So...here is a block of code you can swap out in that last code:

You can replace this block of code:

		Try
			oNewSheet = oSheets.Add()
			oNewSheet.Name = sSheetName
		Catch
			Logger.Error("Error adding a new Sheet named:  " & sSheetName)
		End Try

...with this block of code:

		Dim oSheetSize As DrawingSheetSizeEnum = DrawingSheetSizeEnum.kDDrawingSheetSize
		Dim oPageOrientation As PageOrientationTypeEnum = PageOrientationTypeEnum.kDefaultPageOrientation
		oNewSheet = oSheets.Add(oSize, oPageOrientation, sSheetName)
		'if the sheet already has a Border, and it is not the right one, it must be deleted before adding another
		If oNewSheet.Border IsNot Nothing AndAlso oNewSheet.Border.Name <> "ArchD-Border" Then
			oNewSheet.Border.Delete
		End If
		Try 'if it can not find a BorderDefinition by this name, it will throw an error
			oNewSheet.AddBorder("ArchD-Border")
		Catch
			Logger.Error("Error adding a Border based on a BorderDefinition named 'ArchD-Border'.")
		End Try
		'if the sheet already has a TitleBlock, this will simply replace it for you
		Try 'if it can not find a TitleBlockDefinition by this name, it will throw an error
			'the location part is optional, and if not specified, it used the sheet's own spec for where it should go
			oNewSheet.AddTitleBlock("ArchD-Titleblock", TitleBlockLocationEnum.kBottomRightPosition)
		Catch
			Logger.Error("Error adding a TitleBlock based on a TitleBlockDefinition named 'ArchD-Titleblock'.")
		End Try

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 15 of 20

brianmD486F
Enthusiast
Enthusiast

@WCrihfield 

Wow. Im going to be going through all the links to soak in what I can. This makes sense and doing a little googling and seeing some other codes I saw/understand what you mean by the ActiveSheet isn't going to work haha. Appreciate the explanations of it all to cause this is making it easier to grasp some of this now. 

 

So as your comment in the code said it would error out if it couldn't find the name. 

oNewSheet = oSheets.Add(oSize, oPageOrientation, sSheetName)

brianmD486F_3-1691153157780.png

brianmD486F_4-1691154093466.png

 

From the iLogic Log:

 

ERROR|Error adding a Border based on a BorderDefinition named 'ArchD-Border'.
ERROR|Error adding a TitleBlock based on a TitleBlockDefinition named 'ArchD-TitleBlock'.

 

Tho I don't know why because those are the names under the drawing resources. 

0 Likes
Message 16 of 20

WCrihfield
Mentor
Mentor

Hi @brianmD486F.  I think I see why you are seeing an error.  My mistake...I am using the wrong variable name in the oSheets.Add line for the sheet size spec.  The variable I created just two lines above that was "oSheetSize", and I forgot to change the variable for that from "oSize" to "oSheetSize" in the oSheets.Add method.  I believe that if you copy the oSheetSize variable, and replace the oSize variable in that Add line, that should fix it.  I could not test the code this time, because I do not have those border & title block definitions.  Sorry about that.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 17 of 20

brianmD486F
Enthusiast
Enthusiast

@WCrihfield 

Yup that worked, so it creates all the pages now and then adds the boarder. With the resources you gave me earlier going to mess with adjusting the sheet size. Giving me Size "D" 22x36 but just need it up t0 24x36 So this will be a good exercise for me.

 

Tho for some reason its still hanging on my titleblock name. Which is stumping me cause the name isnt wrong. I checked to see if Case sensitive to and everything looks right. 

 

Edit: Okay so i changed it out to the default "ANSI - Large" And it added that no problem. 

Edit2: Okay so got the paper size working np after looking at the rescources for DrawingSheetSizeEnum So got that covered. So our titleblock does have prompt entries and wondering if that might be an issue? Didnt mention that part but didnt realize it could affect it by chance? 

 

Edit3: Okay so after doing some more messing around I tried going and replacing the data in the ANSI - Large that worked, with our currently title block. Goes through the same issue after doing that, that it cant find the titleblock. So I have to assume that its our actual title block information thats screwing things up. Im gonna keep messing with it and see if I cant pinpoint what inside of the TB actually causing the issue.

 

0 Likes
Message 18 of 20

brianmD486F
Enthusiast
Enthusiast

@WCrihfield 

 

Okay so it def has to do with what's inside our title block causing the issues. I went and deleted all the entry prompts, and they loaded the block no problem. So found the problem! hahaha

0 Likes
Message 19 of 20

WCrihfield
Mentor
Mentor
Accepted solution

OK.  Good to hear.  However, if you want to keep your title block the way it was, you may simply need to supply something in the requested prompt entries part of the oNewSheet.AddTitleBlock method.  It has a place for that type of data, but it can get more complicated when they are involved.  Right in the descriptions for that method, it says that if your title block definition includes prompted entries, then you must provide something to fill those in, or the method will fail.  However, filling hose in correctly can be a bit complicated to get set up just right.  I have worked with a few different folks here on the forums to help them fill in these entries, or edit existing entries after the fact.  You will need to supply the exact number of entries that it is asking for or it will fail/error.  And you will need to make sure that the entry values you provide are supplied in the correct order too, or you may be filling in wrong data to wrong locations.  To figure out the correct order, you need to inspect all of the Inventor.TextBox objects within your TitleBlockDefinition object's sketch, and check which ones it comes to first, second, and so on, and which ones are for which prompts.  You could just try to supply an Array of String that has the right number of entries (Array.Length), but where each entry simply contains nothing (or empty String), then remember to manually edit those later manually.  Or, like you just did, you could eliminate all the prompted entries from your title block definition.  Whatever works best for you.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 20 of 20

brianmD486F
Enthusiast
Enthusiast

@WCrihfield 

Thank you again for all the help and work on this. There will be some work arounds I can be okay with. Yeah, looking at some previous posts when a was digging around it sounds like prompt entries are a pain to calculate for and code in because of all the backend work to figure out which ones they are and the data. For now though this still saves me a bunch of time not having to write out all the sheet names and the likes. I can easily just 'Insert' the titleblock into the sheets as I'm going, and boom done. 

 

Brilliant work and again thank you for everything!

0 Likes