То, что вы пытаетесь выполнить, кажется удивительно трудным, потому что вы должны полагаться на метод расчета Swing размера ваших различных компонентов, а затем получить правильные значения для выполнения расчетов по ним.Хотя это выглядит довольно тривиально в зависимости от доступных методов API, взгляд на исходный код показывает другую историю.Это дополнительно усложняется тем фактом, что некоторые значения рассчитываются правильно только тогда, когда компонент фактически отображается, а это означает, что значения, которые вы пытаетесь получить ранее, не отражают то, что вы видите на экране (как вы узнали).
С другой стороны, кажется, что можно сделать то, к чему ты стремишься.Имейте в виду, однако, что при добавлении элементов в BoxLayout
ожидаемое поведение заключается в том, что все пространство контейнера, которому вы назначили менеджер компоновки, используется для позиционирования дочерних компонентов.Это означает, что при добавлении JTextPane
объектов к вашему JPanel
они будут растягиваться, чтобы их суммарная высота занимала все указанные вами 600 пикселей.В результате вам нужно определиться, когда вы превысили доступную высоту, немного по-другому, поскольку визуализированная высота каждого компонента может изменяться в процессе.
После того, как вы немного поиграете с этим и проклянетесьКачаясь неоднократно, я хотя и придумал решение, используя getBounds()
(который BoxLayout
использует при делегировании для его LayoutParameters
для определения высоты компонента), но метод, который я оказался не очень надежным,Я собираюсь поиграть с этим, так что, надеюсь, я придумаю какой-нибудь пригодный для использования код, или кто-то еще найдет решение, которое я пропустил.
Редактировать: Для полноты вот пример кода, который вызывает doLayout()
для вычисления необходимых размеров перед показом формы (все еще с недостатками BoxLayout
).Он не будет работать на моем JRE 1.5 из-за некоторых ArrayIndexOutOfBoundsException
в SizeRequirements
, но эта ошибка, кажется, была исправлена в 1.6.В 1.5, если ваш список компонентов не был слишком большим, вы могли бы добавить их все, вызвать doLayout()
после цикла (как кажется, это работает в 1.5 по любой причине), а затем просто просмотреть массив, возвращенный getComponents()
удаление всего, после того, как максимальная высота была превышена.
В качестве последнего замечания, я лично поклонник использования MigLayout для более сложных макетов, так как я нахожу его механизм позиционирования и стилизациинемного легче работать, чем текущие встроенные менеджеры по расположению.Не слишком уместно здесь, но стоит упомянуть в любом случае.
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.StyledEditorKit;
public class TestFrame extends JFrame {
private static final int CONTENT_HEIGHT = 600;
private static final int CONTENT_WIDTH = 300;
public static void main(String[] args) {
TestFrame frame = new TestFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public TestFrame() {
super("Test Frame");
this.addComponents();
this.pack();
}
private void addComponents() {
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
panel.setBounds(new Rectangle(CONTENT_WIDTH, CONTENT_HEIGHT));
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
String text = "This is a long String that represents the length of" +
" stings in my application. This will vary in the real" +
" application.<ul><li>It uses html</li><li>not just</li>" +
"<li>plain text</li></ul>I'd like only as many as will fit" +
" in the fame to be added.\n";
this.setContentPane(panel);
int height = 0;
while(height < CONTENT_HEIGHT) {
JTextPane textPane = createTextPane(text);
panel.add(textPane);
panel.doLayout();
// The height on the preferred size has been set to reflect
// the rendered size after calling doLayout()
height += textPane.getPreferredSize().getHeight();
// If we've exceeded the height, backtrack and remove the
// last text pane that we added
if (height > CONTENT_HEIGHT) {
panel.remove(textPane);
}
}
}
private JTextPane createTextPane(String text) {
JTextPane textPane = new JTextPane();
textPane.setEditorKit(new StyledEditorKit());
textPane.setEditable(false);
textPane.setOpaque(false);
textPane.setContentType("text/html");
textPane.setText(text);
return textPane;
}
}