Adding Data & selectedRow Properties to Custom Module

Hey all, I’m building a component that uses Ignition;s VisionAdvancedTable object. I’m trying to make properties for this component that allow the designer to access the dataset as well as the selectedRow like Ignition’s power table.

I’ve done some digging through the SDK and found the VisionAdvancedTableBeanInfo object but don’t know how to use it.

How would I go about adding these properties, any help is appreciated!

The Power Table is the VisionAdvancedTable.

You should probably only provide bean infos for your own custom Swing components, unless you really know what you’re doing.

If you need to add features to an existing component, make your own subclass of that component and register it in the designer palette separately. Your subclass’s beaninfo implementation can request and supplement the information from the parent beaninfo to make the new properties and other features work smoothly with the superclass.

1 Like

I guess I can share how NoteChart does this with the Classic Chart–you’ll have to adapt for the Power Table:

public class NoteChartBeanInfo extends CommonBeanInfo {

	public NoteChartBeanInfo() {
		super(NoteChart.class, new CustomizerDescriptor[] {
				ChartCustomizer.VALUE_DESCRIPTOR });
		getBeanDescriptor().setValue("dbl-click-customizer", ChartCustomizer.VALUE_DESCRIPTOR.getValueName());
	}

	@Override
	protected void initProperties() throws IntrospectionException {
		// Adds common properties
		super.initProperties();

		// Remove properties that NoteChart will define differently from CommonBeanInfo
		removeProp("opaque");

		// Add all notechart-specific properties
		addProp("notes", "Notes", "Dataset of text annotations to display",
				CAT_DATA, PREFERRED_MASK | BOUND_MASK);
		addProp("altNotes", "Alternate Notes", "Dataset of alternate annotations for live modifications",
				CAT_DATA, PREFERRED_MASK | BOUND_MASK);
		addProp("traceTS", "Trace Timestamp",
				"Timestamp for the selected annotation, or independent trace if no selection",
				CAT_DATA, PREFERRED_MASK | BOUND_MASK);
// ***** Much clipped out
		addProp("enableNoteSelect", "Enable Note Selection",
				"Annotations can clicked (at their text) to set selectedNote or selectedAltNote",
				CAT_BEHAVIOR, EXPERT_MASK);

		/*
		 * Hide properties from PMIChart that NoteChart can't use. They
		 * would show up from getAdditionalBeanInfo().
		 */
		addProp("chartType", "Must be an XY Chart", "", CAT_BEHAVIOR, HIDDEN_MASK);
		addProp("subplotMode", "Must be Combined Domain", "", CAT_BEHAVIOR, HIDDEN_MASK);
	}

	@Override
	public Image getIcon(int kind) {
		switch (kind) {
		case BeanInfo.ICON_COLOR_16x16:
		case BeanInfo.ICON_MONO_16x16:
			return new ImageIcon(getClass().getResource("/images/note-chart_16.png")).getImage();
		case SimpleBeanInfo.ICON_COLOR_32x32:
		case SimpleBeanInfo.ICON_MONO_32x32:
			return new ImageIcon(getClass().getResource("/images/note-chart_32.png")).getImage();
		}
		return null;
	}

