Eto + python + mac. shut down

,

Hello. Recently I noticed about Eto. I started to study this and connecting my python project to this UI.
But in some cases the bug not just break process, but also break Rhino. What I mean is that, in some cases Rhino shut down.
I had to open Console App to check the last error messages. Why this happened? And How can I fix this?

Hello @์ด์‹ ํ›„ is Rhino crashing when youโ€™re editing python in the Script Editor?

not during editing, but running script through Tool > Script > Run

running this code

import sys

sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")
import utils
import Rhino.Input
import Rhino.Input.Custom
import scriptcontext as sc
from apartment.apartment_builder import (
    ApartmentInputStructure,
    UnitInput,
    CoreInput,
    WindowInput,
)

from Eto.Forms import (
    Application,
    Form,
    TextBox,
    Button,
    Label,
    TableLayout,
    TableRow,
    TableCell,
)
import Eto.Forms as ef
from Eto.Drawing import Size, Padding


def get_object():  # DEPRECATED ETO loop์™€ ์ถฉ๋Œ๋ฐœ์ƒ
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("์•„ํŒŒํŠธ ๊ด€๋ จ ๋„๋ฉด ๊ฐ์ฒด๋ฅผ ์„ ํƒํ•˜์„ธ์š”")
    go.EnablePreSelect(True, True)
    go.GetMultiple(1, 0)

    if go.CommandResult() != Rhino.Commands.Result.Success:
        ef.MessageBox.Show("์˜ค๋ธŒ์ ํŠธ ์„ ํƒ์ด ์ทจ์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", ef.MessageBoxButtons.OK)
        return


def get_preselected_objects():
    objs = sc.doc.Objects.GetSelectedObjects(True, False)
    return objs


class ValidationResultForm(Form):
    def __init__(self, objects, results):
        super(ValidationResultForm, self).__init__()
        self.Title = "๊ฒ€์ฆ ๊ฒฐ๊ณผ"
        self.ClientSize = Size(400, 200)
        self.Padding = Padding(10)
        self.objects = objects

        layout = TableLayout(
            rows=[
                TableRow(
                    Label(Text=f"๊ฒ€์ฆ {key}: {'โœ… ํ†ต๊ณผ' if passed else 'โŒ ์‹คํŒจ'}")
                )
                for key, passed in results.items()
            ]
            + [None]
        )
        self.Content = layout


