What's new

Scripting Help Please

albie0803

Alibre Super User
I'm trying (and failing) to merge a script with 4 windows into 1

Existing script snippet:
Python:
import glob
import os
import re

HData = {}
# HData[Size][Width]=[thick,root,toe],[thick,root,toe]
HData[65]={}
HData[65][50]=[4.6,6,3],[6,6,3],[7.8,6,3]
HData[75]={}
HData[75][50]=[4.6,7,3],[6,7,3],[7.8,7,3]
HData[100]={}
HData[100][75]=[6,8,5],[7.8,8,5],[9.5,8,5]
HData[125]={}
HData[125][75]=[6,8,5],[7.8,8,5],[9.5,8,5],[12,8,5]
HData[150]={}
HData[150][90]=[7.8,10,5],[9.5,10,5],[12,10,5],[15.8,10,5]
HData[150][100]=[9.5,10,5],[12,10,5],[20,10,5]

# width
Width = 75.0
# base thickness
Thick = 6
# root radius
Rr = 10
# toe radius
Rt = 10
# length
Length = 25
readTh = 0

# called when an input changes in the dialog window
def InputChangedL(Index, Value):
  # size changed
  if Index == 0:
    global Height
    Height = float(LNames[Value])

def InputChangedW(Index, Value):
  # size changed
  if Index == 0:
    global Width
    Width = float(WNames[Value])
    
def InputChangedT(Index, Value):
  # size changed
  if Index == 0:
    global Thick
    Thick = float(TNames[Value])
    
# called when user confirms selections
def SelectionMadeL(Values):
  # get values
  global Height
  Height = float(LNames[Values[0]])

def SelectionMadeW(Values):
  # get values
  global Width
  Width = float(WNames[Values[0]])

def SelectionMadeT(Values):
  # get values
  global Thick
  Thick = float(TNames[Values[0]])
Win = Windows()

DialogWidth = 100
 
LNames = list()   
for i,j in enumerate(HData):
    LNames.append(str(j))

Options = []
Options.append(['UA Height', WindowsInputTypes.StringList, LNames, Length])
Win.UtilityDialog('Length', 'Apply', SelectionMadeL, InputChangedL, Options, DialogWidth)

WData = HData[Height]

WNames = list()
for i,j in enumerate(WData):
    WNames.append(str(j))

Options = []
Options.append(['UA Width', WindowsInputTypes.StringList, WNames, Width])
Win.UtilityDialog('Width', 'Apply', SelectionMadeW, InputChangedW, Options, DialogWidth)

TNames = list()
for i,j in enumerate(WData[Width]):
    TNames.append(str(j[0]))

Options = []
Options.append(['UA Thickness', WindowsInputTypes.StringList, TNames, Thick])
Win.UtilityDialog('Thickness', 'Apply', SelectionMadeT, InputChangedT, Options, DialogWidth)

sum = 0
for i in TNames:
    if i == Thick:
      print i
      print sum
      readTh = sum
    sum += 1
    
Rr = WData[Width][readTh][1]
Rt = WData[Width][readTh][2]

##Input a value window
Lth = 200
Options = []
Options.append(["UA Length", WindowsInputTypes.Real, Lth])
Values = Win.OptionsDialog("Thickness", Options)

#print('Please input length in mm')
Length = int(Values[0])

This is as far as I have got:

Python:
import glob
import os
import re

Win = Windows()

HData = {}
# HData[Size][Width]=[thick,root,toe],[thick,root,toe]
HData[65]={}
HData[65][50]=[4.6,6,3],[6,6,3],[7.8,6,3]
HData[75]={}
HData[75][50]=[4.6,7,3],[6,7,3],[7.8,7,3]
HData[100]={}
HData[100][75]=[6,8,5],[7.8,8,5],[9.5,8,5]
HData[125]={}
HData[125][75]=[6,8,5],[7.8,8,5],[9.5,8,5],[12,8,5]
HData[150]={}
HData[150][90]=[7.8,10,5],[9.5,10,5],[12,10,5],[15.8,10,5]
HData[150][100]=[9.5,10,5],[12,10,5],[20,10,5]

# Height
Height = 65
# width
Width = 50
# base thickness
Thick = 4.6
# length
Length = 0
# root radius
Rr = 10
# toe radius
Rt = 10

