I've created a class to help resize Swing components while maintaining their aspect ratio within a container.
The class works by creating an instance and adding a container's components to it, then the SwingResizer's resizeComponents()
method can be invoked whenever the container's size is changed.
At present the class only accepts a few Swing components.
- Please critique this class' design and usability.
- Is there a simpler solution to this already that I missed? What is the standard solution?
Any other feedback welcome!
/*
* A class for resizing Swing components within a container
* to maintain aspect ratio with the container.
*/
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* @author Patrick Wallace
*/
public class SwingResizer {
/**
* Map holding each component's name as key, and the component's
* size requirements as value.
*/
private Map<String,float[]> componentResizeMap;
private Collection<JButton> buttonList;
private Collection<JLabel> labelList;
private Collection<JTextField> textList;
private Collection<JPanel> panelList;
private Collection<JLayeredPane> lPaneList;
public SwingResizer()
{
componentResizeMap = new HashMap<>();
buttonList = new HashSet<>();
labelList = new HashSet<>();
textList = new HashSet<>();
panelList = new HashSet<>();
lPaneList = new HashSet<>();
}
/**
* Returns a scale value of a container size's axis value against
* it's contained
* component's axis value. For example, if a container size's x-value
* was 100, and it's component's x-value was 50, a scale value of 2
* would be returned.
*
* @param compVec - Component vector, ie an axis value
* @param contSize - a Container size axis value
* @return - scale value
*/
private float convertVectorToScale(int compVec, int contSize)
{
float result = (float) contSize/compVec;
return result;
}
/**
* Adds a JButton's name and size requirement values to a Mapped collection.
*
* @param comp - a Swing component
* @param x - a Swing component's location x-axis value
* @param y - a Swing component's location y-axis value
* @param xCompSize - a Swing component's size x-axis value
* @param yCompSize - a Swing component's size y-axis value
* @param xContSize - a Swing components's container size's x-value
* @param yContSize - a Swing components's container size's y-value
*/
public void addJButton(JButton comp,int x,int y,int xCompSize,
int yCompSize,int xContSize, int yContSize)
{
String name = comp.getName();
System.out.println(comp);
float[] scales = new float[]{convertVectorToScale(x,xContSize),
convertVectorToScale(y,yContSize),
convertVectorToScale(xCompSize,xContSize),
convertVectorToScale(yCompSize,yContSize)};
buttonList.add(comp);
float[] duplicateKey = componentResizeMap.put(name, scales);
if (duplicateKey != null)
{
System.out.println("Error - Duplicate component name");
}
}
/**
* Adds a JLabels's name and size requirement values to a Mapped collection.
*
* @param comp - a Swing component
* @param x - a Swing component's location x-axis value
* @param y - a Swing component's location y-axis value
* @param xCompSize - a Swing component's size x-axis value
* @param yCompSize - a Swing component's size y-axis value
* @param xContSize - a Swing components's container size's x-value
* @param yContSize - a Swing components's container size's y-value
*/
public void addJLabel(JLabel comp,int x,int y,int xCompSize,int yCompSize,
int xContSize, int yContSize)
{
String name = comp.getName();
float[] scales = new float[]{convertVectorToScale(x,xContSize),
convertVectorToScale(y,yContSize),
convertVectorToScale(xCompSize,xContSize),
convertVectorToScale(yCompSize,yContSize)};
labelList.add(comp);
float[] duplicateKey = componentResizeMap.put(name, scales);
if (duplicateKey != null)
{
System.out.println("Error - Duplicate component name");
}
}
/**
* Adds a JTextField's name and size requirement values to a
* Mapped collection.
*
* @param comp - a Swing component
* @param x - a Swing component's location x-axis value
* @param y - a Swing component's location y-axis value
* @param xCompSize - a Swing component's size x-axis value
* @param yCompSize - a Swing component's size y-axis value
* @param xContSize - a Swing components's container size's x-value
* @param yContSize - a Swing components's container size's y-value
*/
public void addJTextField(JTextField comp,int x,int y,int xCompSize,
int yCompSize, int xContSize, int yContSize)
{
String name = comp.getName();
float[] scales = new float[]{convertVectorToScale(x,xContSize),
convertVectorToScale(y,yContSize),
convertVectorToScale(xCompSize,xContSize),
convertVectorToScale(yCompSize,yContSize)};
textList.add(comp);
float[] duplicateKey = componentResizeMap.put(name, scales);
if (duplicateKey != null)
{
System.out.println("Error - Duplicate component name");
}
}
/**
* Adds a JPanel's name and size requirement values to a Mapped collection.
*
* @param comp - a Swing component
* @param x - a Swing component's location x-axis value
* @param y - a Swing component's location y-axis value
* @param xCompSize - a Swing component's size x-axis value
* @param yCompSize - a Swing component's size y-axis value
* @param xContSize - a Swing components's container size's x-value
* @param yContSize - a Swing components's container size's y-value
*/
public void addJPanel(JPanel comp,int x,int y,int xCompSize,int yCompSize,
int xContSize, int yContSize)
{
String name = comp.getName();
float[] scales = new float[]{convertVectorToScale(x,xContSize),
convertVectorToScale(y,yContSize),
convertVectorToScale(xCompSize,xContSize),
convertVectorToScale(yCompSize,yContSize)};
panelList.add(comp);
float[] duplicateKey = componentResizeMap.put(name, scales);
if (duplicateKey != null)
{
System.out.println("Error - Duplicate component name");
}
}
/**
* Adds a JLayeredPane's name and size requirement values to a
* Mapped collection.
*
*@param comp - a Swing component
* @param x - a Swing component's location x-axis value
* @param y - a Swing component's location y-axis value
* @param xCompSize - a Swing component's size x-axis value
* @param yCompSize - a Swing component's size y-axis value
* @param xContSize - a Swing components's container size's x-value
* @param yContSize - a Swing components's container size's y-value
*/
public void addJLayeredPane(JLayeredPane comp,int x,int y,int xCompSize,
int yCompSize, int xContSize, int yContSize)
{
String name = comp.getName();
float[] scales = new float[]{convertVectorToScale(x,xContSize),
convertVectorToScale(y,yContSize),
convertVectorToScale(xCompSize,xContSize),
convertVectorToScale(yCompSize,yContSize)};
lPaneList.add(comp);
float[] duplicateKey = componentResizeMap.put(name, scales);
if (duplicateKey != null)
{
System.out.println("Error - Duplicate component name");
}
}
/**
* Resizes all components named in the component map to maintain
* aspect ration with the container's current size.
*
* @param x - container's current size, x-axis value
* @param y - container's current size, y-axis value
*/
public void resizeComponents(int x,int y)
{
try
{
SwingUtilities.invokeLater(new Runnable(){
public void run()
{
for (JButton button : buttonList)
{
try
{
float[] aspectRatios = componentResizeMap.get(button.getName());
button.setBounds(Math.round(x/aspectRatios[0]),
Math.round(y/aspectRatios[1]),
Math.round(x/aspectRatios[2]),
Math.round(y/aspectRatios[3]));
}
catch (Exception e)
{
System.out.println("Error - " + e.getMessage());
}
}
for (JLabel label : labelList)
{
try
{
float[] aspectRatios = componentResizeMap.get(label.getName());
label.setBounds(Math.round(x/aspectRatios[0]),
Math.round(y/aspectRatios[1]),
Math.round(x/aspectRatios[2]),
Math.round(y/aspectRatios[3]));
}
catch (Exception e)
{
System.out.println("Error - " + e.getMessage());
}
}
for (JTextField tField : textList)
{
try
{
float[] aspectRatios = componentResizeMap.get(tField.getName());
tField.setBounds(Math.round(x/aspectRatios[0]),
Math.round(y/aspectRatios[1]),
Math.round(x/aspectRatios[2]),
Math.round(y/aspectRatios[3]));
}
catch (Exception e)
{
System.out.println("Error - " + e.getMessage());
}
}
for (JPanel panel : panelList)
{
try
{
float[] aspectRatios = componentResizeMap.get(panel.getName());
panel.setBounds(Math.round(x/aspectRatios[0]),
Math.round(y/aspectRatios[1]),
Math.round(x/aspectRatios[2]),
Math.round(y/aspectRatios[3]));
}
catch (Exception e)
{
System.out.println("Error - " + e.getMessage());
}
}
for (JLayeredPane lPane : lPaneList)
{
try
{
float[] aspectRatios = componentResizeMap.get(lPane.getName());
lPane.setBounds(Math.round(x/aspectRatios[0]),
Math.round(y/aspectRatios[1]),
Math.round(x/aspectRatios[2]),
Math.round(y/aspectRatios[3]));
}
catch (Exception e)
{
System.out.println("Error - " + e.getMessage());
}
}
}
});
}
catch (Exception e)
{
System.out.println("Error - " + e.getMessage());
}
}
}
LayoutManager
based class. You would then need to determine the "base" (or normal) ratio, maybe based on thepreferredSize
of the component, then from this you could calculate the required size need to facilitate the requirements of the actual physical layout (as the ratio would only be a small part). If you're after a review, it would better to post the code on codereview instead \$\endgroup\$LayoutManager
that respects the sizes of the child components and supports auto resizing, you want GroupLayout \$\endgroup\$