我真的不知道该怎么做。当用户单击按钮时,我希望有一个面板从当前面板下方“滑出”。然后,当他们再次单击该按钮时,它将滑回。
这是我的意思的一个例子。请注意它看起来像是在左侧窗口的“下方”,以及它如何没有完全(但几乎)延伸到底部和顶部:
这是它没有出现时的图片(背景中的第二个窗口只是第一个图像[上面的那个],因为当我拍摄屏幕截图时浏览器在框架中):
我真的不知道该怎么做。当用户单击按钮时,我希望有一个面板从当前面板下方“滑出”。然后,当他们再次单击该按钮时,它将滑回。
这是我的意思的一个例子。请注意它看起来像是在左侧窗口的“下方”,以及它如何没有完全(但几乎)延伸到底部和顶部:
这是它没有出现时的图片(背景中的第二个窗口只是第一个图像[上面的那个],因为当我拍摄屏幕截图时浏览器在框架中):
两种方法:
使用JLayeredPane
. 好处是你得到了你正在寻找的重叠效果。缺点是 JLP 使用空布局,这意味着如果不付出额外的努力,您的 UI 将无法很好地调整大小。
使用CardLayout
. 好处是您的布局将按照您询问是否调整大小的方式运行。缺点是你不会得到重叠效果。您的滑出式面板右侧将只有空白区域。
编辑:我刚刚注意到你的滑出没有重叠,而是向外延伸到右边。我最初以为您的意思是类似于旧的 Outlook UI。在那种情况下,它可以是滑出式的,还是必须固定在框架上?
这是一个粗略的演示,它简单地使用 aBorderLayout
作为效果。我在这个演示和截图之间看到的最大区别是:
代码:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class SlideOutPanelDemo
{
private JPanel pnlMain;
private JPanel pnlTools;
private JFrame frame;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new SlideOutPanelDemo().createAndShowGUI();
}
});
}
public void createAndShowGUI()
{
JButton button = new JButton("Tools");
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent event)
{
boolean visible = pnlTools.isVisible();
pnlTools.setVisible(! visible);
frame.pack();
}
});
pnlTools = createToolsPanel();
pnlMain = createMainPanel();
JToolBar toolBar = new JToolBar();
toolBar.add(button);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
contentPane.setOpaque(true);
contentPane.add(toolBar, BorderLayout.NORTH);
contentPane.add(pnlMain, BorderLayout.WEST);
contentPane.add(pnlTools, BorderLayout.EAST);
pnlMain.setVisible(true);
pnlTools.setVisible(false);
JFrame.setDefaultLookAndFeelDecorated(true);
frame = new JFrame("Slide Out Panel Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel()
{
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createTitledBorder("Main"));
panel.add(new JLabel("Field 1"));
panel.add(new JTextField(20));
panel.add(new JLabel("Field 2"));
panel.add(new JTextField(20));
panel.setSize(1000, 600);
return panel;
}
private JPanel createToolsPanel()
{
JPanel panel = new JPanel();
panel.setBackground(Color.YELLOW);
Border b1 = BorderFactory.createTitledBorder("Tools");
Border b2 = BorderFactory.createLineBorder(Color.BLUE, 2);
panel.setBorder(BorderFactory.createCompoundBorder(b2, b1));
panel.add(new JLabel("Thing 1"));
panel.add(new JLabel("Thing 2"));
panel.setSize(400, 600);
return panel;
}
}
在一本书Swing Hacks的帮助下,我创建了一个可滑动的 JFrame 和一个可滑动的 JDialog。我花了几个小时来调试代码。
这是一个测试运行,显示 JOptionPane 滑出一部分。
并且一路走来。
基本上,我采用了 JOptionPane 的内容窗格,并将其动画化为图像。
您左键单击幻灯片按钮以将 JOptionPane 滑出。您左键单击 JOptionPane 上的 Yes 或 No 以将 JOptionPane 向后滑动。
下面是创建动画 JFrame 和动画 JDialog 的代码。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.LineBorder;
public class AnimatedJFrame extends JFrame implements ActionListener {
private static final long serialVersionUID = 6462856212447879086L;
public static final int INCOMING = 1;
public static final int OUTGOING = -1;
public static final float ANIMATION_DURATION = 600F;
public static final int ANIMATION_SLEEP = 5;
JComponent sheet;
JPanel glass;
AnimatingSheet animatingSheet;
boolean animating;
int animationDirection;
Timer animationTimer;
long animationStart;
BufferedImage offscreenImage;
public AnimatedJFrame(String name) {
super(name);
glass = (JPanel) getGlassPane();
glass.setLayout(new GridBagLayout());
animatingSheet = new AnimatingSheet();
animatingSheet.setBorder(new LineBorder(Color.BLACK, 1));
}
public JComponent showJDialogAsSheet(JDialog dialog) {
sheet = (JComponent) dialog.getContentPane();
sheet.setBorder(new LineBorder(Color.BLACK, 1));
glass.removeAll();
animationDirection = INCOMING;
startAnimation();
return sheet;
}
public void hideSheet() {
animationDirection = OUTGOING;
startAnimation();
}
private void startAnimation() {
// glass.repaint();
// Clear glass pane and set up animatingSheet
animatingSheet.setSource(sheet);
glass.removeAll();
setGridBagConstraints(animatingSheet);
glass.setVisible(true);
// Start animation timer
animationStart = System.currentTimeMillis();
if (animationTimer == null) {
animationTimer = new Timer(ANIMATION_SLEEP, this);
}
animating = true;
animationTimer.start();
}
private void stopAnimation() {
animationTimer.stop();
animating = false;
}
@Override
public void actionPerformed(ActionEvent event) {
if (animating) {
// Calculate height to show
float animationPercent = (System.currentTimeMillis() - animationStart)
/ ANIMATION_DURATION;
animationPercent = Math.min(1.0F, animationPercent);
int animatingWidth = 0;
if (animationDirection == INCOMING) {
animatingWidth = (int) (animationPercent * sheet.getWidth());
} else {
animatingWidth = (int) ((1.0F - animationPercent) * sheet
.getWidth());
}
// Clip off that much from the sheet and blit it
// into the animatingSheet
animatingSheet.setAnimatingWidth(animatingWidth);
animatingSheet.repaint();
if (animationPercent >= 1.0F) {
stopAnimation();
if (animationDirection == INCOMING) {
finishShowingSheet();
} else {
glass.removeAll();
glass.setVisible(false);
}
}
}
}
private void finishShowingSheet() {
glass.removeAll();
setGridBagConstraints(sheet);
glass.revalidate();
glass.repaint();
}
private void setGridBagConstraints(JComponent sheet) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
glass.add(sheet, gbc);
gbc.gridy = 1;
gbc.weighty = Integer.MAX_VALUE;
glass.add(Box.createGlue(), gbc);
}
}
class AnimatingSheet extends JPanel {
private static final long serialVersionUID = 3958155417286820827L;
Dimension animatingSize = new Dimension(0, 1);
JComponent source;
BufferedImage offscreenImage;
public AnimatingSheet() {
super();
setOpaque(true);
}
public void setSource(JComponent source) {
this.source = source;
animatingSize.height = source.getHeight();
makeOffscreenImage(source);
}
public void setAnimatingWidth(int width) {
animatingSize.width = width;
setSize(animatingSize);
}
private void makeOffscreenImage(JComponent source) {
GraphicsConfiguration gfxConfig = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getDefaultConfiguration();
offscreenImage = gfxConfig.createCompatibleImage(source.getWidth(),
source.getHeight());
Graphics2D offscreenGraphics = (Graphics2D) offscreenImage
.getGraphics();
source.paint(offscreenGraphics);
offscreenGraphics.dispose();
}
@Override
public Dimension getPreferredSize() {
return animatingSize;
}
@Override
public Dimension getMinimumSize() {
return animatingSize;
}
@Override
public Dimension getMaximumSize() {
return animatingSize;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage fragment = offscreenImage.getSubimage(
offscreenImage.getWidth() - animatingSize.width, 0,
animatingSize.width, source.getHeight());
g.drawImage(fragment, 0, 0, this);
}
}
这是测试动画 JFrame 的代码。
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SheetTest implements PropertyChangeListener, Runnable {
JOptionPane optionPane;
AnimatedJFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new SheetTest());
}
@Override
public void run() {
// Build JOptionPane dialog
optionPane = new JOptionPane("Do you want to save?",
JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION);
optionPane.addPropertyChangeListener(this);
frame = new AnimatedJFrame("Sheet Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Put an image in the frame's content pane
ImageIcon icon = new ImageIcon("images/Google Tile.jpg");
JLabel label = new JLabel(icon);
frame.getContentPane().add(label, BorderLayout.CENTER);
JButton dropButton = new JButton("Slide sheet");
dropButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JDialog dialog = optionPane.createDialog(frame, "Irrelevant");
frame.showJDialogAsSheet(dialog);
}
});
frame.getContentPane().add(dropButton, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
frame.hideSheet();
}
}
}
这是我用来创建测试 JFrame 的图像。