class ValidationForm(Form):
    def __init__(
        self,
    ):
        super(ValidationForm, self).__init__()
        self.objects = None
        self.Title = "์•„ํŒŒํŠธ ๋„๋ฉด ๊ฒ€์ฆ"
        self.ClientSize = Size(400, 300)
        self.Padding = Padding(10)

        # --- ์œ„์ ฏ๋“ค ---
        self.name_input = TextBox()
        self.upload_button = utils.make_button("Upload")

        self.result_labels = {
            "A": utils.make_label("๊ฒ€์ฆ A: ๋Œ€๊ธฐ ์ค‘"),
            "B": utils.make_label("๊ฒ€์ฆ B: ๋Œ€๊ธฐ ์ค‘"),
            "C": utils.make_label("๊ฒ€์ฆ C: ๋Œ€๊ธฐ ์ค‘"),
            "D": utils.make_label("๊ฒ€์ฆ D: ๋Œ€๊ธฐ ์ค‘"),
        }

        self.upload_button.Click += self.on_upload_clicked

        # --- ๋ ˆ์ด์•„์›ƒ ---
        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(utils.make_label("์•„ํŒŒํŠธ ์ด๋ฆ„")),
                    TableCell(self.name_input),
                ),
                TableRow(None, TableCell(self.upload_button)),
                TableRow(TableCell(self.result_labels["A"])),
                TableRow(TableCell(self.result_labels["B"])),
                TableRow(TableCell(self.result_labels["C"])),
                TableRow(TableCell(self.result_labels["D"])),
                None,  # ๋์— ์—ฌ์œ  ๊ณต๊ฐ„
            ]
        )

        self.Content = layout

    def on_upload_clicked(self, sender, e):
        apartment_name = self.name_input.Text
        # ์•„ํŒŒํŠธ๋กœ ๋งŒ๋“ค RhinoObject๋“ค์„ ์„ ํƒํ•˜๋„๋ก ํ•จ.

        objs = sc.doc.Objects.GetSelectedObjects(True, False)

        # ์„ ํƒ๋œ ์˜ค๋ธŒ์ ํŠธ๋“ค
        self.objects = objs

        apartment_input_structure = self._create_apartment_input_structure(
            apartment_name, self.objects
        )

        # ๊ฒ€์ฆ ์‹คํ–‰
        apartment_check_result = apartment_input_structure.validate()

        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(utils.make_label(self.get_result_message(result_dict)))
                )
                for key, result_dict in apartment_check_result.items()
            ]
            + [None]
        )
        self.Content = layout

    def get_result_message(self, result_dict):
        result_message = ""
        result = result_dict.get("result")
        message = result_dict.get("message")
        if result:
            result_message += f"๊ฒ€์ฆ ๊ฒฐ๊ณผ: โœ… ํ†ต๊ณผ\n"
        else:
            result_message += f"๊ฒ€์ฆ ๊ฒฐ๊ณผ: โŒ ์‹คํŒจ :{message}\n"

        return result_message

    def _create_apartment_input_structure(
        self, apartment_name, clicked_items
    ) -> ApartmentInputStructure:

        object_by_layer = {}
        for rhino_object in clicked_items:
            lyr_name = utils.get_layer_name(rhino_object)
            if lyr_name not in object_by_layer:
                object_by_layer[lyr_name] = []
            object_by_layer[lyr_name].append(rhino_object)
        unit_inputs = [UnitInput(unit_obj) for unit_obj in object_by_layer["unit"]]
        core_inputs = [CoreInput(core_obj) for core_obj in object_by_layer["core"]]
        window_inputs = [
            WindowInput(window_obj) for window_obj in object_by_layer["window"]
        ]
        apartment_input_structure = ApartmentInputStructure(
            apartment_name,
            unit_inputs,
            core_inputs,
            corridor_inputs=[],
            window_inputs=window_inputs,
            sidewall_inputs=[],
        )
        return apartment_input_structure


# --- ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ---
if __name__ == "__main__":
    form = ValidationForm()
    form.Show()


Because Rhino Crash. I have to check error message thorugh Console App in Mac.
This makes development experience so bad. So I want to fix this.

1 Like


This is image of UI Iโ€™m trying to build.
If i click Upload Button, if there is any error in code(simple error such as input value count not matching). Rhino Crash.

If there is better way to create GUI, I want to try, please inform me.
functions that I need with the GUI

  1. interact with User
    user click RhinoObjects > check Validation + Create BlockDefinition > simulate and optimize with the Block Definition > Visualize 3D results and show data with table or graph.
  2. Python (Cpython prefer)
  3. Various UI elements(image, table, Rhino viewport)

the reason I choose Eto was that Eto has all of this functions, but if there is other way, I want to try that.
Thank You for reading this!

Hey @์ด์‹ ํ›„ ,

A few questions.
Can you run the _systemInfo command and paste the results here.

I canโ€™t test the script crash unfortunately without this library, if you can add it here ot DM it to me I can try to replicate and then create a ticket.

I personally write my Eto UIโ€™s in the Script Editor.

I do know that some things will just Crash Rhino when scripting, especially events.
try/catch can help with certain errors to prevent crashes.

Also, more Eto docs which may help.

Hello, Thank you for response.
I hope you can replicate with this script and my contexts.

My test code which stopping Rhino

import sys
sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")

import Rhino.Input
import Rhino.Input.Custom
import scriptcontext as sc

from Eto.Forms import (
    Application,
    Form,
    TextBox,
    Button,
    Label,
    TableLayout,
    TableRow,
    TableCell,
    Dialog,
)
import Eto.Forms as ef
from Eto.Drawing import Size, Padding

