CardLayout вычисляет неправильный минимальный размерJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 CardLayout вычисляет неправильный минимальный размер

Сообщение Anonymous »

Есть проблема (реальная, высокоприоритетная производственная проблема): CardLayout по какой-то причине вычисляет минимальную ширину независимо от того, какой компонент отображается. См. java.awt.CardLayout#minimumLayoutSize.
Шаги для воспроизведения:
  • Разверните окно.
  • Переключите левый компонент на розовый (он уже).
  • Восстановите окно.
Бам — разделитель такой расположен в странном месте, как будто показан более широкий компонент.
Этот графический интерфейс имитирует фактическое расположение нашего приложения. Он имеет разделенную панель, его левый компонент динамически изменяется с помощью CardLayout (который в данном случае кажется наиболее подходящим макетом). Контейнер состоит из двух компонентов, размеры которых сильно различаются. Расположение разделителя должно отражать это (хотя оно все еще включено).
Как обойти эту проблему?
MRE:

Код: Выделить всё

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;

public class SplitPaneDemo {

static JSplitPane splitPane;
static JPanel leftPanel;
static CardLayout leftLayout;

public static void main(String[] args) {
Container mainPanel = createMainPanel();
JFrame frame = new JFrame("Split Pane Demo");
frame.setContentPane(mainPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}

private static Container createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(createButtonPane(), BorderLayout.NORTH);
panel.add(createSplitPane());
return panel;
}

private static Component createButtonPane() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
panel.add(createButton());
return panel;
}

private static Component createButton() {
JButton button = new JButton("Swap left component");
button.addActionListener(SplitPaneDemo::swapLeftComponent);
return button;
}

private static void swapLeftComponent(ActionEvent e) {
leftLayout.next(leftPanel);
splitPane.setDividerLocation(getShowingPanel().getPreferredSize().width);
}

private static Component getShowingPanel() {
return Arrays.stream(leftPanel.getComponents())
.filter(Component::isShowing)
.findFirst()
.orElseThrow(null);
}

private static Container createSplitPane() {
splitPane = new JSplitPane();
splitPane.setLeftComponent(createLeftPanel());
splitPane.setRightComponent(createGreenPanel());
return splitPane;
}

private static Component createLeftPanel() {
leftPanel = new JPanel(leftLayout = new CardLayout());
leftPanel.setName("leftPanel");
leftPanel.add(createRedPanel(), "red");
leftPanel.add(createPinkPanel(), "pink");
return leftPanel;
}

private static Component createRedPanel() { // wider
Component panel = new JPanel();
Dimension size = new Dimension(500, 500);
panel.setPreferredSize(size);
panel.setMinimumSize(size); // crucial
panel.setBackground(Color.RED);
return panel;
}

private static Component createPinkPanel() { // narrower
Component panel = new JPanel();
panel.setPreferredSize(new Dimension(200, 500));
panel.setBackground(Color.PINK);
return panel;
}

private static Component createGreenPanel() {
Component panel = new JPanel();
panel.setPreferredSize(new Dimension(500, 500));
panel.setBackground(Color.GREEN);
return panel;
}
}
Изображение
Изображение

Переопределение работает, но не ощущается верно.
Кроме того, его нелегко применить в реальном приложении, поскольку мы используем формы графического интерфейса Swing UI Designer (нам не следует этого делать, но мы это делаем).

Код: Выделить всё

        leftPanel = new JPanel(leftLayout = new CardLayout() {
@Override // everything's the same...
public Dimension minimumLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
int ncomponents = parent.getComponentCount();
int w = 0;
int h = 0;

for (int i = 0 ; i < ncomponents ;  i++) {
Component comp = parent.getComponent(i);
if (!comp.isVisible()) continue; // ...except for this line
Dimension d = comp.getMinimumSize();
if (d.width > w) {
w = d.width;
}
if (d.height > h) {
h = d.height;
}
}
return new Dimension(insets.left + insets.right + w + getHgap()*2,
insets.top + insets.bottom + h + getVgap()*2);
}
}
});
Java 8.


Подробнее здесь: https://stackoverflow.com/questions/799 ... nimum-size
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»