JFrame で validate() をオーバーライドして、ネストされた 2 つの JPanel のサイズを手動で制御できるようにしました (これらは、コンテンツを画面にスクロールする際に使用され、境界の外にコンポーネントを配置できるレイアウト マネージャーはありません)。親コンテナの)。これは、ウィンドウをドラッグしてサイズを変更するときにうまく機能しますが、最大化ボタンをクリックすると、validate() が呼び出され、setPreferredSize() が呼び出されますが、パネルのサイズは更新されません。XP で見られる問題、OSX では見られない問題。
public void validate() {
super.validate();
LOGGER.debug("Validate called on Frame. Resizing panel");
if (inited == true) {
Dimension size = panelLeft.getSize();
int referenceHeight = size.height;
LOGGER.info("referenceHeight is " + referenceHeight);
size = lower.getSize();
size.height = referenceHeight;
lower.setPreferredSize(size);
lower.setMinimumSize(size);
size.height = size.height * 2;
movingPanel.setPreferredSize(size);
movingPanel.setMinimumSize(size);
LOGGER.info("sizes now: panel: " + lower.getSize().height + ", scrollpane: "
+ movingPanel.getSize().height);
if (panelSlideController != null) {
panelSlideController.redraw();
LOGGER.debug("redrawing panel slide controller");
}
}
}
panelLeft は、レイアウト マネージャによってフレームの高さいっぱいになるように自動サイズ変更されるパネルです。そのため、その高さは参考として使用されます。
関連するパネルは次のように配置されています。
----------------------------------
|scrollPane |
| -------------------------------- |
||movingPanel ||
|| ------------------------------ ||
|||upper |||
||| |||
||| |||
||| |||
|| ------------------------------ ||
|| ------------------------------ ||
|||lower |||
||| |||
||| |||
||| |||
|| ------------------------------ ||
| -------------------------------- |
----------------------------------
ユーザーには、このレイアウトの上半分のみが表示されます。movingPanel JPanel は JScrollPane のビューポートにあります。目標は、上部パネルが表示可能な垂直方向のスペースをすべて占有するようにすることです。これは、囲んでいる JFrame とほぼ同じ高さです。下のパネルはスクロールする準備ができており、上のパネルと同じ高さに保たれています。lower.height == panelLeft.height と movingPanel.height == panelLeft.heightx2 を維持することで、movingPanel の半分が表示され、上端がフレームの下部にあることを意味します。
私が言ったように、うまくいきます。ウィンドウをドラッグするときの出力例は次のとおりです。
2013-06-20 23:15:41,298 [WT-EventQueue-0] DEBUG s.billing.ui.Form - Validate called on Frame. Resizing panel
2013-06-20 23:15:41,298 [WT-EventQueue-0] INFO s.billing.ui.Form - newheight is 617
2013-06-20 23:15:41,298 [WT-EventQueue-0] INFO s.billing.ui.Form - sizes now: panel: 607, scrollpane: 1214
2013-06-20 23:15:41,538 [WT-EventQueue-0] DEBUG s.billing.ui.Form - Validate called on Frame. Resizing panel
2013-06-20 23:15:41,538 [WT-EventQueue-0] INFO s.billing.ui.Form - newheight is 640
2013-06-20 23:15:41,538 [WT-EventQueue-0] INFO s.billing.ui.Form - sizes now: panel: 636, scrollpane: 1272
ウィンドウを最大化すると、出力は次のようになります。
2013-06-20 22:08:21,234 [WT-EventQueue-0] DEBUG s.billing.ui.Form - Validate called on Frame. Resizing panel
2013-06-20 22:08:21,234 [WT-EventQueue-0] INFO s.billing.ui.Form - newheight is 783
2013-06-20 22:08:21,234 [WT-EventQueue-0] INFO s.billing.ui.Form - sizes now: panel: 543, scrollpane: 1086
そこに setMinimumSize を追加して説得力を高めようとしましたが、役に立ちませんでした。
どんな考えでも大歓迎です
編集:SSCCEを追加
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.Timer;
import javax.swing.UIManager;
class Frame extends JFrame {
private JPanel panelLeft;
private JScrollPane scrollPane;
private JPanel movingPanel;
private JPanel upper;
private JPanel lower;
private boolean inited;
private JLabel labelUpper;
private JLabel labelLower;
private JButton scrollBtn;
private Frame.PanelSlideController panelSlideController;
private JButton resizeBtn;
private boolean lowerShowing = false;
public Frame() {
getContentPane().setLayout(new BorderLayout());
panelLeft = new JPanel();
panelLeft.setBackground(Color.CYAN);
panelLeft.setPreferredSize(new Dimension(300, 400));
getContentPane().add(panelLeft, BorderLayout.WEST);
labelUpper = new JLabel("upper");
panelLeft.add(labelUpper);
labelLower = new JLabel("lower");
panelLeft.add(labelLower);
resizeBtn = new JButton("resize");
resizeBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doResize();
}
});
panelLeft.add(resizeBtn);
scrollBtn = new JButton("Scroll");
scrollBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doScroll();
}
});
panelLeft.add(scrollBtn);
scrollPane = new JScrollPane();
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
movingPanel = new JPanel(new GridLayout(2, 1));
movingPanel.setOpaque(false);
movingPanel.setPreferredSize(new Dimension(300, 400));
upper = new JPanel();
upper.setBackground(Color.YELLOW);
movingPanel.add(upper);
lower = new JPanel();
lower.setBackground(Color.RED);
movingPanel.add(lower);
scrollPane.setViewportView(movingPanel);
getContentPane().add(scrollPane, BorderLayout.EAST);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
inited = true;
}
/**
* This is a manual step instead of overriding validate()
*/
protected void doResize() {
// Get the height we want
int referenceHeight = panelLeft.getSize().height;
// Update the height of the lower panel to equal this
Dimension size = lower.getSize();
size.height = referenceHeight;
lower.setPreferredSize(size);
lower.setMinimumSize(size);
// Update the height of the surrounding panel
size = scrollPane.getSize();
size.height = referenceHeight * 2;
movingPanel.setPreferredSize(size);
movingPanel.setMinimumSize(size);
if (panelSlideController != null) {
panelSlideController.redraw();
System.out.println("redrawing panel slide controller");
}
upper.invalidate();
lower.invalidate();
scrollPane.revalidate();
}
protected void doScroll() {
panelSlideController = new PanelSlideController(scrollPane, 20);
int scrollDirection = lowerShowing ? -1 : 1;
panelSlideController.scrollY(panelLeft.getHeight() * scrollDirection);
lowerShowing = !lowerShowing;
}
@Override
public void validate() {
super.validate();
System.out.println("Validating");
if (inited) {
labelUpper.setText("upper: " + upper.getSize().height);
labelLower.setText("lower: " + lower.getSize().height);
}
}
class PanelSlideController implements ActionListener {
private final JScrollPane scrollPane;
private final int speed;
private Timer timer;
private int endPos;
private boolean scrollingPositive;
public PanelSlideController(JScrollPane scrollPane, int speed) {
this.scrollPane = scrollPane;
this.speed = speed;
}
public void scrollY(int scrollDistance) {
endPos = scrollPane.getViewport().getViewPosition().y + scrollDistance;
scrollingPositive = scrollDistance > 0;
timer = new Timer(speed, this);
timer.start();
}
public void redraw() {
JViewport viewport = scrollPane.getViewport();
Point position = viewport.getViewPosition();
if (scrollingPositive) {
position.y = endPos;
}
else {
position.y = 0;
}
viewport.setViewPosition(position);
}
@Override
public void actionPerformed(ActionEvent e) {
JViewport viewport = scrollPane.getViewport();
Point position = viewport.getViewPosition();
int offset = scrollingPositive ? 10 : -10;
position.y += offset;
viewport.setViewPosition(position);
if ((scrollingPositive && position.y >= endPos)
|| (!scrollingPositive && (position.y <= endPos || position.y <= 0))) {
timer.stop();
}
}
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Frame().setVisible(true);
}
});
}
}
そうですね、上記は実行可能です。panelLeft (シアン) が高さの基準として使用されます。コードを validate() から移動し、代わりにサイズ変更ボタンをクリックして実行します。
したがって、スクロールがクリックされるまで赤いパネル (下)が表示されないようにすることができます。クリックすると、黄色が上にスクロールし、赤いスクロールが表示されます。そしてまた反対方向に戻ります。これを行うには、黄色のパネルが垂直方向の高さすべてを占めている必要があります。レイアウト マネージャーでこれを行うことができれば、大丈夫です。
ここで使用されている名前を反映するために、元のスニペットと「図」を更新しました。
ありがとう