def make_label(text) -> Label:
    lbl = Label()
    lbl.Text = text
    return lbl


def make_button(text) -> Button:
    btn = Button()
    btn.Text = text
    return btn

class ValidationResultForm(Form):
    def __init__(self, objects, results):
        super(ValidationResultForm, self).__init__()
        self.Title = "๊ฒ€์ฆ ๊ฒฐ๊ณผ"
        self.ClientSize = Size(400, 200)
        self.Padding = Padding(10)
        self.objects = objects

        layout = TableLayout(
            rows=[
                TableRow(
                    Label(Text=f"๊ฒ€์ฆ {key}: {'โœ… ํ†ต๊ณผ' if passed else 'โŒ ์‹คํŒจ'}")
                )
                for key, passed in results.items()
            ]
            + [None]
        )
        self.Content = layout


class ValidationDialog(Dialog):
    def __init__(
        self,
    ):
        super(ValidationDialog, self).__init__()
        self.objects = None
        self.Title = "์•„ํŒŒํŠธ ๋„๋ฉด ๊ฒ€์ฆ"
        self.Width = 400
        self.Height = 800
        self.Padding = Padding(10)

        # --- ์œ„์ ฏ๋“ค ---
        self.name_input = TextBox()
        self.upload_button = make_button("Upload")

        self.result_labels = {
            "A": make_label("๊ฒ€์ฆ A: ๋Œ€๊ธฐ ์ค‘"),
            "B": make_label("๊ฒ€์ฆ B: ๋Œ€๊ธฐ ์ค‘"),
            "C": make_label("๊ฒ€์ฆ C: ๋Œ€๊ธฐ ์ค‘"),
            "D": make_label("๊ฒ€์ฆ D: ๋Œ€๊ธฐ ์ค‘"),
        }

        self.upload_button.Click += self.on_upload_clicked

        # --- ๋ ˆ์ด์•„์›ƒ ---
        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(make_label("์•„ํŒŒํŠธ ์ด๋ฆ„")),
                    TableCell(self.name_input),
                ),
                TableRow(None, TableCell(self.upload_button)),
                TableRow(TableCell(self.result_labels["A"])),
                TableRow(TableCell(self.result_labels["B"])),
                TableRow(TableCell(self.result_labels["C"])),
                TableRow(TableCell(self.result_labels["D"])),
                None,  # ๋์— ์—ฌ์œ  ๊ณต๊ฐ„
            ]
        )

        self.Content = layout

    def on_upload_clicked(self, sender, e):
        apartment_name = self.name_input.Text
        # ์•„ํŒŒํŠธ๋กœ ๋งŒ๋“ค RhinoObject๋“ค์„ ์„ ํƒํ•˜๋„๋ก ํ•จ.

        objs = sc.doc.Objects.GetSelectedObjects(True, False)

        # ์„ ํƒ๋œ ์˜ค๋ธŒ์ ํŠธ๋“ค
        self.objects = objs
        raise Exception("this is raise test")
       

    def get_result_message(self, result_dict):
        result_message = ""
        result = result_dict.get("result")
        message = result_dict.get("message")
        if result:
            result_message += f"๊ฒ€์ฆ ๊ฒฐ๊ณผ: โœ… ํ†ต๊ณผ\n"
        else:
            result_message += f"๊ฒ€์ฆ ๊ฒฐ๊ณผ: โŒ ์‹คํŒจ :{message}\n"

        return result_message

print("Starting ValidationForm...")
dialog = ValidationDialog()
dialog.ShowModal()

my systemInfo

Rhino 8 SR19 2025-5-12 (Rhino 8, 8.19.25132.01002, Git hash:master @ 57e3eb280b0f32cbe59f53a554be5e8ffa66fc36)
License type: Commercial, build 2025-05-12
License details: Cloud Zoo

