Easy Chart Pen Panel Moves Through configureChart Scripting

Tom Garrett7 min read
Other ManufacturerOther TopicTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

The Easy Chart pen control panel has no position property. The supported route is to leave it alone and drive pen visibility from other components through cell update bindings on the Tag Pens dataset. The working route is a configureChart extension function that finds the pen panel among the chart's child components and re-docks it in the chart's BorderLayout. Moving the panel is a one-call change. Making its checkboxes run horizontally, or adding tooltips to them, means reaching into Swing children whose behavior you must inspect on your own install.

Geometry of the chart container and the pen strip

The decisive quantity is pixels of trend area consumed by the pen strip. Calling self.getComponents() on the Easy Chart returns two children. The first is a plain javax.swing.JPanel that holds the trend, and the second is PMIEasyChart$PenPanel. Their reported bounds in one 400 px wide chart:

Child Position (x,y) Size (w x h) Layout
javax.swing.JPanel (trend) 0,0 400x442 BorderLayout
PMIEasyChart$PenPanel (pen controls) 0,442 400x48 BorderLayout

The pen panel is a sibling of the trend panel inside the chart's outer container, docked by default below the trend. It takes 48 px of height in this example and gives the trend the full width. Because the outer container uses BorderLayout, the panel's edge is set by the constraint passed to add(). No component property exposes that constraint, which is why the property editor offers nothing.

Reading the symptom: what each request maps to

What you want Layer that controls it Route
Pen panel at bottom, right, or another edge Outer chart container BorderLayout constraint configureChart: remove PenPanel, re-add with new constraint, validate()
Checkboxes closer to the chart or in your own layout Tag Pens dataset visible column Independent checkbox group bound through cell update bindings
Hide, show, enable, or disable pens from other components Tag Pens dataset Cell update bindings on the dataset
Pens listed horizontally Layout of the children inside PenPanel Script; setLayout(FlowLayout()) on the PenPanel itself produced no change
Tooltip on each pen checkbox Checkbox objects inside PenPanel Script via the checkBoxes / getCheckBoxes() members of PenPanel

Mechanism: why the script works and why FlowLayout on PenPanel did not

configureChart(self, chart) is the scripting extension function on the Easy Chart. It runs before the chart renders and receives the component (self) and the underlying JFreeChart object (chart). It returns nothing. Inside it you have full access to the Swing container tree of the component, so the pen panel can be pulled out of the layout manager and added back with a different BorderLayout constraint. Calling self.validate() afterward forces the layout manager to recompute bounds.

PenPanel is itself a container with children. Enumerating them shows a JPanel and a JScrollPane. The scroll pane holds the tag list and presumably scrolls when the pen count exceeds the panel height. Setting a layout on the outer PenPanel does not reorder checkboxes that live inside the scroll pane's viewport. A JScrollPane uses its own scroll-pane layout, so replacing that layout is not the lever. In Swing the list container is the viewport view, reachable with getViewport().getView(). Whether the panel rebuilds its checkboxes and resets layouts on pen dataset changes is internal to PenPanel (its member list includes createGUI). Test on your install rather than assuming a one-time layout change sticks.

Procedure: dock the pen panel at another edge

  1. Open the Easy Chart in the Designer and open the component scripting editor, then select the configureChart extension function.
  2. Paste the script below. It reproduces the working bottom placement using BorderLayout.PAGE_END.
  3. Save, then preview or run the window in a client. Confirm the strip moved and the trend area re-expanded.
  4. To try the right edge, change the constraint to . This is the standard Java BorderLayout constant for that edge and is untested on this component. Right-docking a container sized for a wide strip depends on the panel's preferred width, so read the result before committing to it.
def configureChart(self, chart):
    from java.awt import BorderLayout
    from com.inductiveautomation.factorypmi.application.components.PMIEasyChart import PenPanel
    for c in self.getComponents():          # iterate child components
        if isinstance(c, PenPanel):         # locate the pen control panel
            self.remove(c)                  # detach from the layout manager
            self.add(c, BorderLayout.PAGE_END)   # re-add at bottom
    self.validate()                         # recompute layout

