I have a button in a template, and I want to resize it to a perfect square at runtime regardless of how the template has been sized.
To develop this, I have a Multi-State button inside a test template, and a test button that is in the same container as the template:
My desired result is this: button @ (x = 100, y = 100, width = 100, height = 100)
The obvious approach is this:
# Retrieve the button from the template button = event.source.parent.getComponent('testTemplate').getComponent(0).getComponent(0) # Transform the button in the normal and natural way using system.gui.transform system.gui.transform(button, newX = 100, newY = 100, newWidth = 100, newHeight = 100)
...but this produces a radically incorrect result where the y and height dimensions seem to be exponentially larger than they should be, and the height dimension walks about 4 pixels every time the transform is applied.
It should also be noted that switching this to a relative coordinate space has no perceivable effect on the transform
The x dimension is the ONLY exception in that it always transforms in the expected way.
# Behaves as expected, but is obviously short three dimensions button = system.gui.transform(button, newX = 100)
Trying to set the dimensions directly on the component actually works for the height and the width, but a second later, the component snaps back to its original size:
from java.awt import Dimension button = event.source.parent.getComponent('testTemplate').getComponent(0).getComponent(0) button.setMinimumSize(Dimension(100, 100)) button.setMaximumSize(Dimension(100, 100)) button.setPreferredSize(Dimension(100, 100)) button.setSize(Dimension(100, 100))
Believing this is a layout issue, I looked the layout up in the documentation, and it says this about the constraints:
Vision Layout constraints object, used with FPMILayout to hold the "layout constraints" (LC) of a component. This is a bit of a mess because of backwards compatibility, here's the explanation
Conveniently, the functions
FPMILayout.getBounds(javax.swing.JComponent)make neat work of this confusion. these methods (and their setters) should be the only way that bounds get accessed.
Trying to directly adjust the size with FPMILayout actually works for BOTH size and location, but a second later, the component snaps back to its original position as if nothing had been changed:
from com.inductiveautomation.factorypmi.application.components.util import FPMILayout from java.awt.geom import Rectangle2D button = event.source.parent.getComponent('testTemplate').getComponent(0).getComponent(0) layout = FPMILayout.getOffsettingParent(button).layout layout.setBounds(button, Rectangle2D.Double(100, 100, 100, 100))
preferredBounds has a permanent effect, but just like the transform, the result is way off. However, I discovered that if I created a ratio between the widths and heights of the
preferredBounds to the actual bounds, and then used that to transform the component, I got the size and position I wanted:
from com.inductiveautomation.factorypmi.application.components.util import FPMILayout #Retrieve the button button = event.source.parent.getComponent('testTemplate').getComponent(0).getComponent(0) # Get the FPMILayout layout = FPMILayout.getOffsettingParent(button).layout # Make sure there is no possiblility of dividing by zero widthDivisor, heightDivisor = max(1, layout.getBounds(button).width), max(1, layout.getBounds(button).height) # Define ratios to get sizes that are relative to the original template widthRatio = float(layout.getPreferredBounds(button).width) / widthDivisor heightRatio = float(layout.getPreferredBounds(button).height) / heightDivisor # Define the desired dimensions desiredX = 100 desiredY = 100 desiredWidth = 100 desiredHeight = 100 # Calculate the dimensions that will be needed to get the transform to work using ratios newX = desiredX newY = desiredY * heightRatio newWidth = desiredWidth * widthRatio newHeight = desiredHeight * heightRatio # Execute the transform system.gui.transform(button, newX, newY, newWidth, newHeight)
However, I assume the button text is still rendering at its original coordinates because the word 'Off' is no longer visible:
Edit: It's possible that I messed something up when I was probing the component. After restarting the designer, the label renders as expected.
At this point, I'm assuming that I've somehow wandered off course or lost track of some key concept, so before I travel any further into left field, I have to ask: does anybody know a better way to go about this?