PickObject in class/function

Hey,

i have one line of code (Selection of Face) that works well as its own UI button.

Watch the following video: https://youtu.be/SK5LuRr4BTw

Code:

import clr

import sys

sys.path.append(‘C:\Program Files (x86)\IronPython 2.7\Lib’)

import System

from System import Array

from System.Collections.Generic import *

clr.AddReference(‘ProtoGeometry’)

from Autodesk.DesignScript.Geometry import *

clr.AddReference(“RevitNodes”)

import Revit

clr.ImportExtensions(Revit.Elements)

clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference(“RevitServices”)

import RevitServices

from RevitServices.Persistence import DocumentManager

from RevitServices.Transactions import TransactionManager

clr.AddReference(“RevitAPI”)

clr.AddReference(“RevitAPIUI”)

import Autodesk

from Autodesk.Revit.DB import *

from Autodesk.Revit.UI import *

doc = DocumentManager.Instance.CurrentDBDocument

uiapp = DocumentManager.Instance.CurrentUIApplication

app = uiapp.Application

uidoc = uiapp.ActiveUIDocument

a = uidoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Face)

print(a)

Now i want to be able to do the same with my own UI and when I select a button that i am then able to select a face with this line of code.
I have been trying very hard, dived into classes and functions but i just can not make it properly work. Right now the problem is that when i click the button Revit is frozen and greyed out. I cannot select anything. But when i close my window i can select a face.

Watch the following video:

Code:

# dependencies

import clr

clr.AddReference('System.Windows.Forms')

clr.AddReference('IronPython.Wpf')

#Import the Revit API

import clr

import sys

sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')

import System

from System import Array

from System.Collections.Generic import *

clr.AddReference('ProtoGeometry')

from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")

import Revit

clr.ImportExtensions(Revit.Elements)

clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitServices")

import RevitServices

from RevitServices.Persistence import DocumentManager 

from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")

clr.AddReference("RevitAPIUI")

import Autodesk 

from Autodesk.Revit.DB import *

from Autodesk.Revit.UI import *

from pyrevit import revit, DB, UI

# find the path of ui.xaml

from pyrevit import script

from pyrevit import forms

xamlfile = script.get_bundle_file('ui.xaml')

# import WPF creator and base Window

import wpf

from System import Windows

class PrintSheetsWindow(forms.WPFWindow):

    def __init__(self):

        wpf.LoadComponent(self, xamlfile)

                

    def face(self, sender, args):

        #this does not work

        doc = DocumentManager.Instance.CurrentDBDocument

        uiapp = DocumentManager.Instance.CurrentUIApplication 

        app = uiapp.Application 

        uidoc = uiapp.ActiveUIDocument

        a = uidoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Face) 

        return a

        

# let's show the window (modal)

PrintSheetsWindow().ShowDialog()

Thanks for any help

Laurin

Yeah I ran into that problem too.
It’s not a problem with the tool per-say, but it has to do with how dialogs & windows work.

So the problem you have is that you’ve created a ‘modal window’ which is a fancy term for, ‘this thing will always be on top and will block you from interacting with revit untill it is closed’.

That’s why you cannot interact with revit after pushing the button. Your wpf window is keeping you in the dialog.

So you have 3 options ahead of you.

  1. You can either redesign your code so that you close the wpf window temporarily and re-enable it after the pick command has passed. (Perhaps sounds harder than it is, but it requires a bit of work)

  2. You can try and go for a ‘non-modal’ window. Which is more tricky as well as requires some more experience I fear. There’s an example in this thread here

  3. (maybe?) is it possible (and reasonable) to ask users to pick a face before your window even shows? Sometimes a simple change of concept can do a lot of good.

Ah okay, very helpful thank you @GertjanVDB !

Actually for this kind of task solution 3. would be the best and easiest solution.

I would really like to give the user the option to select a face or a curve or …
Do you have an example of the 1. option?

Sure I can.
But it’s in a pseudo codish kind of way so you’ll have to use your thinker to fill in the blanks.

I’ve pasted it on pastebin here:
pyrevit-wpf-reopeningdialog - Pastebin.com
Or read it down below. Hope this helps you

def main():

    do_ui_loop = True

    picked_ref = None

    while do_ui_loop:

        ui = MyWindow(picked_ref)

        ui_result = ui.ShowDialog()

        if ui_result == True:

            # * this part is reached if the dialog has been 'OK-ed'

            if ui.mode == 'requires_pick':

                picked_ref = get_face()

            elif ui.mode == 'some other thing you require?':

                pass

            elif ui.mode == 'yet another thing you need to close the ui for?':

                pass

            else:

                # * do whatever your code needs to do after the user has pressed OK here

                do_ui_loop = False  # VERY IMPORTANT, or you'll be stuck in a loop

                do_stuff()

                

        else:

            # * this part will be reached if the user pressed the 'x' button to close the window

            do_ui_loop = False

def get_face():

    # * this is now your 'face' function

class MyWindow(forms.WPF):

    def __init__(self, picked_ref = None):

        self.picked_ref = picked_ref

        self.mode = ''  # * We'll use this as a sort of state of the dialog window

        wpf.LoadComponent(self, xamlfile)

        if picked_ref:

            # * if a reference has been provided

    def face_click(self, sender, args):

        # * now we set the 'mode' variable to 'requires_pick' but you can use anything you like

        # * we'll use this as way to check if the user has made a specific choice int he UI

        # * in this case, that choice is: 'I want to pick a face'

        self.mode = 'requires_pick'

        # * By setting the dialogresult to True, the window will close.

        # * This sort of tells windows that an 'OK' button was clicked

        # * 

        self.DialogResult = True