Select to view content in your preferred language

Searching a shape by inputting attribute values in a GUI window using Python.

249
4
08-30-2024 12:23 AM
desert
by
Occasional Contributor

I received assistance here on how to find shapes using attribute values in a Python script.
Since it was inconvenient to directly input attribute values into the code each time, I tried entering them through the Python console, but it was impossible.
Then, I found a way to implement a GUI using Jython and tried it.

It's currently working well, including searches for Korean(2Bytes char) attributes. While it may not be the most elegant solution, I hope it helps others.
("Functional limitation - Search does not work when the attribute value is a number.")

As a program designed to handle large datasets, CityEngine must include a core functionality to search for shapes based on their attributes.(Does this feature really exist, or am I missing something?)

 

 

 

 

 

 

# Last modified: 2024-08-29 19:00:00 KST
# Version: 1.4
# Requirement: Fix the issue where the input GUI window was not displaying correctly.

'''
@author: desert
'''
from scripting import *
from javax.swing import JFrame, JLabel, JTextField, JButton, JPanel
from java.awt import GridLayout, BorderLayout
from java.awt.event import ActionListener

# Get a CityEngine instance
ce = CE()

# selectByAttribute function: Select objects based on the attribute name and value
def selectByAttribute(attr, value):
    objects = ce.getObjectsFrom(ce.scene)
    selection = []
    for o in objects:
        attrvalue = ce.getAttribute(o, attr)
        if attrvalue == value:
            selection.append(o)
    
    ce.setSelection(selection)

# Class defining the GUI components
class InputFrame(JFrame, ActionListener):
    def __init__(self):
        self.createAndShowGUI()

    def createAndShowGUI(self):
        self.setTitle("Attribute Input")
        self.setSize(400, 150)
        self.setLayout(BorderLayout())

        # Add attribute name and value fields to the central panel
        panel = JPanel()
        panel.setLayout(GridLayout(2, 2, 10, 10))
        
        # Attribute name input field
        panel.add(JLabel("Attribute Name:"))
        self.attrField = JTextField(15)
        panel.add(self.attrField)
        # Attribute value input field
        panel.add(JLabel("Attribute Value:"))
        self.valueField = JTextField(15)
        panel.add(self.valueField)
        
        # Add the panel to the center
        self.add(panel, BorderLayout.CENTER)

        # Add Execute and Close buttons to the bottom
        buttonPanel = JPanel()
        buttonPanel.setLayout(GridLayout(1, 2, 10, 10))

        # Execute button
        self.button = JButton("Search", actionPerformed=self.actionPerformed)
        buttonPanel.add(self.button)
        
        # Close button
        self.closeButton = JButton("Cancel", actionPerformed=self.closeWindow)
        buttonPanel.add(self.closeButton)

        # Add the button panel to the bottom
        self.add(buttonPanel, BorderLayout.SOUTH)

        # Set the default close operation and make the GUI visible
        self.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
        self.setVisible(True)
    
    # Function triggered when the button is clicked
    def actionPerformed(self, event):
        attr = self.attrField.getText()
        value = self.valueField.getText()
        selectByAttribute(attr, value)
        print("Selected objects with attribute '{}' and value '{}'.".format(attr, value))
        self.dispose()
    
    # Function to close the window when the close button is clicked
    def closeWindow(self, event):
        self.dispose()

if __name__ == '__main__':
    # Launch the GUI window
    InputFrame()

 

 

 

 

4 Replies
desert
by
Occasional Contributor

I've modified the code to allow searching for numerical attribute values as well.

Please note that I'm a beginner in Python, so there might be some shortcomings.

 

# Last modified: 2024-08-31 16:00:00 KST
# Version: 1.7
# Requirement: Fix the issue float type attr value

'''
@author: desert
'''
from scripting import *
from javax.swing import JFrame, JLabel, JTextField, JButton, JPanel
from java.awt import GridLayout, BorderLayout
from java.awt.event import ActionListener

# Get a CityEngine instance
ce = CE()

# selectByAttribute function: Select objects based on the attribute name and value
def selectByAttribute(attr, value):
    objects = ce.getObjectsFrom(ce.scene)
    selection = []
    for o in objects:
        attrvalue = ce.getAttribute(o, attr)
        print(type(attrvalue))
        if isinstance(attrvalue,float) and attrvalue == float(value):
            selection.append(o)
        elif isinstance(attrvalue,str) and attrvalue == value: 
            selection.append(o)

    
    ce.setSelection(selection)

# Class defining the GUI components
class InputFrame(JFrame, ActionListener):
    def __init__(self):
        self.createAndShowGUI()

    def createAndShowGUI(self):
        self.setTitle("Attribute Input")
        self.setSize(400, 150)
        self.setLayout(BorderLayout())

        # Add attribute name and value fields to the central panel
        panel = JPanel()
        panel.setLayout(GridLayout(2, 2, 10, 10))
        
        # Attribute name input field
        panel.add(JLabel("Attribute Name:"))
        self.attrField = JTextField(15)
        panel.add(self.attrField)
        # Attribute value input field
        panel.add(JLabel("Attribute Value:"))
        self.valueField = JTextField(15)
        panel.add(self.valueField)
        
        # Add the panel to the center
        self.add(panel, BorderLayout.CENTER)

        # Add Execute and Close buttons to the bottom
        buttonPanel = JPanel()
        buttonPanel.setLayout(GridLayout(1, 2, 10, 10))

        # Execute button
        self.button = JButton("Search", actionPerformed=self.actionPerformed)
        buttonPanel.add(self.button)
        
        # Close button
        self.closeButton = JButton("Cancel", actionPerformed=self.closeWindow)
        buttonPanel.add(self.closeButton)

        # Add the button panel to the bottom
        self.add(buttonPanel, BorderLayout.SOUTH)

        # Set the default close operation and make the GUI visible
        self.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
        self.setVisible(True)
    
    # Function triggered when the button is clicked
    def actionPerformed(self, event):
        attr = self.attrField.getText()
        value = self.valueField.getText()
        selectByAttribute(attr, value)
        print("Selected objects with attribute '{}' and value '{}'.".format(attr, value))
        self.dispose()
    
    # Function to close the window when the close button is clicked
    def closeWindow(self, event):
        self.dispose()

if __name__ == '__main__':
    # Launch the GUI window
    InputFrame()

 

JonasObertuefer
Esri Contributor

Hi @desert,

Thanks for sharing your script with the community.

While its true that currently advanced selections based on attributes can be done using the python scripting interface only, a basic search for attributes is available directly in the Scene Editor:

JonasObertuefer_0-1726041829283.png

For more details about the feature checkout the online help:

CityEngine Help: Scene Editor: Additional layer options

If you are interested in advanced search capabilities through a GUI interface, I encourage you to create a new post in the Ideas forum!

Cheers
Jonas

0 Kudos
desert
by
Occasional Contributor

It seems I did something unnecessary without even thoroughly reading the manual I had checked before. I will carefully read the help section again. Thank you for pointing it out.

0 Kudos
JonasObertuefer
Esri Contributor

I wouldn't say its unnecessary because you can do advanced filtering and selection using python. For instance using your script you can search for specific key/value pairs while the search bar in the Scene Editor will match everything with the entered name.

0 Kudos