/ / Scroll JLayer не се държи като превъртен JPanel, който трябва да замести - java, swing, jscrollpane, jlayer

Преглеждаше JLayer не се държи като превъртана JPanel, която трябва да замени - java, swing, jscrollpane, jlayer

Бих искал да украся JPanel с JLayer, ноне успявам да разбера защо по този начин обърквам този панел да бъде поставен в JScrollPane. Предполага се, че украсеният компонент действа като спад в замяната, но в този случай изглежда не работи.

Следващият код създава два еквивалентни JPanelsи ги поставя в друг панел с CardLayout (така че можете да превключвате между тях с помощта на бутоните). Единствената разлика е, че в един случай панелът е декориран с JLayer.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.LayerUI;

public class JLayerScroll extends JFrame {

public JLayerScroll() {
setTitle("Jumpy border");
setLayout(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);

createGui();

setSize(400, 200);
setLocationRelativeTo(null);
}

private void createGui() {
JPanel mainPanel = new JPanel(new CardLayout());
// two panels ("label panels"), first one decorated, second one not
mainPanel.add(createSingleScrolledComponent(new JLayer<JPanel>(createLabelPanel(), new LayerUI<JPanel>())), WITH_JLAYER);
mainPanel.add(createSingleScrolledComponent(createLabelPanel()), WITHOUT_JLAYER);
add(mainPanel);

createButtons(mainPanel);
}

private JPanel createSingleScrolledComponent(Component component) {
GridBagConstraints gbc;
JScrollPane scroll;

JPanel panel = new JPanel(new GridBagLayout());
scroll = new JScrollPane(component);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0d;
gbc.weighty = 1.0d;
panel.add(scroll, gbc);

return panel;
}

private JPanel createLabelPanel() {
GridBagConstraints gbc;

JPanel panel = new JPanel(new GridBagLayout());

JPanel entry = new JPanel(new GridBagLayout());
entry.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.red));

JLabel label = new JLabel("Some input:");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
entry.add(label, gbc);

JTextField field = new JTextField(20);
field.setMinimumSize(new Dimension(field.getPreferredSize().width, field.getMinimumSize().height));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
entry.add(field, gbc);

gbc = new GridBagConstraints();
gbc.gridx = 2;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0d;
entry.add(Box.createHorizontalGlue(), gbc);

gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0d;
panel.add(entry, gbc);

gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1.0d;
panel.add(Box.createVerticalGlue(), gbc);

return panel;
}

private static final String WITH_JLAYER = "with-jlayer";
private static final String WITHOUT_JLAYER = "no-jlayer";

private void createButtons(final JPanel mainPanel) {
GridBagConstraints gbc;
JButton button;
JPanel actionsPanel = new JPanel(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0d;
actionsPanel.add(Box.createHorizontalGlue(), gbc);
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
button = new JButton("With JLayer");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
CardLayout layout = (CardLayout) mainPanel.getLayout();
layout.show(mainPanel, WITH_JLAYER);
}
});
actionsPanel.add(button, gbc);
gbc.gridx = 2;
gbc.gridy = 0;
button = new JButton("Without JLayer");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
CardLayout layout = (CardLayout) mainPanel.getLayout();
layout.show(mainPanel, WITHOUT_JLAYER);
}
});
actionsPanel.add(button, gbc);
add(actionsPanel, BorderLayout.SOUTH);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JLayerScroll().setVisible(true);
}
});
}

}

Ако обърнете внимание на червената граница в дветеслучаи ще забележите, че в единия случай тя обхваща цялото налично хоризонтално пространство (както се очаква), докато в другия случай се обхваща само около видими компоненти (етикет и текстово поле).

Скачаща граница

Защо това се случва и как да постигна същото поведение, както в недекларирания случай (обхващащ цялото налично хоризонтално пространство)?

Отговори:

1 за отговор № 1

Единствената разлика е, че в един случай панелът е декориран с JLayer.

Разлика между a JPanel и a JLayer е, че JLayer изпълнява Scrollable интерфейс, но a JPanel не.

Най- getScrollableTracksViewportWidth() метод контролира дали компонентът е добавен къмпрозорецът за показване трябва да се показва в предпочитания от него размер или ширината на прозореца. JLayer делегира на JPanel, но тъй като JPanel не прилага интерфейса за превъртане, реализацията на JLayer ще върне „невярно“, което означава, че компонентът трябва да бъде показан в предпочитаната му ширина.

Така че начин да се заобиколи това е да се използва обвивка панел за JLayer:

//scroll = new JScrollPane(component);
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add( component );
scroll = new JScrollPane(wrapper);

Сега компонентът, добавен към прозореца на екрана на scrollpane, е JPanel и в двата случая, така че те трябва да се държат по същия начин.