readTh = 0

# called when an input changes in the dialog window
def onchange(Index, Value):
  global Height
  global Width
  global Thick
  # size changed
  if Index == 0:
    Height = float(HNames[Value])
    WData = HData[Height]
    for i,j in enumerate(WData):
      WNames.append(str(j))
      Win.SetStringList(1,WNames)
  elif Index == 1:
    Width = float(WNames[Value])
    for i,j in enumerate(WData[Width]):
      TNames.append(str(j[0]))
      Win.SetStringList(2,TNames)
  elif Index == 2:
    for i,j in enumerate(WData[Width]):
      TNames.append(str(j[0]))
    Thick = float(TNames[Value])
    Rr = WData[Width][Thick][1]
    Rt = WData[Width][Thick][2]

def updateui():
#  to define a UI start
  pass

HNames = list()   
for i,j in enumerate(HData):
    HNames.append(str(j))
    
WNames = list()
TNames = list()

Options = []
Options.append(['UA Height', WindowsInputTypes.StringList, HNames, Height])
Options.append(['UA Width', WindowsInputTypes.StringList, WNames, Width])
Options.append(['UA Thickness', WindowsInputTypes.StringList, TNames, Thick])
Options.append(["UA Length", WindowsInputTypes.Real, Length])
Values = Win.OptionsDialog('Create Unequal Angle', Options, 50, onchange, updateui)

Can someone please fix up the code so that fields 1 and 2 properly populate?

I will then use this as a template to do the same with 4 other scripts which were originally built the same way.

Many, many thanks in advance.
Allan
 

jfleming

Alibre Super User
Albie, I do not know anything about Python code, but I put it into ChatGPT and asked for it to correct it:. If this is not of any help, I am sorry. I felt it would be an interesting experiment...




import glob
import os
import re
from pyrevit import revit, DB

Win = revit.GetApp().CreateDialog()

HData = {}
# HData[Size][Width]=[thick,root,toe],[thick,root,toe]
HData[65] = {}
HData[65][50] = [[4.6, 6, 3], [6, 6, 3], [7.8, 6, 3]]
HData[75] = {}
HData[75][50] = [[4.6, 7, 3], [6, 7, 3], [7.8, 7, 3]]
HData[100] = {}
HData[100][75] = [[6, 8, 5], [7.8, 8, 5], [9.5, 8, 5]]
HData[125] = {}
HData[125][75] = [[6, 8, 5], [7.8, 8, 5], [9.5, 8, 5], [12, 8, 5]]
HData[150] = {}
HData[150][90] = [[7.8, 10, 5], [9.5, 10, 5], [12, 10, 5], [15.8, 10, 5]]
HData[150][100] = [[9.5, 10, 5], [12, 10, 5], [20, 10, 5]]

# Height
Height = 65
# width
Width = 50
# base thickness
Thick = 4.6
# length
Length = 0
# root radius
Rr = 10
# toe radius
Rt = 10

readTh = 0

# called when an input changes in the dialog window
def onchange(Index, Value):
global Height
global Width
global Thick
global HNames
global WNames
global TNames
global Win
# size changed
if Index == 0:
Height = float(HNames[Value])
WData = HData[Height]
WNames = []
for i, j in enumerate(WData):
WNames.append(str(j))
Win.SetStringList(1, WNames)
elif Index == 1:
Width = float(WNames[Value])
TNames = []
for i, j in enumerate(HData[Height][Width]):
TNames.append(str(j[0]))
Win.SetStringList(2, TNames)
elif Index == 2:
Thick = float(TNames[Value])
Rr = HData[Height][Width][Thick][1]
Rt = HData[Height][Width][Thick][2]

def updateui():
# to define a UI start
pass

HNames = []
for i, j in enumerate(HData):
HNames.append(str(j))

WNames = []
TNames = []

Options = []
Options.append(['UA Height', 'StringList', HNames, Height])
Options.append(['UA Width', 'StringList', WNames, Width])
Options.append(['UA Thickness', 'StringList', TNames, Thick])
Options.append(["UA Length", 'Real', Length])
Values = Win.OptionsDialog('Create Unequal Angle', Options, 50, onchange, updateui)



