После многих исследований я понимаю, что с Swing нет хорошего способа сделать это. Проблема связана не только с MigLayout, но и с макетами типа ScrollPaneLayout, которая предполагает, что предпочтительная высота останется неизменной после другой эффективной ширины (которая не является предпочтительной шириной).
Есть два варианта:
1) В настоящее время я делаю свою собственную реализацию MigLayout с компонентом ограничением соотношения сторон. Вы можете скачать его здесь:
https://github.com/lqbweb/miglayout-aspect
До сих пор, она работает с сокращением и растет X в простом случае сетки с 1 компонентной/сотой. Я все еще должен тестировать с охватом, течением в ячейке и стыковкой ..... Я буду держать этот репозиторий обновленным, и любая помощь приветствуется.
Как вы, вероятно, используете его как представление на ViewPort, вам придется немного взломать getPreferredSize представления, если вы используете его с Scrollable.getScrollableTracksViewportWidth(), возвращающим true, поэтому он не возвращает реальную предпочтительную высоту, но ту, которая соответствует ширине. В моем коде есть геттер для сетки, а сетка имеет функцию возврата предпочтительной высоты для заданной ширины.
2) Сохраняя текущую реализацию MigLayout нетронутой (4.2 на момент ответа), я нашел только один способ добиться этого: добавив обратный вызов макета и внедряя метод getSize() с чем-то вроде этого:
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();
}
}
}
});
, а затем, добавляя компонент, как:
CC constraints=new CC();
constraints.shrinkX(100);
constraints.minWidth("1");
constraints.minHeight("1");
add(tmpImg, constraints);
Но вы должны добавить и сохранить обновленный раскладку ограничение (LC), чтобы установить вручную предпочтительный размер макета, так как после обратный вызов становится предвзятым.
Кстати, последний код может быть 'add (tmpImage, new CC(). ShrinkX (100) .minWidth (" 1 "). MinHeight (" 1 "))' если вы предпочитаете. – wchargin
ok, старый код с функцией «getSize()» имел недостаток. Он считает, что ширина не изменится в течение этого цикла макета. Итак, мне пришлось реализовать «currentBounds (ComponentWrapper)», который выполняется в самом конце цикла компоновки, и он проверяет, что аспектный ранг по-прежнему прав. Это могло быть проще и чище, если MigLayout проходил в правильном обратном вызове эффективные размеры «horSizes» и «verSizes» с возвратом «doAgain». Ответ отредактирован, чтобы показать, как у меня это сейчас .... – lqbweb
ОК, я не отредактировал свой ответ, наконец, потому что есть еще одна проблема. Боюсь, для этого нет чистого решения. Когда я верну свой BoundSize в getSize, он будет использоваться позже, чтобы неправильно рассчитать предпочтительный размер Grid. Я попытаюсь реализовать это на моей собственной реализации MigLayout, так как официальная поддержка, которую я понимаю, довольно бедна. – lqbweb