Rhino Crashing on trying to load a new image through Python Script

Hi im Jordan,

I’m still somewhat new to coding so I would be very grateful for some help.

I am trying to set up a UI window that displays an image that is corresponding to a selection in a ListBox.

I have an initial placeholder image that is displaying correctly, and is used when there is no selection from the ListBox. But when I make a selection from the ListBox that has a new Bitmap associated to load for that selection, it is crashing Rhino, and I am wondering if there is a specific step that I am missing when trying to call a new image when the selection is changed.

Here is a code snippit of how the Placeholder image is set originally for the UI.

    self.previewimage = ImageView()
    self.previewimage.ToolTip = "A preview of the Luminaire."
    self.previewimage.Image = Bitmap(RootFolder + Imagery + "\PlaceHolder.jpg")
    self.previewimage.Height = 150
    self.previewimage.Width = 150

Here is a snippit of my code for how the new image is called to replace the placeholder image.

def Get_Preview_Image(self, sender, e):
    LumPreview = "\PlaceHolder.jpg"
    if self.LumLib.SelectedIndex == 0:
        LumPreview = "\\" + self.LumLib.DataStore[0].replace(".3dm",".jpg")
        self.previewimage.Image = Bitmap(RootFolder + Imagery + LumPreview)
    elif self.LumLib.SelectedIndex == 1:
        LumPreview = "\\" + self.LumLib.DataStore[1].replace(".3dm",".jpg")
        self.previewimage.Image = Bitmap(RootFolder + Imagery + LumPreview)
    else:
        print("Selection not set up yet.")

The string representation for LumPreview is returning correctly to what is required, hence why I am unsure as to why it is crashing unless I am missing a step or have gone about the transition of imagery in the wrong way.

Any help is greatly appreciated.

Jordan

Hi Jordan,

Can you post a complete example? I can’t reproduce a crash with the following code, which changes the image in the form:

from time import sleep
import Eto.Forms

from Eto.Forms import ImageView
from Eto.Drawing import Bitmap


window = Eto.Forms.Form()
previewimage = ImageView()
previewimage.ToolTip = "A preview of the Luminaire."
previewimage.Image = Bitmap(r"C:\Users\Pierre\Desktop\a.jpg")
previewimage.Height = 150
previewimage.Width = 150
window.Content = previewimage
window.Show()

sleep(3)
previewimage.Image = Bitmap(r"C:\Users\Pierre\Desktop\b.jpg")

Hi @pierrec, thanks for taking a look at my issue, I am currently using Rhino 7, and here is the complete example that is crashing whenever I am selecting either the first or 2nd option in my listbox.

My initial image the Placeholder.jpg works perfectly fine, its just when i use the list box to make my selection which is then changing the file name to use for the JPG image replacement it is crashing, if i remove the setting of a new bitmap LumPreview does return the correct string for the new image, so I believe it is something in how im setting the new bitmap.

import clr
clr.AddReference("Eto")
clr.AddReference("Rhino.UI")
from Rhino.UI import *
from Eto.Forms import *
from Eto.Drawing import *

import os
import scriptcontext
import rhinoscriptsyntax as rs
import Rhino.UI
import Eto.Drawing as drawing
import Eto.Forms as forms

class LuminaireManager(forms.Form): 

    def __init__(self):
        self.Title = "Luminaire Manager"
        self.Resizable = False
        self.Padding = drawing.Padding(2)
        self.Topmost = True
        RootFolder ="D:\Sync\JC-CB File Transfer\_JC-CB Exchange\RhinoLuminaires"
        Luminaires = "\Luminaires"
        Imagery = "\PreviewImages"
        LampDetail = "\Descriptions"

        def Titles(text):
            m_label = forms.Label()
            m_label.Text = text
            m_label.VerticalAlignment = forms.VerticalAlignment.Center
            m_label.TextAlignment = forms.TextAlignment.Right
            return m_label

        self.LumLib = forms.ListBox()
        self.LumLib.ToolTip = "A list of the Luminaire objects in the scene containing the designated naming convention."
        self.LumLib.Height = 150
        self.LumLib.Width = 400
        self.LumLib.DataStore = os.listdir(RootFolder + Luminaires)
        self.LumLib.SelectedIndexChanged += self.Get_Preview_Image

        self.previewimage = ImageView()
        self.previewimage.ToolTip = "A preview of the Luminaire."
        self.previewimage.Image = Bitmap(RootFolder + Imagery + "\PlaceHolder.jpg")
        self.previewimage.Height = 150
        self.previewimage.Width = 150

        self.groupbox0 = forms.GroupBox(Text = "Luminaire Library:")
        Padding = drawing.Padding(10, 5, 10, 5)
        grouplayout0 = forms.DynamicLayout()
        grouplayout0.Spacing = drawing.Size(5, 5)

        self.groupbox1 = forms.GroupBox(Text = "Luminaire Preview:")
        Padding = drawing.Padding(30, 15, 30, 15)
        grouplayout1 = forms.DynamicLayout()
        grouplayout1.Spacing = drawing.Size(10, 10)

        grouplayout0.AddRow(None)
        grouplayout0.AddRow(self.LumLib)
        grouplayout0.AddRow(None)
        self.groupbox0.Content = grouplayout0

        grouplayout1.AddRow(None)
        grouplayout1.AddRow(self.previewimage)
        grouplayout1.AddRow(None)
        self.groupbox1.Content = grouplayout1

        layout = forms.DynamicLayout(DefaultSpacing = drawing.Size(2,2))
        layout.AddRow(self.groupbox0, self.groupbox1)
        self.Content = layout;

    def Get_Preview_Image(self, sender, e):
        LumPreview = "\PlaceHolder.jpg"
        if self.LumLib.SelectedIndex == 0:
            LumPreview = "\\" + self.LumLib.DataStore[0].replace(".3dm",".jpg")
            self.previewimage.Image = Bitmap(RootFolder + Imagery + LumPreview)
       elif self.LumLib.SelectedIndex == 1:
            LumPreview = "\\" + self.LumLib.DataStore[1].replace(".3dm",".jpg")
            self.previewimage.Image = Bitmap(RootFolder + Imagery + LumPreview)
        else:
            print("Selection not set up yet.")