The function may run more than once as the chart reconfigures. The loop above is safe to repeat because it removes and re-adds the same component with the same constraint each time.

Procedure: inspect the PenPanel internals for horizontal layout

Print members from a live instance. Calling dir() on the imported class shows class-level attributes only; an instance from the chart shows what that runtime object exposes. The listing for the class includes checkBoxes, getCheckBoxes, createGUI, getLayout, and the nested PenControl.

  1. Inside the PenPanel branch of the loop, run print(dir(c)) and print(c.getLayout()).
  2. Loop c.getComponents() and print each child's type and bounds. Expect a JPanel and a JScrollPane.
  3. For the JScrollPane child, print ch.getViewport().getView() and its getLayout(). That inner container is the candidate for a FlowLayout or a wrapped grid.
  4. Apply the layout change to that inner container, then call revalidate() on it and self.validate() on the chart. Test with a pen count large enough to force wrapping.

A layout set directly on PenPanel was tried and left the output unchanged, so do not spend more time there. The scroll pane's contents are the target.

Procedure: tooltips on pen checkboxes

PenPanel exposes checkBoxes and getCheckBoxes(). Read that collection, check its type with print(type(...)), then call setToolTipText() on each checkbox. Using each checkbox's own label text as the tooltip is a reasonable starting point; this pattern is untested on the component.

for c in self.getComponents():
    if isinstance(c, PenPanel):
        for cb in c.getCheckBoxes():
            cb.setToolTipText(cb.getText())

If tooltips vanish after a pen dataset change, the panel is rebuilding its checkboxes (see createGUI). In that case re-apply the tooltips at every configureChart call, or drop the internal panel and use the fallback below.

Fallback: external checkboxes bound to the Tag Pens dataset

When script access to internals is unacceptable, build the pen selector from ordinary components. Add cell update bindings on the Tag Pens dataset so other components can hide, show, enable, or disable pens. A separate checkbox group placed wherever the window layout needs it is bound to the pen dataset's visible column, one checkbox per pen row. This gives full control over position, orientation, and tooltips using standard component properties. The built-in strip remains unless you also remove it in configureChart (call self.remove(c) on the PenPanel without re-adding it; untested). The tradeoff is a checkbox count that must be kept in step with the pen count.

Verification of layout after the script runs

Quantity Expected after change Where to read it
PenPanel position Matches the new edge (for bottom: y equal to the trend panel height) c.getBounds() printed in configureChart
Trend panel width or height Recovers the space the strip vacated Print the first child's getSize()
Child count of the chart Still 2 len(self.getComponents()); more than 2 means the panel was added twice
Behavior after pen dataset edit Layout and tooltips persist Change the pen list at runtime and observe
Behavior after window reopen Same as first open Close and reopen the window in the client

Recurring pitfalls with Easy Chart scripting

  • Skipping validate() leaves the panel in the old position until something else forces a layout pass.
  • Setting a layout on PenPanel instead of on the viewport view produces no visible change.
  • Inspecting the PenPanel class instead of the live instance gives a member list without the runtime state you need.
  • The comment block left as pass in a scroll-pane branch modifies nothing. Add the layout call there.
  • Script edits that reach into Swing internals depend on class names under com.inductiveautomation.factorypmi. Retest after every Ignition upgrade.

Can I move the Easy Chart pen control panel with a property?

No. The component has no position property; move it by removing the PenPanel child in configureChart and re-adding it with a different BorderLayout constraint, then calling self.validate().

Does a checkbox group bound to the Tag Pens dataset replace the built-in pen panel?

It replaces its function, not its presence. Bind each external checkbox to the pen dataset's visible column through cell update bindings, and remove the built-in PenPanel in configureChart if you do not want both.

Can I get a supported way to reposition the pen panel or set pen checkbox tooltips?

The scripted approach reaches into internal Swing classes, so verify it against your Ignition version and expect it to need retesting after upgrades. If the layout resets or the script errors on your version, stop changing internals and open a case with Inductive Automation technical support, quoting the version and the configureChart script you ran.

Back to blog