Apple macOS Version 14.7 (Build 23H124) (Physical RAM: 16GB)
Mac Model Identifier: MacBookAir10,1
Language: en-KR (MacOS default)
.NET 7.0.0

Metal GPU Family Apple 7
Metal GPU Family Common 3
Metal GPU Family Mac 2
Graphics processors
Apple M1
Color LCD (1440 x 900 @ 60.00Hz)
GPU Vendor: Apple

USB devices
None

Bluetooth devices
None

Third party kernel extensions
None

Third party plugins
/usr/lib/swift/libswiftCore.dylib
/usr/lib/swift/libswiftCoreFoundation.dylib
/usr/lib/swift/libswiftCoreGraphics.dylib
/usr/lib/swift/libswiftCoreImage.dylib
/usr/lib/swift/libswiftDarwin.dylib
/usr/lib/swift/libswiftDispatch.dylib
/usr/lib/swift/libswiftIOKit.dylib
/usr/lib/swift/libswiftMetal.dylib
/usr/lib/swift/libswiftOSLog.dylib
/usr/lib/swift/libswiftObjectiveC.dylib
/usr/lib/swift/libswiftQuartzCore.dylib
/usr/lib/swift/libswiftUniformTypeIdentifiers.dylib
/usr/lib/swift/libswiftXPC.dylib
/usr/lib/swift/libswift_Concurrency.dylib
/usr/lib/swift/libswiftos.dylib
/usr/lib/swift/libswiftsimd.dylib
/usr/lib/swift/libswift_StringProcessing.dylib
/usr/lib/swift/libswift_RegexParser.dylib
/usr/lib/swift/libswiftCryptoTokenKit.dylib
/usr/lib/usd/libusd_ms.dylib
/usr/lib/swift/libswiftCoreAudio.dylib
/usr/lib/swift/libswiftCoreLocation.dylib
/usr/lib/swift/libswiftCoreMedia.dylib
/usr/lib/swift/libswiftCompression.dylib
/usr/lib/swift/libswiftCoreMIDI.dylib
/usr/lib/swift/libswiftAVFoundation.dylib
/usr/lib/swift/libswiftCoreML.dylib
/usr/lib/swift/libswiftFileProvider.dylib
/usr/lib/swift/libswiftIntents.dylib
/usr/lib/swift/libswiftAccelerate.dylib
/usr/lib/swift/libswiftGLKit.dylib
/usr/lib/swift/libswiftGameplayKit.dylib
/usr/lib/swift/libswiftMetalKit.dylib
/usr/lib/swift/libswiftModelIO.dylib
/usr/lib/swift/libswiftSceneKit.dylib
/usr/lib/swift/libswiftSpriteKit.dylib
/usr/lib/swift/libswiftVision.dylib
/usr/lib/swift/libswiftRegexBuilder.dylib
/usr/lib/swift/libswiftDemangle.dylib
/usr/lib/swift/libswiftShazamKit.dylib
/usr/lib/swift/libswiftObservation.dylib
/usr/lib/swift/libswiftVideoToolbox.dylib
/usr/lib/swift/libswiftWebKit.dylib
/usr/lib/swift/libswiftNaturalLanguage.dylib
/usr/lib/swift/libswiftSystem.dylib
/usr/lib/swift/libswiftMapKit.dylib
/usr/lib/log/liblog_network.dylib
/Users/sinhoo/.rhinocode/py39-rh8/libpython3.9.dylib
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_heapq.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_ssl.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/libssl.1.1.dylib
/Users/sinhoo/.rhinocode/py39-rh8/libcrypto.1.1.dylib
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_socket.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/math.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/select.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/array.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_struct.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/binascii.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/zlib.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_bz2.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_lzma.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/grp.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_bisect.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_random.cpython-39-darwin.so
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/_sha512.cpython-39-darwin.so