def LuminaireManagerWindow():
    dlg = LuminaireManager()
    dlg.Show();

if __name__ == "__main__":
    LuminaireManagerWindow()

Not sure why this is giving you a full crash, it would be easier if it just printed an error, but the issue is with your RootFolder and Imagery variables: they are not defined in Get_Preview_Image. Here’s something that works:

import clr
clr.AddReference("Eto")
clr.AddReference("Rhino.UI")
from Rhino.UI import *
from Eto.Forms import *
from Eto.Drawing import *

import os
import scriptcontext
import rhinoscriptsyntax as rs
import Rhino.UI
import Eto.Drawing as drawing
import Eto.Forms as forms

class LuminaireManager(forms.Form): 

    def __init__(self):
        self.Title = "Luminaire Manager"
        self.Resizable = False
        self.Padding = drawing.Padding(2)
        self.Topmost = True
        RootFolder =r"C:\Users\pcuvil\Desktop"
        self.RootFolder = RootFolder
        Luminaires = r"\Luminaires"
        Imagery = r"\PreviewImages"
        self.Imagery = Imagery
        LampDetail = r"\Descriptions"

        def Titles(text):
            m_label = forms.Label()
            m_label.Text = text
            m_label.VerticalAlignment = forms.VerticalAlignment.Center
            m_label.TextAlignment = forms.TextAlignment.Right
            return m_label

        self.LumLib = forms.ListBox()
        self.LumLib.ToolTip = "A list of the Luminaire objects in the scene containing the designated naming convention."
        self.LumLib.Height = 150
        self.LumLib.Width = 400
        self.LumLib.DataStore = os.listdir(RootFolder + Luminaires)
        self.LumLib.SelectedIndexChanged += self.Get_Preview_Image

        self.previewimage = ImageView()
        self.previewimage.ToolTip = "A preview of the Luminaire."
        self.previewimage.Image = Bitmap(RootFolder + Imagery + r"\a.jpg")
        self.previewimage.Height = 150
        self.previewimage.Width = 150

        self.groupbox0 = forms.GroupBox(Text = "Luminaire Library:")
        Padding = drawing.Padding(10, 5, 10, 5)
        grouplayout0 = forms.DynamicLayout()
        grouplayout0.Spacing = drawing.Size(5, 5)

        self.groupbox1 = forms.GroupBox(Text = "Luminaire Preview:")
        Padding = drawing.Padding(30, 15, 30, 15)
        grouplayout1 = forms.DynamicLayout()
        grouplayout1.Spacing = drawing.Size(10, 10)

        grouplayout0.AddRow(None)
        grouplayout0.AddRow(self.LumLib)
        grouplayout0.AddRow(None)
        self.groupbox0.Content = grouplayout0

        grouplayout1.AddRow(None)
        grouplayout1.AddRow(self.previewimage)
        grouplayout1.AddRow(None)
        self.groupbox1.Content = grouplayout1

        layout = forms.DynamicLayout(DefaultSpacing = drawing.Size(2,2))
        layout.AddRow(self.groupbox0, self.groupbox1)
        self.Content = layout;

    def Get_Preview_Image(self, sender, e):
        LumPreview = r"\PlaceHolder.jpg"
        LumPreview = "\\" + self.LumLib.DataStore[self.LumLib.SelectedIndex].replace(".3dm", ".jpg")
        image_path = self.RootFolder + self.Imagery + LumPreview
        self.previewimage.Image = Bitmap(image_path)

def LuminaireManagerWindow():
    dlg = LuminaireManager()
    dlg.Show();

if __name__ == "__main__":
    LuminaireManagerWindow()

As an aside not directly related to your problem, I think you should try to use Python’s os.path facilities to deal with paths. Although strings are a good approximation for a static path, joining them and moving around directories will be much safer with os.path. Also, when dealing with backslashes in strings (and paths-as-strings on Windows), make sure all of them are properly escaped, either with "with\\slash" or r"with\slash", or you will have surprises when your folder names start with some letters.

@curtisw, is there something to look at for you here? I feel like this should not be a complete Rhino crash. I’ve got a report on Raygun, and a minimal example below (crash on the print(crash_rhino) line):

import Eto.Drawing as drawing
import Eto.Forms as forms

class CrashList(forms.Form): 
    def __init__(self):
        self.listbox = forms.ListBox()
        self.listbox.DataStore = ["a", "b", "c"]
        self.listbox.SelectedIndexChanged += self.onIndexChanged
        self.Content = self.listbox

    def onIndexChanged(self, sender, e):
        print(self.listbox.SelectedIndex)
        print(crash_rhino)
        
if __name__ == "__main__":
    dlg = CrashList()
    dlg.Show()

2 Likes

Unfortunately there’s no way for us to avoid crashes on UI events, only the main script execution. I recommend adding a try/except to any event handler if you wish to avoid crashes in the python scripts. For example:

    def onIndexChanged(self, sender, e):
        try:
            print(self.listbox.SelectedIndex)
            print(crash_rhino)
        except Exception as e:
            print("An error occurred: " + str(e))

Thank you very much for the help, I will use the information that you have provided and see if i can achieve the desired outcome.

Jordan