Here's what has been changed:
Imported the necessary modules, including pyrevit for creating a dialog. 2. Fixed the import statement for Windows.
  1. Changed the list syntax for storing the data in HData to use square brackets instead of parentheses.
  2. Added missing WindowsInputTypes module import.
  3. Corrected the access to WindowsInputTypes by prefixing it with the module name.
  4. Added missing revit.GetApp().CreateDialog() to create the dialog object.
  5. Added global statements for the variables that need to be modified within the onchange function.
  6. Added missing initialization for HNames, WNames, and TNames before using them in the onchange function.
  7. Corrected the assignment of WNames and TNames within the onchange function.
  8. Removed the unnecessary readTh variable.
  9. Replaced the Values assignment with the corrected Options list.
Please note that the code assumes the use of the pyrevit library for creating the dialog. Make sure you have the necessary dependencies installed to run this code successfully.
 

Attachments

  • Fix Python Code.png
    Fix Python Code.png
    335.9 KB · Views: 6

NateLiquidGravity

Alibre Super User
I can tell you ChatGPT got it wrong without trying it. This is 100% b.s. Win = revit.GetApp().CreateDialog()

I attempted to make a similar dialog with multiple dynamic dropdowns a while back, but I can't try it anymore as some update broke StringLists on Windows 7. I eventually gave up and just made my own using WinForms.
 

idslk

Alibre Super User
Hello Allan,

not knowing the rest of the script, you may try the following:
Python:
import glob
import os
import re

Win = Windows()

HData = {}
# HData[Size][Width]=[thick,root,toe],[thick,root,toe]
HData[65]={}
HData[65][50]=[4.6,6,3],[6,6,3],[7.8,6,3]
HData[75]={}
HData[75][50]=[4.6,7,3],[6,7,3],[7.8,7,3]
HData[100]={}
HData[100][75]=[6,8,5],[7.8,8,5],[9.5,8,5]
HData[125]={}
HData[125][75]=[6,8,5],[7.8,8,5],[9.5,8,5],[12,8,5]
HData[150]={}
HData[150][90]=[7.8,10,5],[9.5,10,5],[12,10,5],[15.8,10,5]
HData[150][100]=[9.5,10,5],[12,10,5],[20,10,5]

# Height
Height = 65
# width
Width = 50
# base thickness
Thick = 4.6
# length
Length = 0
# root radius
Rr = 10
# toe radius
Rt = 10

readTh = 0

# called when an input changes in the dialog window
def onchange(Index, Value):
  global Height
  global Width
  global Thick
  global WData
  global WNames
  global TNames
  # size changed
  if Index == 0:
    Height = float(HNames[Value])
    WData = HData[Height]
    if len(WNames)>0:
      del WNames
      WNames=[]
    for i,j in enumerate(WData):
      WNames.append(str(j))
    Win.SetStringList(1,WNames)
  elif Index == 1:
    Width = int(WNames[Value])
    if len(TNames)>0:
      del TNames
      TNames=[]
    for i,j in enumerate(WData[Width]):
      TNames.append(str(j[0]))
    Win.SetStringList(2,TNames)
  elif Index == 2:
    Thick = TNames.index(TNames[Value])
    Thickname = TNames[Value]
    Rr = WData[Width][Thick][1]
    Rt = WData[Width][Thick][2]
    print "Height",Height,"Width",Width,"Thick",Thickname,"Rr",Rr,"Rt",Rt

def updateui():
#  to define a UI start
  pass

HNames = list()  
for i,j in enumerate(HData):
    HNames.append(str(j))
   
WNames = list()
TNames = list()

Options = []
Options.append(['UA Height', WindowsInputTypes.StringList, HNames, Height])
Options.append(['UA Width', WindowsInputTypes.StringList, WNames, Width])
Options.append(['UA Thickness', WindowsInputTypes.StringList, TNames, Thick])
Options.append(["UA Length", WindowsInputTypes.Real, Length])
Values = Win.OptionsDialog('Create Unequal Angle', Options, 50, onchange, updateui)

If there are any questions...feel free...

Regards
Stefan
 
Last edited:

NateLiquidGravity