Rhino plugins that do not ship with Rhino
/Users/sinhoo/Library/Application Support/McNeel/Rhinoceros/packages/8.0/Fologram/2024.2.9/Fologram.rhp โ€œFologramโ€ 2024.2.9.0
/Users/sinhoo/Library/Application Support/McNeel/Rhinoceros/8.0/MacPlugIns/Enscape.Rhino8.Plugin.rhp โ€œEnscape.Rhino8.Pluginโ€ 4.7.0.57

Rhino plugins that ship with Rhino
/Applications/Rhino 8.app/Contents/Frameworks/RhMaterialEditor.framework โ€œRenderer Development Kitโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/Commands.rhp โ€œCommandsโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/PlugIns/NamedSnapshots.rhp โ€œSnapshotsโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RDK_EtoUI.rhp โ€œRDK_EtoUIโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/MeshCommands.rhp โ€œMeshCommandsโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoRenderCycles.rhp โ€œRhino Renderโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoCycles.rhp โ€œRhinoCyclesโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/PlugIns/SectionTools.rhp โ€œSectionToolsโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/PlugIns/Displacement.rhp โ€œDisplacementโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/PlugIns/PanelingTools.rhp โ€œPanelingToolsโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoDLR_Python.rhp โ€œIronPythonโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/GrasshopperPlugin.rhp โ€œGrasshopperโ€ 8.19.25132.1002
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoCodePlugin.rhp โ€œRhinoCodePluginโ€ 8.19.25132.1002

1 Like

Are you able to include me this library either here or in a direct message @์ด์‹ ํ›„? The script wonโ€™t run without it for me :slight_smile:

RhinoPlugin.zip (156.3 KB)
This is all files in that directory. I ran codes in python_scripts directory.
Thanks for follwing up.

The rhino ide can now write c# directly. If you want to use pyeto, it is better to write py+cs in the rhino ide. There should be fewer errors.

1 Like

@์ด์‹ ํ›„ for what it is worth, the screenshot of the Console app shows the error and solution. __init__() missing an argument core_inputs. You probably should do core_inputs=core_inputs, but it really depends on what the __init__ of your class ApartmentInputStructure is.

edit: I actually only now noticed the ZIP file you uploaded. I think probably should remove the named arguments in the call, just pass in the values you want to without naming them.

From

        apartment_input_structure = ApartmentInputStructure(
            apartment_name,
            unit_inputs,
            core_inputs,
            corridor_inputs=[],
            window_inputs=window_inputs,
            sidewall_inputs=[],
        )

to

        apartment_input_structure = ApartmentInputStructure(
            apartment_name,
            unit_inputs,
            core_inputs,
            [],
            window_inputs,
            [],
        )
2 Likes

@N Thank you for the advice. Iโ€™m trying to find best way to build interface with Rhino - python script.
I used to build this interface with grasshopper + VSCode Studio and make every python scripts as package and import + reload in Grasshopper to make my codes reusable.
But my client had some difficulties to use GH interface so I wanted to build UI in Rhino.
What is the best way?
My concern is two things.
First, it should be flexible and interactive with rhino Document(like creating block defintions or validating)
Second, the code could be reusable(I build many tiny utilty codes and use those codes in many projects)
I found that I can write python3 in rhino script editor(before I confused script editor between RhinoPythonEditor which allows only iron python), so I started to test it. But if there is better way, please give me some advice

Thank you for your check.
I knew my code has error, my issue was that Rhino crashes so its hard to check what the error is, which makes developing experience so bad.

As you mentioned, I will try to remove named args to check if this work. Thank you!

That is indeed not ideal. @CallumSykes , @eirannejad, is there maybe something be done here that Rhino wouldnโ€™t completely crash on a Python error?

Change to get the object name, I hope you can help
Forgive me if I donโ€™t understand your native language, I can only guess and make some changes

#! python 3
import sys
sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")

import Rhino.Input
import Rhino.Input.Custom
import scriptcontext as sc
import Eto.Forms as ef
import rhinoscriptsyntax as rs

from Eto.Forms import (
    Application,
    Form,
    TextBox,
    Button,
    Label,
    TableLayout,
    TableRow,
    TableCell,
    Dialog,
)
import Eto.Forms as ef
from Eto.Drawing import Size, Padding

