Rename Selected Views

Let's practice selecting our elements and changing properties once more. Let's create a tool to rename our Views with Find/Replace, Suffix/Preffix logic.

Rename Selected Views

Let's practice selecting our elements and changing properties once more. Let's create a tool to rename our Views with Find/Replace, Suffix/Preffix logic.

Summary

Brainstorm The Tool Idea

Let's create a tool to rename selected views with Prefix, Suffix, Find, Replace logic.

We will have to do the following steps:

  • Get Views

  • Get User Input

  • Prepare New Unique View names

  • Rename Views

Let's Begin.

Get Views

We will combine 2 ways of getting our views.

FIrst of all we will check if user has any views manually selected in the Project Browser, because uidoc.Selection.GetElementIds() will return them as well.

And if user hasn't selected any views in Project Browser, then we will prompt a menu asking them to select views from the list. And we will use pyrevit.forms.select_views for that.

There is a prewritten function which will show a menu to select views with a single line of code. We can see many code examples in pyRevit Dev Docs: Effective Inputs.

👇Here is an example.

from pyrevit import forms

selected_views = forms.select_views()
print(selected_views)

Lastly, if user still hasn't selected any views after the form, then it's a good idea to notify user about it and stop execution.

Since we already started using pyrevit.forms, we can also use alert function that will show a dialog box with a message, and it has an option to exitscript.

from pyrevit import forms

if not views:
    forms.alert('Error', exitscript=True)

👇 Here is the code Snippet for selecting views in our tool

#⬇️ Imports
from pyrevit import forms

# 1️⃣ GET VIEWS
selected_elements = get_selected_elements()
selected_views    = [el for el in selected_elements if issubclass(type(el), View)]

if not selected_views:
    selected_views = forms.select_views()

    if not selected_views:
        forms.alert('There were no Views selected. \n'
                    'Please Try Again.', exitscript=True)

💡We will cover all pyrevit.forms in a seperate module in the future as well.

Get User Input (temp for Dev phase)

Next, we want to get user input.

But since we are still in development phase, it's good to keep it simple until everything works. So I will just hardcode these values by creating 4 variables like below.

# 2️⃣ GET USER INPUT - Temp
prefix  = ""
find    = "B"
replace = "A"
suffix  = ""

💡We will create an actual UI form when everything works!

Create New View Names

Now we can start iterating through selected views and prepare new View Names.

It's very simple, we will use python's built-in str method .replace() with the current view.Name and then add prefix and suffix on both ends.


for view in selected_views:
    # 3️⃣ NEW NAME
    current_name = view.Name
    new_name = prefix + view.Name.replace(find, replace) + suffix

Rename Views with Unique Name

Now we can actually begin renaming. We will override .Name property since it can be overridden.

Also as you're aware, View Names in Revit must be unique, so we need to make sure that our new names also unique when we rename them.

We could get a list of all view names and then check our name, but I prefer to attempt to rename them and If Revit returns an error - it means that View Name already exists, and we need to append something to make it unique. So that's why we have Try/Except statements to check it.

Also I create a for loop to try it for 20 times, and keep adding symbol in the end. We could use a while loop, but I hate when I forget to add a break statement, and then my Revit is crashing because of an infinite loop. So I stick with for loops when I can.

👇 And this will be enough to rename your views with hardcoded values.


for view in selected_views:
    # 3️⃣ NEW NAME
    current_name = view.Name
    new_name = prefix + view.Name.replace(find, replace) + suffix


    # 4️⃣ RENAME VIEWS (unique view names)
    with Transaction(doc, __title__) as t:
        t.Start()
        for i in range(20):
            try:
                view.Name = new_name
                print("{} -> {}".format(current_name, new_name))
                break
            except:
                new_name += "*"
        t.Commit()

Transaction

Also you can notice that I use Transaction class.

💡Transaction are used to make any changes in Revit projects. This protects our project from unintentional changes.

💡 It's also great for beginners to know, we can't mess up anything unless we use them, so get comfortable using Revit API!

In a nutshell: We need to
1) Define a Transaction
2) .Start() transaction
3) .Commit() transaction.
and all the changes have to be between Start and Commit statements.

Here are 2 syntax examples of how to use them:

# Syntax A
t = Transaction(doc, 'Change Name')
t.Start()  #🔓
# 👉 Changes Here...
t.Commit() #🔒

# Syntax B
with Transaction(doc, 'Change Name') as t:
    t.Start()  #🔓
    # 👉 Changes Here...
    t.Commit() #🔒
Get User Input with rpw.FlexForm

Now all the main functionality works!
So we can explore how to improve getting find, replace, prefix and suffix variables.

Creating custom UI forms is not an easy task, but luckily for us, there are plenty of pre-written forms in pyRevit and rpw modules.

rpw is a module written by Gui Tallarico and it's available in pyRevit by default! He is also a creator of RevitAPIdocs.com website (Yes, this website is not from Autodesk…).

There are different modules available, but I want to focus your attention on FlexForm.
It allows you to quickly create simple forms with selected elements.

In our case we will need Label, TextBox, Separator and Button components, and it will be a very useful form for our tool.

Then we can get user inputs by using form.values, it will return a dictionary that contains user input.

# 2️⃣ GET USER INPUT - FlexForm

# https://revitpythonwrapper.readthedocs.io/en/latest/ui/forms.html#flexform
from rpw.ui.forms import (FlexForm, Label, TextBox, Separator, Button)
components = [Label('Prefix:'),  TextBox('prefix'),
              Label('Find:'),    TextBox('find'),
              Label('Replace:'), TextBox('replace'),
              Label('Suffix:'),  TextBox('suffix'),
              Separator(),       Button('Rename Views')]

form = FlexForm('Title', components)
form.show()

