问题
I'm arranging images in a grid with MigLayout. I could get the width to take the whole space available in the column, but then I want the height to grow accordingly so the proportion of the image still fixed.
What is the best approach for this? Could I do that with an expression in the constraint or I have to override the getPreferredSize()?
Thanks!
回答1:
After a lot of researching, I realize that there is no nice way of doing this with Swing. The problem is not only coming from MigLayout but also from layouts like ScrollPaneLayout, which assumes that the preferred height will remain the same after a different effective width (which is not the preferred width).
There are two options:
1) Currently, I'm doing my own implementation of MigLayout with an aspect ratio component constraint. You can download it from here:
https://github.com/lqbweb/miglayout-aspect
So far, it works with shrinking and growing X in a simple grid case with 1 component / cell. I still have to test with spanning, flowing in the cell and docking..... I'll keep that repository updated and any help is well welcome.
As you will probably use it as a view on a ViewPort, you will have to hack a bit the getPreferredSize of the view if you use it with the Scrollable.getScrollableTracksViewportWidth() returning true, so it doesn't return the real preferred height but the one that matches the width. In my code there is a getter for the grid, and the grid has a function to return a preferred height for a given width.
2) Keeping the current implementation of MigLayout untouched (4.2 at the time of this answer), I only found one way to achieve this: by adding a callback to the layout and implementing getSize() method with something like this:
migLayout.addLayoutCallback(new LayoutCallback() {
/**
* This is run before the layout starts laying out
*/
@Override
public BoundSize[] getSize(ComponentWrapper comp) {
if(comp.getComponent() instanceof DCMImageWrapper) {
DCMImageWrapper img=(DCMImageWrapper) comp.getComponent(); //this is the BufferedImage embedded in a JLabel
int calculatedHeight=img.getHeightFor(comp.getWidth());
UnitValue maxHeight=new UnitValue(calculatedHeight);
BoundSize height=new BoundSize(maxHeight, maxHeight, maxHeight, null);
return new BoundSize[]{null, height};
} else {
return null;
}
}
private double getCurrentAspect(ComponentWrapper comp) {
if(comp.getWidth()==0 || comp.getHeight()==0) return 0;
double currentAspect=comp.getWidth()/(double)comp.getHeight();
return currentAspect;
}
/**
* Check if the aspect still valid
*/
@Override
public void correctBounds(ComponentWrapper comp) {
if(comp.getComponent() instanceof DCMImageWrapper) {
DCMImageWrapper img=(DCMImageWrapper) comp.getComponent();
double currentAspect=getCurrentAspect(comp);
double origAspect=img.getDCMImage().getAspect();
double currentError=Math.abs(origAspect-currentAspect);
if(currentError > img.getDCMImage().getAspectError()) {
//recalculate layout
revalidate();
}
}
}
});
and then, adding the component like:
CC constraints=new CC();
constraints.shrinkX(100);
constraints.minWidth("1");
constraints.minHeight("1");
add(tmpImg, constraints);
But, you will have to add and keep updated a layout constraint (LC) to set manually the preferred size of the layout, as after the callback it gets biased.
来源:https://stackoverflow.com/questions/16902256/miglayout-how-to-resize-the-height-proportionally-to-the-width-keeping-the-asp