Alibre Super User
Your data structure is a little difficult to read. Just a personal preferences. I might use a class and some helper functions like this:
Python:
class Angle:
    def __init__(self, height, width, thickness, root_radius, toe_radius):
        self.Height = height
        self.Width = width
        self.Thickness = thickness
        self.RootRadius = root_radius
        self.ToeRadius = toe_radius

    def __str__(self):
        attributes = [
            "Height: " + str(self.Height),
            "Width: " + str(self.Width),
            "Thickness: " + str(self.Thickness),
            "RootRadius: " + str(self.RootRadius),
            "ToeRadius: " + str(self.ToeRadius)
        ]
        return "\n".join(attributes)

# Angle(height, width, thickness, root_radius, toe_radius)
angles = [
Angle(65, 50, 4.6, 6, 3),
Angle(65, 50, 6, 6, 3),
Angle(65, 50, 7.8, 6, 3),
Angle(75, 50, 4.6, 7, 3),
Angle(75, 50, 6, 7, 3),
Angle(75, 50, 7.8, 7, 3),
Angle(100, 75, 6, 8, 5),
Angle(100, 75, 7.8, 8, 5),
Angle(100, 75, 9.5, 8, 5),
Angle(125, 75, 6, 8, 5),
Angle(125, 75, 7.8, 8, 5),
Angle(125, 75, 9.5, 8, 5),
Angle(125, 75, 12, 8, 5),
Angle(150, 90, 7.8, 10, 5),
Angle(150, 90, 9.5, 10, 5),
Angle(150, 90, 12, 10, 5),
Angle(150, 90, 15.8, 10, 5),
Angle(150, 100, 9.5, 10, 5),
Angle(150, 100, 12, 10, 5),
Angle(150, 100, 20, 10, 5)
]

def get_unique_heights(angles):
    unique_heights = set()
    for angle in angles:
        unique_heights.add(angle.Height)
    return list(unique_heights)

def get_unique_widths_by_height(angles, height):
    unique_widths = set()
    for angle in angles:
        if angle.Height == height:
            unique_widths.add(angle.Width)
    return list(unique_widths)

def get_unique_thicks_by_height_width(angles, height, width):
    unique_thicks = set()
    for angle in angles:
        if angle.Height == height and angle.Width == width:
            unique_thicks.add(angle.Thickness)
    return list(unique_thicks)
Again - since I can't test the dialog - I'll leave someone else integrate it if they want.
 

albie0803

Alibre Super User
Thanks all for your input. Jason's ChatGPT was enough to fix some errors I had, allowing me to then go on and figure it out.
Nate, the data layout was what I had originally, which I copied from someone here back when scripting first came out. I will be interested to explore what you offer and attempt to get my head around it.
Stefan, I'll be interested to compare what I ended up with, with what you have posted. It looks very similar at first glance. I'll check on Monday.
 

albie0803

Alibre Super User
Hi Guys,

Here is one of the (working) scripts I was working on. It creates Equal Angle lengths in an assembly.
Can someone please modify it so that when you click OK, the program runs but doesn't actually close until Cancel is clicked.
I want to be able to create multiple parts before closing the script.
Example work flow:> Set parameters : OK : Change parameters : OK : Change parameters : OK : Change parameters : OK : Cancel
Thanks in advance
Python:
import glob
import os
import re

Win = Windows()

HData = {}
# HData[Width]=[thick,root,toe],[thick,root,toe]
HData[25]=[3,5,3],[4.6,5,3],[6,5,3]
HData[30]=[3,5,3],[4.6,5,3],[6,5,3]
HData[40]=[3,5,3],[4.6,5,3],[6,5,3]
HData[45]=[3,5,3],[4.6,5,3],[6,5,3]
HData[50]=[3,6,3],[4.6,6,3],[6,6,3],[7.8,6,3]
HData[55]=[4.6,6,3],[6,6,3]
HData[65]=[4.6,6,3],[6,6,3],[7.8,6,3],[9.5,6,3]
HData[75]=[4.6,8,5],[6,8,5],[7.8,8,5],[9.5,8,5]
HData[90]=[6,8,5],[7.8,8,5],[9.5,8,5]
HData[100]=[6,8,5],[7.8,8,5],[9.8,8,5],[12,8,5]
HData[125]=[7.8,10,5],[9.5,10,5],[12,10,5],[15.8,10,5]
HData[150]=[9.5,13,5],[12,13,5],[15.8,13,5],[19,13,5]
HData[200]=[13,18,5],[16,18,5],[18,18,5],[20,18,5],[26,18,5]