	@Override
	protected void initDesc() {
		VisionBeanDescriptor bean = getBeanDescriptor();
		bean.setName("Classic Note Chart");
		bean.setDisplayName("Classic Note Chart");
		bean.setShortDescription("A component that displays time-series Plots with annotation marks.");
		BeanInfo superbi = new PMIChartBeanInfo();
		BeanDescriptor superbean = superbi.getBeanDescriptor();
		List<ExtensionFunctionDescriptor> extensionFunctionList = new ArrayList<ExtensionFunctionDescriptor>();
		@SuppressWarnings("unchecked")
		List<ExtensionFunctionDescriptor> superFunctionList = (List<ExtensionFunctionDescriptor>) superbean
				.getValue("vision-extension-functions");
		if (superFunctionList != null) {
			for (ExtensionFunctionDescriptor efd : superFunctionList) {
				if (!efd.getMethodName().equalsIgnoreCase("getXTraceLabel"))
					extensionFunctionList.add(efd);
			}
		}
		extensionFunctionList.add(ExtensionFunctionDescriptor.newFunction("formatTraceTS").returns(String.class)
				.description("Allows overriding the displayed timestamp in X-Trace mode.  Return the string or None for the default.")
				.arg("chart", "A JFreeChart object. Refer to the JFreeChart documentation for API details.")
				.arg("traceTS", "A java Date object.")
				.arg("textFmt", "A string with the date formatting pattern that would be used by default.")
				.defaultImpl("# Put your code here").build());
		extensionFunctionList.add(ExtensionFunctionDescriptor.newFunction("formatTraceValue").returns(String.class)
				.description("Allows overriding the displayed pen name and value in X-Trace mode.  Return the string or None for the default.")
				.arg("chart", "A JFreeChart object. Refer to the JFreeChart documentation for API details.")
				.arg("subPlot", "The integer subplot index within the chart.")
				.arg("plotDS", "The integer plot dataset index within the subplot.")
				.arg("penIdx", "The integer pen index within the plot dataset.")
				.arg("v", "The (interpolated) pen value to format.")
				.arg("rangeAxis", "The value axis object whose number format override would normally be used.")
				.arg("penName", "The name of the pen.  *Not* automatically prepended to your result string.")
				.defaultImpl("# Put your code here").build());
		bean.setValue("vision-extension-functions", extensionFunctionList);
	}

	@Override
	public BeanInfo[] getAdditionalBeanInfo() {
		BeanInfo[] superbi = { new PMIChartBeanInfo() };
		return superbi;
	}
}

While the complete file is commercially copyrighted, the above snippet is hereby placed in the public domain. The magic is in that last method definition. (:

5 Likes

Thank you very much Phil! It’s much appreciated. Going to go give it the college try :grin:

Hey Phil, my understanding is that the getAdditionalBeanInfo() method needs to be called somewhere . My first thought would be the initProperties(), considering you have a note there in the snippet. I tried that using by calling it with this.getAdditionalBeanInfo(), with no success.

protected void initProperties() throws IntrospectionException {
        // Adds common properties
        super.initProperties();
        this.getAdditionalBeanInfo();
        //Add properties
        //addProp("data", "table data", "The data currently in the table", CAT_DATA, PREFERRED_MASK | BOUND_MASK);
        //Remove Properties
        //removeProp("opaque");

I also noticed that I’m having issues adding and removing properties, which I found odd, but I don’t know the best way test these other then uploading it to the gateway and checking. Any tricks to the trade you’d recommend for this?

No, the designer infrastructure calls getAdditionalBeanInfo when your DesignerHook adds the component to the palette.

Your initProperties() method should do the following:

  1. Call super.initProperties() to get component defaults.
  2. Use .removeProp() to discard defaults you don’t want, or would conflict with later definitions.
  3. Use .addProp() to set up all your new properties.
  4. Use .addProp(..., HIDDEN_MASK) to suppress properties that will come in from the superclass beaninfo that you don’t want to show up.

That last works because any property you declare in your beaninfo takes precedence over properties supplied by getAdditionalBeanInfo().

2 Likes

I'm a greybeard who clings to traditional methods. /:

There are instructions for setting up debugging of designer/client scopes with your IDE, but I've never bothered. I litter my code with debug logging whenever I'm experimenting with parts of Ignition I'm not confident of. And then load the fresh module to the gateway.

I also don't bother with auto-uploading to a gateway. I have numerous gateways with various Ignition versions, so that feature never was all that convenient for me. My build + drag-n-drop onto the module install page of a target server takes about 35 seconds for my most complex build. I keep a terminal open tailing the wrapper log of such development targets.