# Is it okay to use Swing components instead of PMIObjects? & Using the setStyles() method

**URL:** <https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002>\
**Category:** Module Development\
**Created:** [October 31, 2024, 2:00pm UTC](https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002 "2024-10-31T14:00:48Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Noah\_St\_Mark](https://avatars.discourse-cdn.com/v4/letter/n/7ab992/32.png) [@Noah\_St\_Mark](https://forum.inductiveautomation.com/u/Noah_St_Mark)\
**Post date:** [October 31, 2024, 2:00pm UTC](https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002/1 "2024-10-31T14:00:48Z")

</div>

Hi Everyone,

I have a question about PMIObjects. According to the Javadocs, PMIObjects like PMILabel inherit from Swing components—in this case, from [JLabel](https://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.14/com/inductiveautomation/factorypmi/application/components/PMILabel.html).

I’m building some custom widgets and have noticed that my styles are ignored when I use PMIObjects. However, when I use Swing components, the styles work as expected. Am I using incorrect syntax for PMIObjects? Is it okay to use Swing components instead of PMIObjects? Are there any risks associated with using Swing components?

Additionally, I have a question about using the [setStyles()](https://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.14/com/inductiveautomation/factorypmi/application/components/PMILabel.html#setStyles(com.inductiveautomation.ignition.common.Dataset)) method for any PMIObject.

I’m using a [dataset builder](https://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.14/com/inductiveautomation/ignition/common/util/DatasetBuilder.html), but I’m unsure how to define the column types. I don’t know which class to use for defining the column types. Can anyone help me create a styles dataset from inside the module? Here is a screenshot from Ignition Designer when using a style customizer:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/6/6/66c24fad546be4737a1ebe811965c92eb1df1343.png)

```python
public class DiscreteControlPane extends JPanel implements ActionListener {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private PMIButton autoOn = new PMIButton();
    //private JLabel deviceState = new JLabel();
    private PMILabel deviceState = new PMILabel();
    private PMIButton manualOn = new PMIButton();
    private PMIButton manualOff = new PMIButton();
    private PMILabel deviceDescription = new PMILabel();

    private DatasetBuilder styles = DatasetBuilder.newBuilder()
            .colNames("Property","Value")
            .colTypes(String.class, String.class)
            .addRow("border", "border(line;color(0,0,0,255);2)")
            .addRow("background", Color.blue);

    private Dataset stylesDataset = styles.build();

    private String tagPath;
    private Color lightGrey = new Color(238, 236, 232, 255);

    private Dimension buttonSize = new Dimension(150, 53);

    public DiscreteControlPane() {

        logger.info("Styles -> ",deviceDescription.getStyles());

        logger.info("Inside Constructor for discrete pane -> Context: ");
        this.setBackground(lightGrey);
        this.setOpaque(true);
        GridBagLayout layoutManager = new GridBagLayout();

        this.setLayout(layoutManager);
        setPreferredSize(new Dimension(520, 303));
        GridBagConstraints layoutBehavior = new GridBagConstraints();
        layoutBehavior.weighty = 1;
        layoutBehavior.weightx = 1;
        layoutManager.setConstraints(this, layoutBehavior);

        autoOn.setText("AUTO ON");
        manualOn.setText("MANUAL ON");
        manualOff.setText("MANUAL OFF");
        deviceState.setText("INSERT DYNAMIC TEXT");
        deviceDescription.setText("INSERT DYNAMIC TEXT");

        autoOn.addActionListener(this);
        manualOn.addActionListener(this);
        manualOff.addActionListener(this);

        layoutBehavior.gridx = 0;
        layoutBehavior.gridy = 0;
        layoutBehavior.gridwidth = GridBagConstraints.REMAINDER;
        layoutBehavior.fill = GridBagConstraints.CENTER;
        layoutManager.setConstraints(deviceDescription, layoutBehavior);
        add(deviceDescription);

        //TODO: resize buttons - look into padding, why cant my elements retain their size....
        
        deviceState.setStyles(stylesDataset);
        //deviceState.setBackground(new Color(0x1F3D7C));
        deviceState.setOpaque(true);
        layoutBehavior.gridx = 0;
        layoutBehavior.gridy = 1;
        layoutBehavior.gridwidth = GridBagConstraints.REMAINDER;
        layoutBehavior.fill = GridBagConstraints.CENTER;
        layoutManager.setConstraints(deviceState, layoutBehavior);
        add(deviceState);

        layoutBehavior.insets = new Insets(10, 20, 20, 20);

        autoOn.setPreferredSize(buttonSize);
        layoutBehavior.gridx = 0;
        layoutBehavior.gridy = 2;
        layoutBehavior.gridwidth = 1;
        layoutBehavior.fill = GridBagConstraints.BOTH;
        layoutManager.setConstraints(autoOn, layoutBehavior);
        add(autoOn);

        layoutBehavior.insets = new Insets(0, 0, 20, 20);
        manualOff.setPreferredSize(buttonSize);
        layoutBehavior.gridx = 2;
        layoutBehavior.gridy = 3;
        layoutBehavior.gridwidth = 1;
        layoutBehavior.fill = GridBagConstraints.BOTH;
        layoutManager.setConstraints(manualOff, layoutBehavior);
        add(manualOff);

        layoutBehavior.insets = new Insets(10, 0, 20, 20);
        manualOn.setPreferredSize(buttonSize);
        layoutBehavior.gridx = 2;
        layoutBehavior.gridy = 2;
        layoutBehavior.gridwidth = 1;
        layoutBehavior.fill = GridBagConstraints.BOTH;
        layoutManager.setConstraints(manualOn, layoutBehavior);
        add(manualOn);
      
    }

```

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [October 31, 2024, 2:24pm UTC](https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002/2 "2024-10-31T14:24:11Z")

</div>

I don't really have an answer as far as using Swing Components over PMI objects, technically it should work just fine. I'm guessing the recommendation would be to use the PMI objects so that there is a similar UI Look and Feel for your component in comparison to the standard components. The user is going to have an expectation about how certain things work, and generally you don't want to subvert that expectation.

As for the Dataset builder, for the Style dataset that you've shown I would expect something like this:

```python
import javax.swing.border.Border
import javax.swing.border.LineBorder
import java.awt.Color

private DatasetBuilder styles = DatasetBuilder.newBuilder()
    .colNames("State","animationIndex","animationDuration","background","border","fillBackground","foreground")
    .colTypes(Integer.class, Integer.class,Integer.class,Color.class,Border.class,Boolean.class,Color.class)
    .addRow(0,0,1000,Color.blue,LineBorder(Color.black,2),true,Color.black);

```

---

<div class="post-metadata">

**Author:** ![Noah\_St\_Mark](https://avatars.discourse-cdn.com/v4/letter/n/7ab992/32.png) [@Noah\_St\_Mark](https://forum.inductiveautomation.com/u/Noah_St_Mark)\
**Post date:** [October 31, 2024, 2:46pm UTC](https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002/3 "2024-10-31T14:46:30Z")

</div>

Thanks for responding. I tried your suggested changes but no dice. Any suggestions why the PMILabel ignores styles but the JLabel will apply the styles? does the setStyles() method work?

```python

import com.inductiveautomation.factorypmi.application.components.PMIButton;
import com.inductiveautomation.factorypmi.application.components.PMILabel;
import com.inductiveautomation.ignition.common.Dataset;
import com.inductiveautomation.ignition.common.util.DatasetBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.border.LineBorder;

//Delete VisionComponent interface. Make be causing null pointer exceptions.
public class DiscreteControlPane extends JPanel implements ActionListener {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private PMIButton autoOn = new PMIButton();
    //private JLabel deviceState = new JLabel();
    private PMILabel deviceState = new PMILabel();
    private PMIButton manualOn = new PMIButton();
    private PMIButton manualOff = new PMIButton();
    private PMILabel deviceDescription = new PMILabel();

    private DatasetBuilder styles = DatasetBuilder.newBuilder()
            .colNames("State", "background", "border", "fillBackground", "foreground")
            .colTypes(Integer.class,Color.class, Border.class, Boolean.class,Color.class)
            .addRow(0,Color.blue, new LineBorder(Color.black,2),true, Color.BLACK);

    private Dataset stylesDataset = styles.build();

    private String tagPath;
    private Color lightGrey = new Color(238, 236, 232, 255);

    private Dimension buttonSize = new Dimension(150, 53);

    public DiscreteControlPane() {

        logger.info("Styles -> ",deviceDescription.getStyles());

        logger.info("Inside Constructor for discrete pane -> Context: ");
        this.setBackground(lightGrey);
        this.setOpaque(true);
        GridBagLayout layoutManager = new GridBagLayout();

        this.setLayout(layoutManager);
        setPreferredSize(new Dimension(520, 303));
        GridBagConstraints layoutBehavior = new GridBagConstraints();
        layoutBehavior.weighty = 1;
        layoutBehavior.weightx = 1;
        layoutManager.setConstraints(this, layoutBehavior);

        autoOn.setText("AUTO ON");
        manualOn.setText("MANUAL ON");
        manualOff.setText("MANUAL OFF");
        deviceState.setText("INSERT DYNAMIC TEXT");
        deviceDescription.setText("INSERT DYNAMIC TEXT");

        autoOn.addActionListener(this);
        manualOn.addActionListener(this);
        manualOff.addActionListener(this);

        layoutBehavior.gridx = 0;
        layoutBehavior.gridy = 0;
        layoutBehavior.gridwidth = GridBagConstraints.REMAINDER;
        layoutBehavior.fill = GridBagConstraints.CENTER;
        layoutManager.setConstraints(deviceDescription, layoutBehavior);
        add(deviceDescription);

        //TODO: resize buttons - look into padding, why cant my elements retain their size....
        
        deviceState.setStyles(stylesDataset);
        deviceState.repaint();
        //deviceState.setBackground(new Color(0x1F3D7C));
        deviceState.setOpaque(true);
        layoutBehavior.gridx = 0;
        layoutBehavior.gridy = 1;
        layoutBehavior.gridwidth = GridBagConstraints.REMAINDER;
        layoutBehavior.fill = GridBagConstraints.CENTER;
        layoutManager.setConstraints(deviceState, layoutBehavior);
        add(deviceState);

        layoutBehavior.insets = new Insets(10, 20, 20, 20);

        autoOn.setPreferredSize(buttonSize);
        layoutBehavior.gridx = 0;
        layoutBehavior.gridy = 2;
        layoutBehavior.gridwidth = 1;
        layoutBehavior.fill = GridBagConstraints.BOTH;
        layoutManager.setConstraints(autoOn, layoutBehavior);
        add(autoOn);

        layoutBehavior.insets = new Insets(0, 0, 20, 20);
        manualOff.setPreferredSize(buttonSize);
        layoutBehavior.gridx = 2;
        layoutBehavior.gridy = 3;
        layoutBehavior.gridwidth = 1;
        layoutBehavior.fill = GridBagConstraints.BOTH;
        layoutManager.setConstraints(manualOff, layoutBehavior);
        add(manualOff);

        layoutBehavior.insets = new Insets(10, 0, 20, 20);
        manualOn.setPreferredSize(buttonSize);
        layoutBehavior.gridx = 2;
        layoutBehavior.gridy = 2;
        layoutBehavior.gridwidth = 1;
        layoutBehavior.fill = GridBagConstraints.BOTH;
        layoutManager.setConstraints(manualOn, layoutBehavior);
        add(manualOn);
  
    }

```

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [October 31, 2024, 2:56pm UTC](https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002/4 "2024-10-31T14:56:48Z")

</div>

> [@Noah\_St\_Mark](#):
>
> does the setStyles() method work?

I'm sure it does, but it seems that perhaps there is something calling this at the creation of the component (in the designer).

If you look at the documentation for the StyleProvider Interface that defines the `setStyles` function it says this:

> Typically, the implementation of the styles is provided by the StyleListener class, which sets up all of the bindings.

Which makes me think that really the style is expected to be modified in a different place.

Thinking through this again, styles (in a Vision Component) context are really something that are changed by the end user. As the component designer, your task should really be to just provide support (which has already been done by the PMI components).

What exactly are you trying to accomplish with the styles, perhaps there is a different approach that should be used.

---

<div class="post-metadata">

**Author:** ![Noah\_St\_Mark](https://avatars.discourse-cdn.com/v4/letter/n/7ab992/32.png) [@Noah\_St\_Mark](https://forum.inductiveautomation.com/u/Noah_St_Mark)\
**Post date:** [October 31, 2024, 3:02pm UTC](https://forum.inductiveautomation.com/t/is-it-okay-to-use-swing-components-instead-of-pmiobjects-using-the-setstyles-method/98002/5 "2024-10-31T15:02:59Z")

</div>

We are modularizing some control interfaces for some of our machines. The look and feel will be consistent with stuff we originally created in designer. This label will be subscribed to a tag and change its style based off the value that is read. Its the same functionality that I currently have on the project but I want to package this inside my module. I don't mind using a JLabel since it does what I need it to do but it would of been nice to make a dataset instead.