# width
Width = 50
# base thickness
Thick = 4.6
# length
Length = 0
# root radius
Rr = 10
# toe radius
Rt = 10

# called when an input changes in the dialog window
def onchange(Index, Value):
  global Width
  global Thick
  global WNames
  global TNames
  global RtVal
  global RrVal
  global Rr
  global Rt
  # size changed
  if Index == 0:
    Width = float(WNames[Value])
    WData = HData[Width]
    TNames = []
    RrVal = []
    RtVal = []
    for i, j in enumerate(WData):
      TNames.append(str(j[0]))
      RrVal.append(str(j[1]))
      RtVal.append(str(j[2]))
    Win.SetStringList(1, TNames)
  elif Index == 1:
    Thick = float(TNames[Value])
    Rr = float(RrVal[Value])
    Rt = float(RtVal[Value])

def updateui():
# to define a UI start
  pass

WNames = []
SNames = []
SNames = sorted(HData, key=lambda key: HData[key])

for i, j in enumerate(SNames):
  WNames.append(str(j))

TNames = []

Options = []
Options.append(['EA Width', WindowsInputTypes.StringList, WNames, Width])
Options.append(['EA Thickness', WindowsInputTypes.StringList, TNames, Thick])
Options.append(["EA Length", WindowsInputTypes.Real, Length])
Values = Win.OptionsDialog('Create Equal Angle', Options, 50, onchange, updateui)

Length = int(Values[2])

# all values are in millimeters
Units.Current = UnitTypes.Millimeters
 
Assy = CurrentAssembly()
 
# Create part
Square = Assy.AddNewPart('Angle %dx%dx%d' % (Width,Width,Length),0,0,0)
 
# Body
Profile = Square.AddSketch('Profile', Square.GetPlane('XY-Plane'))
# Outer square
Line = Polyline()
Line.AddPoint(PolylinePoint(Width/2.,Width/2.))
Line.AddPoint(PolylinePoint(-Width/2.,Width/2.))
Line.AddPoint(PolylinePoint(-Width/2.,-Width/2.))
Line.AddPoint(PolylinePoint((-Width/2.)+Thick,-Width/2.))
Line.AddPoint(PolylinePoint((-Width/2.)+Thick,(Width/2.)-Thick))
Line.AddPoint(PolylinePoint((-Width/2.)+Thick,(Width/2.)-Thick))
Line.AddPoint(PolylinePoint(Width/2.,(Width/2.)-Thick))
Line.AddPoint(PolylinePoint(Width/2.,Width/2.))
Profile.AddPolyline(Line,False)

# Extrude
Square.AddExtrudeBoss('Extrude',Profile,Length,False)
 
# Inner radius
Square.AddFillet('Fillet<1>',[Square.GetEdge('Edge<6>')],Rr,False)
Square.AddFillet('Fillet<2>',[Square.GetEdge('Edge<6>'),Square.GetEdge('Edge<12>')],Rt,False)
 
Last edited:

albie0803

Alibre Super User
How can the above code be modified so that it works in a created sub assembly?

Building a folding table out of SHS. Created the frame for the top using script.
Create a new sub assembly for the leg frame. If I run the script in the parent window it just creates a new part. If I open the new sub assembly in a separate window and then try the script i get:

Exception: Unable to add new part to assembly. Make sure the assembly has been opened for editing. Operation is invalid as the parent Occurrence is not active
 

NateLiquidGravity

Alibre Super User
Yes I have but building frames is a rare occurrence for me, so I couldn't justify buying it to the boss. You have done an amazing job with it.
The free trial allows creation of up to 5 frame members each time you run it.

But back to your topic. From my memory: adding parts to a sub assembly requires you to do something like this:
Python:
Assem = CurrentAssembly()
SubAssem = Assem.GetSubAssembly('Name here<instance number here>')
Prt = SubAssem.AddPart('New Part')
I don't think you can get AlibreScript to recognize the currently active editing window from the script because running the script switches windows to start and also each time it outputs to the console. You could add another selection to the dialog box for the user to pick a subassembly.
 
Top