Sunday 13 March 2016

Window Forms via Dynamo

Within our practice we are looking at ways of deploying the Dynamo graphs to engineers and technicians that don't have much or any experience with Dynamo. Opening the graphs can become very daunting at times for most people so this could become a reason not to use them.

Last December Dyno by ArcProjects was mentioned in one of the AU classes. The tool would allow you to run Dynamo graphs just by double clicking on a button without opening Dynamo's main window at all. This has the potential of being a very great tool, as it will allow you to run Dynamo graphs as Macros instead.

This workflow however raised a few other questions. If the users are not going to open the Dynamo graphs at all, how are they going to interact with the graph when an user input is required ? It turns out that you can (not easily however) create window forms in IronPython. Who knew, right ?

Code snippet:
 
 import clr  
 import sys  
 clr.AddReference('System.Windows.Forms')  
 clr.AddReference('System.Drawing')  
 from System.Windows.Forms import Application, Button, Form, Label, TextBox  
 from System.Drawing import Point  

 # The input to this node will be stored in the IN0...INX variable(s). 
 dataEnteringNode = IN[0]  

 # Store the user input in this variable
   def saveDataFromForm():  
      UserInput.append(form.textbox.Text)  

 # Windows form structureclass SimpleTextBoxForm(Form):  
   def __init__(self):  
     self.Text = "Simple TextBox Example"  

     self.Width = 300     
     self.Height = 200  

     self.label = Label()  
     self.label.Text = dataEnteringNode  
     self.label.Location = Point(25, 25)  
     self.label.Height = 25     
     self.label.Width = 250  

     self.textbox = TextBox()  
     self.textbox.Text = "The Default Text"     
     self.textbox.Location = Point(25, 75)  
     self.textbox.Width = 150  

     self.button1 = Button()  
     self.button1.Text = 'Press Me'     
     self.button1.Location = Point(25, 125)  
     self.button1.Click += self.update  

     self.button2 = Button()  
     self.button2.Text = 'Reset'     
     self.button2.Location = Point(125, 125)  
     self.button2.Click += self.reset  

     self.AcceptButton = self.button1  
     self.CancelButton = self.button2  

     self.Controls.Add(self.label)  
     self.Controls.Add(self.textbox)  
     self.Controls.Add(self.button1)  
     self.Controls.Add(self.button2)  

   def update(self, sender, event):  
     self.label.Text = self.textbox.Text  
     saveDataFromForm()  

   def reset(self, sender, event):  
     self.label.Text = dataEnteringNode  
     self.textbox.Text = "The Default Text"  

 UserInput = list()  
 form = SimpleTextBoxForm()  
 Application.Run(form)  
   
 #Assign your output to the OUT variable 
OUT = UserInput  

The code above will create a Windows Form with the description inside the form introduced via a string in Revit. The title of the Windows Form can also be formatted in the same way, by using IN[1]. The user introduced a value or text in the text box. This user input will then form the Output.

Windows Form in Dynamo Example
As it stands, the form won't close unless one presses the X button. If the PressMe button is pressed multiple times, then the Output will generate a list. If this is not the desired behavior, then this can be tweaked by making the button close the form when pressed.

The Window Form can open the door for multiple applications in a Dynamo graph, however it is quite tedious to build. What could have been easily done in C# with a few lines of code, in IronPython we are looking at easily 10 times more lines.

Special thanks to Michael Kirschner and the Autodesk Vasari community, as well as Voidspace for offering all the material and inspiration. Further reads here:

Autodesk Vasari community : Python import statements for Dynamo Thread
Voidsapce website : IronPython and Windows Forms

No comments:

Post a Comment