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
- Open the Easy Chart in the Designer and open the component scripting editor, then select the
configureChartextension function. - Paste the script below. It reproduces the working bottom placement using
BorderLayout.PAGE_END. - Save, then preview or run the window in a client. Confirm the strip moved and the trend area re-expanded.
- To try the right edge, change the constraint to . This is the standard Java
BorderLayoutconstant 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.
- Inside the
PenPanelbranch of the loop, runprint(dir(c))andprint(c.getLayout()). - Loop
c.getComponents()and print each child's type and bounds. Expect aJPaneland aJScrollPane. - For the
JScrollPanechild, printch.getViewport().getView()and itsgetLayout(). That inner container is the candidate for aFlowLayoutor a wrapped grid. - Apply the layout change to that inner container, then call
revalidate()on it andself.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
PenPanelinstead of on the viewport view produces no visible change. - Inspecting the
PenPanelclass instead of the live instance gives a member list without the runtime state you need. - The comment block left as
passin 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.