Hello,
does anyone use it for dynamo ?
is there also implementation tutorials regarding that ?
KR
Andreas
Hello,
does anyone use it for dynamo ?
is there also implementation tutorials regarding that ?
KR
Andreas
Normally, if developer want to integrate with user interface, they will choose zero touch node
.
I recommend if you want to save your time for that, let go with C# + WPF
, Python not is everything for any case .
For me i want all my scripts not to have dependency on anything (not even python libraries that are not OOTB)
(Im frothing for numpy etc…)
I built on the below to create forms where rquired for my user inputs.
i think it is even not supported
import sys
import clr
import numpy
from numpy import *
import pandas
from pandas import *
#import PyQt6
#from PyQt6 import *
OUT = sys.version, pandas.__version__, numpy.__version__
So what is than recomandable ? PyRevit ? or the hard way C#
KR
Andreas
Yeah its not supported yet…
Im so excited for when it is.
The link i gave is for winforms which is supported and has a python script that has a few examples already built into it.
It takes a bit of time to set up the first one and understand it but after that its pretty easy to modify for each scenario.
@pyXam ,
here also some errors:
#thanks to Ben Robinson
import clr
import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)
#############-------------\-------------##############
### UI additional references ###
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Windows.Forms import Application, Form, FormWindowState, Screen, Label, PictureBox, PictureBoxSizeMode, AnchorStyles, BorderStyle, ComboBox, ComboBoxStyle, FormBorderStyle, CheckBox, TextBox, TextBoxBase
from System.Windows.Forms import Button, LinkLabel, Panel, Button
from System.Drawing import Icon, Color, Font, Point, Size
#system location C:\Windows\Microsoft.NET\Framework64\v4.0.30319
import System.IO
#############-------------\-------------#############
### Define some variables ###
these variables are static through the 2 windows
bitmapImage = System.Drawing.Bitmap("C:\Users\andre\Downloads\\" + "icon.png") #titlebar logo as bmp
titleIcon = Icon.FromHandle(bitmapImage.GetHicon()) #titlebar logo as icon
titleText = "Dimensioning" #text that appears in the GUI titlebar
btnHeight = 40 #declared here as used for btn locations
btnWidth = 120
spacing = 20 #spacing size for GUI elements to form a consistent border
fontMessage = Font("Helvetica ", 9)
fontCK = Font("Helvetica ", 8) #set Checkbox Font
winSize = Size(1000,600) #consistant window size
#############-------------\-------------#############
### Global defs ###
def button(txt, loc, clc):
btn = Button()
#btnCancel.Parent = self
btn.Text = txt
btn.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right)
btn.Location = loc
btn.Click += clc
btn.Height = btnHeight
btn.Width = btnWidth
btn.BackColor = Color.FromArgb(220, 220, 220)
return btn
def logo(uiW, uiH):
logo = PictureBox()
bitmapImage = System.Drawing.Bitmap("C:\Me\Dynamo\WPF in Dynamo\\" + "dyna-sco-logo-text.png")
logo.Image = bitmapImage
ratio = float(logo.Height)/ float(logo.Width) #needs to be a float as int will round to the nearest whole number
logo.Size = Size(220, 130*ratio) #fixed for consistancy
logo.Location = Point(spacing, (uiH - logo.Height)-spacing)
logo.SizeMode = PictureBoxSizeMode.Zoom # zooms the image to fit the extent
logo.Anchor = (AnchorStyles.Bottom | AnchorStyles.Left) #anchor styles lock elements to a given corner of the GUI if you allow users change size
return logo
##########################-------------\-------------##########################
### Create a Class to define the first window ###
# create a instance of the form class called dimsionInputs.
#In Winforms, any window or a dialog is a Form.#
class dimsionInputs(Form):
def __init__(self): #the __init__ method inside a class is its constructor
self.Text = titleText
self.Icon = titleIcon
self.BackColor = Color.FromArgb(255, 255, 255)
self.WindowState = FormWindowState.Normal # set maximised minimised or normal size GUI
self.CenterToScreen() #centres GUI to the middle of your screen
self.BringToFront() #brings the GUI to the front of all open windows
self.Topmost = True #true to display the GUI infront of any other active forms
self.Size = winSize #small enough to fit on most screens
uiWidth = self.DisplayRectangle.Width #get the size of the form to use to scale form elements
uiHeight = self.DisplayRectangle.Height
stHeight = uiHeight / 4.5 #the height at which the check & text boxes will start
htSpacing = 50 #a standard spacing vertical gap betwen check & text boxes
self.FormBorderStyle = FormBorderStyle.FixedDialog # fixed dialog stops the user from adjusting the form size. Recomended disabling this when testing to see if elements are in the wrong place.#
### Set Default Values ###
# self.dropDownOutput = 'pick one'
self.txtBoxOffOutput = '500' #offset of dimension from wall
self.txtBoxCoordOutput = 'Internal' #name of coordinate system to be used
self.ckBoxESOutput = False #External Side?
self.ckBoxLWOutput = False #Linked Walls?
self.ckBoxAWOutput = False #All Walls?
self.ckBoxMDOutput = False #Multiple dims per wall?
self.messText = 'test'
self.runNextOutput = False #how we decide if we want the next window to fire#
self.Controls.Add(logo(uiWidth, uiHeight)) #add logo
#############-------------\-------------#############
### Create Main Window Text ###
userMessage = Label() #label displays texts
font = fontMessage
userMessage.Text = 'Automatic Dimensions for Linked or Project Walls'
userMessage.Font = font
userMessage.Location = Point(spacing, spacing) #all location require a point object from system.Drawing to set the location.
userMessage.Size = Size(uiWidth-(spacing*2),(uiHeight/4)-60) #size the control with the width of the GUI to ensure it scales with different screen
self.Controls.Add(userMessage) #this adds control element to the GUI
#############-------------\-------------#############
#combox drop down
# cBox = ComboBox() #dropdown control form
# cBox.Location = Point(spacing,uiHeight/3)
# cBox.Width = uiWidth -(spacing*2)
# cBox.Items.AddRange(tuple[(1,2,3,])) # Adds an array of items to the list of items for a ComboBox.
# cBox.DropDownStyle = ComboBoxStyle.DropDownList #setting to dropdown list prevents users from being able to add aditional text values
# cBox.SelectedIndexChanged += self.dropDownOutput #.Click+= registers the press of the button to register the event handler and determine what action takes place when button clicked
# self.Controls.Add(cBox)
#############-------------\-------------#############
### CHECKBOXES ##
#checkbox External Side
ckBoxES = CheckBox()
ckBoxES.Name="External Side"
ckBoxES.Text="External Side? (or internal side)"
ckBoxES.Location = Point(spacing,stHeight)
ckBoxES.Width = uiWidth -(spacing*2)
ckBoxES.Font = fontCK
ckBoxES.Height = 40
ckBoxES.CheckStateChanged += self.ckBoxESChecked
#checkbox Linked Walls
ckBoxLW = CheckBox()
ckBoxLW.Name="Linked Walls"
ckBoxLW.Text="Linked Walls?"
ckBoxLW.Location = Point(spacing,stHeight+htSpacing)
ckBoxLW.Width = uiWidth -(spacing*2)
ckBoxLW.Font = fontCK
ckBoxLW.Height = 40
ckBoxLW.CheckStateChanged += self.ckBoxLWChecked
#checkbox All Walls
ckBoxAW = CheckBox()
ckBoxAW.Name="All Walls"
ckBoxAW.Text="All Walls?"
ckBoxAW.Location = Point(spacing,(stHeight+htSpacing*2))
ckBoxAW.Width = uiWidth -(spacing*2)
ckBoxAW.Height = 40
ckBoxAW.Font = fontCK
ckBoxAW.CheckStateChanged += self.ckBoxAWChecked
#checkbox MultiDims
ckBoxMD = CheckBox()
ckBoxMD.Name="Multi-Dims"
ckBoxMD.Text="Multi-Dims for each wall (for brick checking)"
ckBoxMD.Location = Point(spacing,(stHeight+htSpacing*3))
ckBoxMD.Width = uiWidth -(spacing*2)
ckBoxMD.Height = 40
ckBoxMD.Font = fontCK
ckBoxMD.CheckStateChanged += self.ckBoxMDChecked
#add to Window
self.Controls.Add(ckBoxES)
self.Controls.Add(ckBoxLW)
self.Controls.Add(ckBoxAW)
self.Controls.Add(ckBoxMD)
#############-------------\-------------#############
### TEXTBOXES ##
#TextBox Coordinate System
textBoxCoord = TextBox()
textBoxCoord.Width = 300
textBoxCoord.Text="Internal"
textBoxCoord.Font = fontCK
textBoxCoord.Location = Point(spacing + 400 ,(stHeight+htSpacing*4))
textBoxCoord.TextChanged += self.txtBoxCoordChanged
#TextBox Coordinate System - Label
textBoxCoordLabel = Label() #label displays texts
textBoxCoordLabel.Text = "Coordinate System Name"
textBoxCoordLabel.Width = 400
textBoxCoordLabel.Font = fontCK
textBoxCoordLabel.Location = Point(spacing,(stHeight+htSpacing*4))
textBoxCoordLabel.Height = 50
#add to Window
self.Controls.Add(textBoxCoordLabel)
self.Controls.Add(textBoxCoord)
#TextBox Offset
textBoxOffset = TextBox()
textBoxOffset.Location = Point(spacing + 400,(stHeight+htSpacing*5))
textBoxOffset.Width = 300
textBoxOffset.Text= "500"
textBoxOffset.Name="Offset Distance"
textBoxOffset.Font = fontCK
textBoxOffset.TextChanged += self.txtBoxOffChanged
#TextBox Offset - Label
textBoxOffsetLabel = Label() #label displays texts
textBoxOffsetLabel.Text = "Offset Distance"
textBoxOffsetLabel.Width = 200
textBoxOffsetLabel.Font = fontCK
textBoxOffsetLabel.Height = 40
textBoxOffsetLabel.Location = Point(spacing,(stHeight+htSpacing*5))
#this is how you would do a margin
#textBoxOffsetLabel.Margin = Padding(712,418,0,0)
#add to Window
self.Controls.Add(textBoxOffsetLabel)
self.Controls.Add(textBoxOffset)
#############-------------\-------------#############
### Buttons ##
#Create Ok Button
btnOkClick = self.okButtonPressed #register click by user
btnOkLoc = Point(uiWidth - ((btnWidth * 2) + spacing + 30), uiHeight - (btnHeight + spacing))
btnOk = button('OK', btnOkLoc, btnOkClick)
#Create Cancel Button
btnCnclClick = self.CnlButtonPressed #register click by user
btnCnclLoc = Point(uiWidth - (btnHeight + spacing + 90), uiHeight - (btnHeight + spacing ))
btnCancel = button('Cancel', btnCnclLoc, btnCnclClick)
#add to Window
self.Controls.Add(btnOk)
self.Controls.Add(btnCancel)
#############-------------\-------------#############
### Return Info From User ##
#these defs are the mechanism by which we assess the info from the user
#self is the instance of the GUI form. Sender is the control/widget. args is the argument/event provided from the control
###dropDown ####
# def dropDownOutput(self, sender, args):
# self.dropDownOutput = sender.SelectedItem #output the selected item.
### checkBoxes ###
def ckBoxESChecked(self, sender, args):
if sender.Checked:
self.ckBoxESOutput = True
#otherwise indeterminate states give erroneous results
else:
self.ckBoxESOutput = False
def ckBoxLWChecked(self, sender, args):
if sender.Checked:
self.ckBoxLWOutput = True
else:
self.ckBoxLWOutput = False
def ckBoxAWChecked(self, sender, args):
if sender.Checked:
self.ckBoxAWOutput = True
else:
self.ckBoxAWOutput = False
def ckBoxMDChecked(self, sender, args):
if sender.Checked:
self.ckBoxMDOutput = True
else:
self.ckBoxMDOutput = False
### textBoxes ###
def txtBoxOffChanged(self, sender, args):
self.txtBoxOffOutput = sender.Text
def txtBoxCoordChanged(self, sender, args):
self.txtBoxCoordOutput = sender.Text
### buttons ###
def okButtonPressed(self, sender, args):
numErrorProvider = System.Windows.Forms.ErrorProvider()
try:
int(self.txtBoxOffOutput)
self.Close() #trigger to close the GUI when button is pressed
self.runNextOutput = True #if the ok button is pressed set runNextOutput as True
except ValueError:
numErrorProvider.SetError(sender, 'Offset must be a number')
def CnlButtonPressed(self, sender, args):
self.Close()
self.runNextOutput = False #if the cancel button is pressed set runNextOutput as False
##########################-------------\-------------##########################
### Create a Class to define the second window ####
class followForm(Form):
def __init__(self): #the __init__ method inside a class is its constructor
self.Text = titleText
self.Icon = titleIcon
self.Size = winSize
self.CenterToScreen()
self.FormBorderStyle = FormBorderStyle.FixedDialog
self.runNextOutput = False #how we decide if we want the next window to fire
uiWidth = self.DisplayRectangle.Width #get the size of the form to use to scale form elements
uiHeight = self.DisplayRectangle.Height
self.Controls.Add(logo(uiWidth, uiHeight)) #add logo
#############-------------\-------------#############
### Buttons ##
#Create Ok Button
btnOkClick = self.okButtonPressed #register click by user
btnOkLoc = Point(uiWidth - ((btnWidth * 2) + spacing + 30), uiHeight - (btnHeight + spacing))
btnOk = button('OK', btnOkLoc, btnOkClick)
#Create Cancel Button
btnCnclClick = self.CnlButtonPressed #register click by user
btnCnclLoc = Point(uiWidth - (btnHeight + spacing + 90), uiHeight - (btnHeight + spacing ))
btnCancel = button('Cancel', btnCnclLoc, btnCnclClick)
#add to Window
self.Controls.Add(btnOk)
self.Controls.Add(btnCancel)
#############-------------\-------------#############
### Create Second Window Text ###
userMessageScnd = Label() #label displays texts
font = fontMessage
dimsionInputs()
#message(ckBoxLWChecked, ckBoxAWChecked)
userMessageScnd.Text = 'runNextOutput = ' + str(dimForm.runNextOutput) + '''\n\nThis is a contradiction! \n\nThis window only fired because runNextOutput was changed to True by the previous window! \n\nSo, sadly, it seems we can\'t link a series of windows driven by dynamic information without daisy-chaining python nodes together'''
#userMessageScnd.Text = dimsionInputs().messText
userMessageScnd.Font = font
userMessageScnd.Location = Point(spacing, spacing) #all location require a point object from system.Drawing to set the location.
userMessageScnd.Size = Size(uiWidth-(spacing*2),(uiHeight)) #size the control with the width of the GUI to ensure it scales with different screen
self.Controls.Add(userMessageScnd) #this adds control element to the GUI
#############-------------\-------------#############
### Return Info From User ##
### buttons ###
def okButtonPressed(self, sender, args):
self.Close() #trigger to close the GUI when button is pressed
self.runNextOutput = True #if the ok button is pressed set runNextOutput as True#
def CnlButtonPressed(self, sender, args):
self.Close()
##########################-------------\-------------##########################
### And Run ##
dimForm = dimsionInputs()
followForm = followForm()
Application.Run(dimForm)
if dimForm.runNextOutput:
Application.Run(followForm)
OUT = dimForm.ckBoxESOutput, dimForm.ckBoxLWOutput, dimForm.ckBoxAWOutput, dimForm.ckBoxMDOutput, dimForm.txtBoxOffOutput, dimForm.txtBoxCoordOutput,
i use Revit2024 (IronPython2 Package is loaded)
KR
Andreas
What specifically is the error you are getting?
i set this up a while ago for me so i can’t remember specifically what i needed to change to make it work but i’m sure that the .PNG shows in 2 locations was one of them
I am running this in R2023 with Cpython3 Engine.
Hello, Mr. Draxl take a look at Mr. Poupin’s posts, this should guide you in the right direction
Cordially
christian.stan
i tried both PyQt5 and 6 i was not able to install stuff. I had problems with Madlib and ifcopenshell too…
i did everything with pip
numpy and pandas works well.
KR
Andreas
sorry not yet competent enough on this UI aspect
cordially
christian.stan
Hi,
using PyQt is possible with Dynamo however, as we are in a .Net environment, I rather recommend Winform or Wpf, just to take advantage of features like DataBinding and others
example with QtDesigner and Python
Thank you
so that means i have to switch to c# ?
so my idea ist to write and perform the code in dynamo (py) and than in PyRevit(CostumToolbar)
when i use WPF or Winform… what should i use ?
My first step would be “select category” and than “filter by Name contains”
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('System')
from System.Collections.Generic import List
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
collector = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)
all_walls = collector.WhereElementIsNotElementType().ToElements() #dropdown menu for categories
spec_typ = [i for i in all_schedules if i.Name.Contains("STB")] #Textbox
OUT = spec_typ
How is the workflow i “construct” the window ?
KR
Andreas
if the end use is pyRevit you might as well do the python code directly in pyRevit (unless there are dependencies with the Dynamo API)
Winform and Wpf remain possible with IronPython and PythonNet there are several examples on the forum (there is however an additional difficulty with PythonNet)
Then even if you code in Python learning C# is interesting (just to understand the multiple examples that exist on the Revit API)
i apsolutly agree with C#, i try also ZeroTouch… …but it is more complex regarding folder management and deep understanding how your computer is structured and dealing with costumized workflows…
a example with Winform
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('System')
from System.Collections.Generic import List
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms
from System.Drawing import *
from System.Windows.Forms import *
class Form27(Form):
def __init__(self):
collector = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)
self._all_walls = collector.WhereElementIsNotElementType().ToElements()
# out value
self.selectWall = None
self.userText = ""
self.InitializeComponent()
def InitializeComponent(self):
self._buttonOK = System.Windows.Forms.Button()
self._comboBox1 = System.Windows.Forms.ComboBox()
self._label1 = System.Windows.Forms.Label()
self._label2 = System.Windows.Forms.Label()
self._textBox1 = System.Windows.Forms.TextBox()
self.SuspendLayout()
#
# buttonOK
#
self._buttonOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right
self._buttonOK.Location = System.Drawing.Point(241, 230)
self._buttonOK.Name = "buttonOK"
self._buttonOK.Size = System.Drawing.Size(88, 32)
self._buttonOK.TabIndex = 0
self._buttonOK.Text = "OK"
self._buttonOK.UseVisualStyleBackColor = True
self._buttonOK.Click += self.ButtonOKClick
#
# comboBox1
#
self._comboBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
self._comboBox1.FormattingEnabled = True
self._comboBox1.Location = System.Drawing.Point(12, 74)
self._comboBox1.Name = "comboBox1"
self._comboBox1.Size = System.Drawing.Size(317, 21)
self._comboBox1.Items.AddRange(System.Array[System.Object](self._all_walls))
self._comboBox1.DisplayMember = "Name"
self._comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList # force ready only
self._comboBox1.TabIndex = 1
self._comboBox1.SelectedIndexChanged += self.ComboBox1SelectedIndexChanged
#
# label1
#
self._label1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
self._label1.Location = System.Drawing.Point(13, 45)
self._label1.Name = "label1"
self._label1.Size = System.Drawing.Size(316, 23)
self._label1.TabIndex = 2
self._label1.Text = "label1"
#
# label2
#
self._label2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
self._label2.Location = System.Drawing.Point(13, 111)
self._label2.Name = "label2"
self._label2.Size = System.Drawing.Size(316, 23)
self._label2.TabIndex = 3
self._label2.Text = "label2"
#
# textBox1
#
self._textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
self._textBox1.Location = System.Drawing.Point(12, 138)
self._textBox1.Name = "textBox1"
self._textBox1.Size = System.Drawing.Size(317, 20)
self._textBox1.TabIndex = 4
#
# Form27
#
self.ClientSize = System.Drawing.Size(341, 274)
self.MinimumSize = self.ClientSize + System.Drawing.Size(20, 20)
self.Controls.Add(self._textBox1)
self.Controls.Add(self._label2)
self.Controls.Add(self._label1)
self.Controls.Add(self._comboBox1)
self.Controls.Add(self._buttonOK)
self.Name = "Form27"
self.Text = "Form27"
self.ResumeLayout(False)
self.PerformLayout()
def ComboBox1SelectedIndexChanged(self, sender, e):
self.selectWall = sender.SelectedItem
def ButtonOKClick(self, sender, e):
self.userText = self._textBox1.Text
self.Close()
form = Form27()
form.ShowDialog()
OUT = form.selectWall, form.userText