# Writing a customizer

**URL:** <https://forum.inductiveautomation.com/t/writing-a-customizer/12705>\
**Category:** Module Development\
**Created:** [February 22, 2017, 3:41pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705 "2017-02-22T15:41:40Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [February 22, 2017, 3:41pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/1 "2017-02-22T15:41:40Z")

</div>

I need to write a customizer for a dataset that includes properties such as color, border etc.

As an example, Ignition uses a text string to store the color values and border values. What class/classes do I use to translate from the text string that is stored to a java Color and from text string to a java Border?  
Using regex, it is simple to write a converter from a string such as “color(200,250,210,250)” to an instance of a color object. However, the conversion from the text border description is a bit more complex. Besides, I should use code that is already available.

What classes support the development of the customizer itself? How do I learn how to use them?

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [February 28, 2017, 5:16pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/2 "2017-02-28T17:16:55Z")

</div>

Getting a customizer to display is easy enough. Albeit, I wondering if there is any special magic to setting the values of the following fields:

[code] public static final String VALUE\_ACCEL\_KEYSTROKE = “c”;  
public static final String VALUE\_COMMAND = “MyComponent Customizer”;

```
public static final Integer	VALUE_MNEMONIC = 1; 
public static final String	VALUE_NAME = "MyComponentCustomizer"; 
public static final String	VALUE_SHORT_DESCRIPTION = "Opens the customizer for the selected MyComponent"; 
public static final CustomizerDescriptor	VALUE_DESCRIPTOR
                        = new CustomizerDescriptor(
                                MyComponentCustomizer.class
                            , VALUE_NAME
                            , VALUE_COMMAND
                            , VALUE_MNEMONIC
                            , VALUE_SHORT_DESCRIPTION
                            , VALUE_ACCEL_KEYSTROKE);

```

[/code]

In particular, is there any special importance to the value of “VALUE\_MNEMONIC”?  
Accelerator keystroke doesn’t do what I expect, namely the short cut for the menu item to invoke the customizer.  
I also am unable to set a title for the Customizer panel when it is displayed.  
The VALUE\_COMMAND appears to be the value displayed as the menu item and the SHORT\_DESCRIPTION appears to be the tool tip in said menu.

---

<div class="post-metadata">

**Author:** ![KathyApplebaum](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kathyapplebaum/32/7261_2.png) [@KathyApplebaum](https://forum.inductiveautomation.com/u/KathyApplebaum)\
**Post date:** [March 1, 2017, 3:04pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/3 "2017-03-01T15:04:55Z")

</div>

It gets passed to a Java Action associated with the customizer. We tend to use null, and you’re certainly welcome to as well. If you want to use a value, use a value that would map to a character. One way to do it is `KeyEvent.VK_1` KeyEvent.VK\_1 is just a constant, but the intent is easier to read in the code than using ‘49’ 🙂

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 2, 2017, 12:38am UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/4 "2017-03-02T00:38:03Z")

</div>

I found a class called SwingColorEditor that appears close to what I need with respect to allowing the user to select colors. When used in the code presented below, it gives the following display:  
 ![](https://us1.discourse-cdn.com/inductiveautomation/original/2X/0/062b0d0a5de908ecd0495faadd3bb88a47cb4a49.jpeg)  
  
However, I think for a customizer the following is more appropriate and I suspect I need a different class than the SwingColorEditor to achieve it:  
 ![](https://us1.discourse-cdn.com/inductiveautomation/original/2X/4/40f6cd26ed3f57f771320990eb695b83ac690c6f.jpeg)  
  
Furthermore, I’m not clear how to interface SwingColorEditor with a TableCellEditor. Here is how I’ve used it in the TableCellRenderer:

[code]private class JJColorRenderer extends SwingColorEditor  
implements TableCellRenderer {  
boolean isBordered = true;

```
    public JJColorRenderer(boolean isBordered) {
        this.isBordered = isBordered;
        setOpaque(true); //MUST do this for background to show up.
    }

    @Override
    public Component getTableCellRendererComponent(
                            JTable table, Object color,
                            boolean isSelected, boolean hasFocus,
                            int row, int column) {
        Color newColor = parseColor((String)color);
        setValue(newColor);

```

// some stuff manipulating the border is removed for clarity

```
        return this.getCustomEditor();
    }
}[/code]

```

My current implementation of the TableCellEditor brings up a dialog with JColorChooser. It allows the user to select a color, but it is hardly in keeping with the Ignition look and feel.

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 6, 2017, 12:36pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/5 "2017-03-06T12:36:34Z")

</div>

The following works to a reasonable extent as a table cell editor for Colors. It gives a null pointer exception when a value is selected from the color wheel, suggesting that the SwingColorEditor instance is not quite initialized properly. Perhaps a call to .initComponents is in order. By applying the principle of symmetry, I figure that SwingBorderEditor and SwingIconEditor would be the classes I need for the Border columns and Icon columns respectively.

[code] private class ColorEditor extends AbstractCellEditor  
implements TableCellEditor,  
PropertyChangeListener {  
Color currentColor;  
String currentColorString;  
SwingColorEditor swingcoloreditor;;

```
    public ColorEditor() {
        swingcoloreditor = new SwingColorEditor();
// setting BindableEnabled to false removes the Binding icon from the editor
        swingcoloreditor.setBindableEnabled(false);
// Need to catch the property change event to get the newly selected value
        swingcoloreditor.addPropertyChangeListener(this);
    }

    //Implement the one CellEditor method that AbstractCellEditor doesn't.
    @Override
    public Object getCellEditorValue() {
        return currentColorString;
    }

    //Implement the one method defined by TableCellEditor.
    @Override
    public Component getTableCellEditorComponent(JTable table,
                                                 Object value,
                                                 boolean isSelected,
                                                 int row,
                                                 int column) {
        currentColorString = (String)value;
        currentColor = parseColor(currentColorString);
        swingcoloreditor.setValue(currentColor);
        return swingcoloreditor.getCustomEditor();
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        currentColor = (Color) swingcoloreditor.getValue();
        currentColorString = String.format(
                "color(%d,%d,%d,%d)"
                ,currentColor.getRed()
                ,currentColor.getGreen()
                ,currentColor.getBlue()
                ,currentColor.getAlpha()
                );
    }     
}[/code]
```

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 6, 2017, 1:11pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/6 "2017-03-06T13:11:08Z")

</div>

FYI, here is the error message that I get when I select a value from the color wheel

[quote]Exception in thread “AWT-EventQueue-2” java.lang.NullPointerException  
at com.inductiveautomation.factorypmi.designer.property.editors.bb.SwingColorEditor.setValue(SwingColorEditor.java:164)  
at com.inductiveautomation.factorypmi.designer.property.editors.bb.SwingColorEditor$2.stateChanged(SwingColorEditor.java:91)  
at com.inductiveautomation.ignition.client.util.gui.color.ColorEditor.fireChange(ColorEditor.java:340)  
at com.inductiveautomation.ignition.client.util.gui.color.ColorEditor.setSelectedColor(ColorEditor.java:309)  
at com.inductiveautomation.ignition.client.util.gui.color.ColorEditor$2.stateChanged(ColorEditor.java:252)  
at javax.swing.colorchooser.DefaultColorSelectionModel.fireStateChanged(DefaultColorSelectionModel.java:149)  
at javax.swing.colorchooser.DefaultColorSelectionModel.setSelectedColor(DefaultColorSelectionModel.java:99)[/quote]  
Despite the message, the selected value is passed through correctly to my table

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 6, 2017, 3:31pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/7 "2017-03-06T15:31:26Z")

</div>

Looks like perhaps I should be using the classes ColorEditor.ColorTableCellEditor and ColorEditor.ColorTableCellRenderer for processing my colors. It will take a touch of refactoring.

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 6, 2017, 4:02pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/8 "2017-03-06T16:02:59Z")

</div>

Yes indeed, this is much better

` jtable.setDefaultRenderer(Color.class,
                                 new ColorEditor.ColorTableCellRenderer());
        jtable.setDefaultEditor(Color.class,
                               ColorEditor.createTableCellEditor());`  
No need for me to set up a custom renderer or cell editor. Nor are there any mysterious null pointer exceptions.

Unfortunately, I cannot find similar classes for Borders.

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 8, 2017, 2:09pm UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/9 "2017-03-08T14:09:49Z")