user_inputs = form.values
prefix  = user_inputs['prefix']
find    = user_inputs['find']
replace = user_inputs['replace']
suffix  = user_inputs['suffix']

🎦 Check the video to understand it better.

Final Code

So now you have all the parts of the script!

Let's put it all together in a single code!

# -*- coding: utf-8 -*-
__title__ = "03.05 - Rename Views"
__doc__ = """Date    = 29.12.2022
_____________________________________________________________________
Description:
Code from lesson 03.05 - Rename Views
Tutorial on using selection and modifying properties.
_____________________________________________________________________
Author: Erik Frits"""

# ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗
# ║║║║╠═╝║ ║╠╦╝ ║ ╚═╗
# ╩╩ ╩╩  ╚═╝╩╚═ ╩ ╚═╝ IMPORTS
#==================================================
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection import ObjectType, PickBoxStyle, Selection

#custom
from Snippets._selection import get_selected_elements

#pyrevit
from pyrevit import forms

# .NET Imports
import clr
clr.AddReference("System")
from System.Collections.Generic import List

# ╦  ╦╔═╗╦═╗╦╔═╗╔╗ ╦  ╔═╗╔═╗
# ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║  ║╣ ╚═╗
#  ╚╝ ╩ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝╚═╝ VARIABLES
#==================================================
uidoc = __revit__.ActiveUIDocument
doc   = __revit__.ActiveUIDocument.Document

selection = uidoc.Selection # type: Selection

# ╔╦╗╔═╗╦╔╗╔
# ║║║╠═╣║║║║
# ╩ ╩╩ ╩╩╝╚╝
#==================================================

# 1️⃣ GET VIEWS
selected_elements = get_selected_elements()
selected_views    = [el for el in selected_elements if issubclass(type(el), View)]

if not selected_views:
    selected_views = forms.select_views()

    if not selected_views:
        forms.alert('There were no Views selected. \n'
                    'Please Try Again.', exitscript=True)

# 2️⃣ GET USER INPUT
# prefix  = ""
# find    = "B"
# replace = "A"
# suffix  = ""


# https://revitpythonwrapper.readthedocs.io/en/latest/ui/forms.html#flexform
from rpw.ui.forms import (FlexForm, Label, TextBox, Separator, Button)
components = [Label('Prefix:'),  TextBox('prefix'),
              Label('Find:'),    TextBox('find'),
              Label('Replace:'), TextBox('replace'),
              Label('Suffix:'),  TextBox('suffix'),
              Separator(),       Button('Rename Views')]

form = FlexForm('Title', components)
form.show()

user_inputs = form.values
prefix  = user_inputs['prefix']
find    = user_inputs['find']
replace = user_inputs['replace']
suffix  = user_inputs['suffix']



for view in selected_views:
    # 3️⃣ NEW NAME
    current_name = view.Name
    new_name = prefix + view.Name.replace(find, replace) + suffix


    # 4️⃣ RENAME VIEWS (unique view names)
    with Transaction(doc, __title__) as t:
        t.Start()
        for i in range(20):
            try:
                view.Name = new_name
                print("{} -> {}".format(current_name, new_name))
                break
            except:
                new_name += "*"
        t.Commit()
Bonus Snippet for improved selection

👀 Here is the improved get_selected_elements function that I mentioned during the video. Check it out if you are curious enough!

def get_selected_elements_(uidoc=uidoc, filter_types=None, filter_cats=None):
    #type(UIDocument, list, list) -> list
    """Function to get selected elements in Revit UI.
    :param uidoc:        We need to provide uidoc if you want to jump between projects!
    :param filter_types: Option to filter elements by Type
    :param filter_cats:  Option to filter elements by BuiltInCategory
    :return: list of selected elements (Filtered optionally)

    e.g.
    walls_floors = get_selected_elements_(filter_types=[Wall, Floor])
    windows_doors = get_selected_elements_(filter_cats=[BuiltInCategory.OST_Windows, BuiltInCategory.OST_Doors])"""

    selected_el_ids = uidoc.Selection.GetElementIds()
    selected_elems = [doc.GetElement(e_id) for e_id in selected_el_ids]

    if not filter_types and not filter_cats:
        return selected_elems

    elif filter_types:
        return [el for el in selected_elems if type(el) in filter_types]

    elif filter_cats:
        return [el for el in selected_elems if el.Category.BuiltInCategory in filter_cats]

HomeWork

Try to create similar tool for Sheets.

You will need to:

1️⃣ Get ViewSheets
2️⃣ Get User Input
3️⃣ Change ViewSheet.SheetNumber / ViewSheet.Name
4️⃣ Close and Show ProjectBrowser to see updated SheetNumbers

Help resources:

👉 pyrevit.forms.select_sheets
👉 ViewSheet.SheetNumber
👉 ViewSheet.Name
👇 Snippet To Close and Show Project Browser

from Autodesk.Revit.UI import DockablePanes, DockablePane

project_bwoser_id = DockablePanes.BuiltInDockablePanes.ProjectBrowser
project_browser = DockablePane(project_browser-id)

# Change ViewSheet.SheetNumber here

project_browser.Show()

⌨️ Happy Coding!

Questions:

How to create Custom Forms?

How to create Custom Forms?

Discuss the lesson:

P.S. This discord window is controlled with a bot and sometimes you might experience connection issues. If that happened, open Discord server with an app and look for this lesson's channel. Alternatively you could give it a try later in the browser.

Sorry for that, I am still figuring it out.
- Erik

P.S. This discord window is controlled with a bot and sometimes you might experience connection issues. If that happened, open Discord server with an app and look for this lesson's channel. Alternatively you could give it a try later in the browser.

Sorry for that, I am still figuring it out.
- Erik

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API