def make_label(text) -> Label:
    lbl = Label()
    lbl.Text = text
    return lbl


def make_button(text) -> Button:
    btn = Button()
    btn.Text = text
    return btn

class ValidationResultForm(Form):
    def __init__(self, objects, results):
        super(ValidationResultForm, self).__init__()
        self.Title = "๊ฒ€์ฆ ๊ฒฐ๊ณผ"
        self.ClientSize = Size(400, 200)
        self.Padding = Padding(10)
        self.objects = objects

        layout = TableLayout(
            rows=[
                TableRow(
                    Label(Text=f"๊ฒ€์ฆ {key}: {'โœ… ํ†ต๊ณผ' if passed else 'โŒ ์‹คํŒจ'}")
                )
                for key, passed in results.items()
            ]
            + [None]
        )
        self.Content = layout


class ValidationDialog(ef.Form):
    def __init__(
        self,
    ):
        super(ValidationDialog, self).__init__()
        self.objects = None
        self.Title = "์•„ํŒŒํŠธ ๋„๋ฉด ๊ฒ€์ฆ"
        self.Width = 400
        self.Height = 800
        self.Padding = Padding(10)
        self.Topmost = True

        # --- ์œ„์ ฏ๋“ค ---
        self.name_input = TextBox()
        self.upload_button = make_button("Upload")

        self.result_labels = {
            "A": make_label("๊ฒ€์ฆ A: ๋Œ€๊ธฐ ์ค‘"),
            "B": make_label("๊ฒ€์ฆ B: ๋Œ€๊ธฐ ์ค‘"),
            "C": make_label("๊ฒ€์ฆ C: ๋Œ€๊ธฐ ์ค‘"),
            "D": make_label("๊ฒ€์ฆ D: ๋Œ€๊ธฐ ์ค‘"),
        }

        self.upload_button.Click += self.on_upload_clicked

        # --- ๋ ˆ์ด์•„์›ƒ ---
        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(make_label("์•„ํŒŒํŠธ ์ด๋ฆ„")),
                    TableCell(self.name_input),
                ),
                TableRow(None, TableCell(self.upload_button)),
                TableRow(TableCell(self.result_labels["A"])),
                TableRow(TableCell(self.result_labels["B"])),
                TableRow(TableCell(self.result_labels["C"])),
                TableRow(TableCell(self.result_labels["D"])),
                None,  # ๋์— ์—ฌ์œ  ๊ณต๊ฐ„
            ]
        )

        self.Content = layout

    def on_upload_clicked(self, sender, e):
        try:
            # apartment_name = self.name_input.Text
            # ์•„ํŒŒํŠธ๋กœ ๋งŒ๋“ค RhinoObject๋“ค์„ ์„ ํƒํ•˜๋„๋ก ํ•จ.

            # objs = sc.doc.Objects.GetSelectedObjects(True, False)
            objs = "test"
            # # ์„ ํƒ๋œ ์˜ค๋ธŒ์ ํŠธ๋“ค
            # self.objects = objsCV 
            # raise Exception("this is raise test")
            self.name_input.Text = self.rs_cmd()
            # self.Invalidate()
        except Exception as ex:
            print("Error!" + ex)
       
    def get_result_message(self, result_dict):
        result_message = ""
        result = result_dict.get("result")
        message = result_dict.get("message")
        if result:
            result_message += f"๊ฒ€์ฆ ๊ฒฐ๊ณผ: โœ… ํ†ต๊ณผ\n"
        else:
            result_message += f"๊ฒ€์ฆ ๊ฒฐ๊ณผ: โŒ ์‹คํŒจ :{message}\n"

        return result_message

    def rs_cmd(self):
        obj = rs.SelectedObjects()
        ro = rs.ObjectName(obj)
        return ro

print("Starting ValidationForm...")
dialog = ValidationDialog()
dialog.Show()