</div>

I’ve had no luck trying to find a class that supports translating a java Border to a string and back again. I can write my own that would support translating the simpler borders from string to border. However, I’ve no idea how to access the details of the border to write a translator from border to string. Any help would be most appreciated.

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 9, 2017, 1:28am UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/10 "2017-03-09T01:28:06Z")

</div>

Yahoo tells me today that I’ve become the three eyed raven and I can no longer depend on Hodor.  
Apparently Aesop did write:  
So quando a gente se dedica pessoalmente ao trabalho, sem esperar ajuda alheia, ele vai para a frente.

So, this will have to do for the moment.

[code]public class BorderTranslator {  
public static String toString(Border b) {  
// translates border to a human readable form  
if (b == null) {  
return “border(empty)”;  
}  
if (b.getClass().equals( EmptyBorder.class)) {  
return “border(empty)”;

```
    } else if (b.getClass().equals( EtchedBorder.class)) {
        EtchedBorder etchB = (EtchedBorder) b;
        int type = etchB.getEtchType();
        return String.format("border(etched;%d)",type);
        
    } else if (b.getClass().equals( BevelBorder.class)) {
        BevelBorder bevelB = (BevelBorder) b;
        int type = bevelB.getBevelType();
        return String.format("border(bevel;%d)",type);
        
    } else if (b.getClass().equals( BasicBorders.ButtonBorder.class)) {
        return String.format("border(button)");
        
    } else if (b.getClass().equals( BasicBorders.FieldBorder.class)) {
        return String.format("border(field)");
        
    } else if (b.getClass().equals( LineBorder.class)) {
        LineBorder lineB = (LineBorder) b;
        int type = lineB.getThickness();
        Color col = lineB.getLineColor();
        return String.format("border(line;%s;%d)", toString(col), type);
        
    } else if (b.getClass().equals( MatteBorder.class)) {
        MatteBorder matteB = (MatteBorder) b;
        Insets insets = matteB.getBorderInsets();
        Color col = matteB.getMatteColor();
        return String.format("border(matte;%s;%d;%d;%d;%d)"
                , toString(col)
                , insets.top, insets.left
                , insets.bottom, insets.right);
    }
    return "border(empty)"; // for an unrecognized border make it an empty one
}
    
public static String toString(Color val) {
    return String.format(
                "color(%d,%d,%d,%d)"
                ,val.getRed()
                ,val.getGreen()
                ,val.getBlue()
                ,val.getAlpha()
                );
}

public Border toBorder(String s) {
    
    return BorderFactory.createEmptyBorder();
}

```

}[/code]

---

<div class="post-metadata">

**Author:** ![JimBranKelly1](https://avatars.discourse-cdn.com/v4/letter/j/7feea3/32.png) [@JimBranKelly1](https://forum.inductiveautomation.com/u/JimBranKelly1)\
**Post date:** [March 9, 2017, 4:17am UTC](https://forum.inductiveautomation.com/t/writing-a-customizer/12705/11 "2017-03-09T04:17:03Z")

</div>

The following works for the moment to parse the border descriptor string into a Border object instance:

[code]public static Border toBorder(String s) {

```
    if (s.length() < 8) {
        return BorderFactory.createEmptyBorder();
    }
    String arglist = s.substring(7, s.length()-1); // strip leading and trailing syntax "border(" and ")"
    String[] args = arglist.split(";"); // get the arguments
    
    if ("empty".equalsIgnoreCase(args[0])) {
        return BorderFactory.createEmptyBorder();
        
    } else if ("etched".equalsIgnoreCase(args[0])) {
        return BorderFactory.createEtchedBorder(Integer.parseInt(args[1]));
        
    } else if ("bevel".equalsIgnoreCase(args[0])) {
        int i = Integer.parseInt(args[1]);
        if ( i == 1010 ) {
            return BorderFactory.createCompoundBorder(
                    BorderFactory.createBevelBorder(0)
                    ,BorderFactory.createBevelBorder(1)
            );
        }
        return BorderFactory.createBevelBorder(i);
    
    } else if ("field".equalsIgnoreCase(args[0])) {
        return new FieldBorder();
    
    } else if ("button".equalsIgnoreCase(args[0])) {
        return new ButtonBorder();        
   
    } else if ("line".equalsIgnoreCase(args[0])) {
        return createLineBorder(args);
        
    } else if ("matte".equalsIgnoreCase(args[0])) {
        return createMatteBorder(args);        
    }
    return BorderFactory.createEmptyBorder();
}[/code]
```
