简体   繁体   English

使用秋千创建滑出工具面板

[英]Create slide out Tool Panel with swing

I really don't know how to do this. 我真的不知道该怎么做。 I want to have a panel "slide out" from underneath the current one when the user clicks a button. 我想让一个面板在用户单击按钮时从当前面板的下方“滑出”。 Then, when they click the button again, it will slide back in. 然后,当他们再次单击该按钮时,它将重新滑入。

Here is an example of what I mean. 这是我的意思的一个例子。 Notice how it looks like it's "under" the window on the left and how it doesn't extend past completely (but almost) to the bottom and the top: 请注意,它看起来像是在左侧窗口的“下方”,以及它如何不完全(但几乎)延伸到底部和顶部:

在此处输入图片说明

Here's a picture of it when it is not out (the second window in the background is just the first image [the one above] because the browser was in the frame when I took the screen shot): 这是一张没有显示时的图片(背景中的第二个窗口只是第一个图像(上面的一个),因为在我拍摄屏幕快照时浏览器在框架中): 在此处输入图片说明

Two approaches: 两种方法:

  1. Use a JLayeredPane . 使用JLayeredPane Upside is that you get the overlap effect that you're looking for. 好处是您会得到想要的重叠效果。 Downside is that JLP uses a null layout, which means your UI won't resize nicely without extra effort. 缺点是JLP使用的是null布局,这意味着您的UI在没有额外努力的情况下将无法很好地调整大小。

  2. Use a CardLayout . 使用CardLayout Upside is that your layout will behave as you asked if resized. 好处是您的布局将按照您要求的大小进行调整。 Downside is that you won't get the overlap effect. 缺点是您不会得到重叠效果。 You're slide-out panel will just have blank space to right of it. 您滑出面板的右侧将只有空白。

EDIT: I just noticed that your slide-out isn't overlapping, but extending outward to the right. 编辑:我只是注意到您的滑出不是重叠,而是向右向外延伸。 I originally thought you meant something like the old Outlook UI. 我最初以为您的意思类似于旧的Outlook UI。 In that case, can it be any slide-out, or does it have to be anchored to the frame? 在那种情况下,它是否可以滑出,还是必须固定在框架上?

Here's a crude demo that simply uses a BorderLayout for the effect. 这是一个简单的演示,仅使用BorderLayout进行效果。 The big difference I see between this demo and the screenshots are: 我在此演示和屏幕截图之间看到的最大区别是:

  1. The frame's border extends with the slide-out in the demo 框架的边框随着演示中的滑出而扩展
  2. The slide-out panel isn't offset in the demo. 滑出面板在演示中没有偏移。

Code: 码:

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;
  }
}

With the help of a book, Swing Hacks , I created a sliding JFrame and a sliding JDialog. 借助《 Swing Hacks 》这本书,我创建了一个滑动JFrame和一个滑动JDialog。 It took me a few hours to debug the code. 我花了几个小时来调试代码。

Here's a test run showing a JOptionPane slid part way out. 这是一个测试运行,显示JOptionPane滑出了一半。

试纸局部

And all the way out. 一直到。

工作表测试

Basically, I took the content pane of the JOptionPane, and animated it as an image. 基本上,我采用了JOptionPane的内容窗格,并将其动画化为图像。

You left click the slide sheet button to slide the JOptionPane out. 左键单击幻灯片按钮将JOptionPane滑出。 You left click Yes or No on the JOptionPane to slide the JOptionPane back. 您在JOptionPane上单击“是”或“否”,以向后滑动JOptionPane。

Here's the code to create the animated JFrame and animated JDialog. 这是创建动画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);
    }
}

Here's the code to test the animated JFrame. 这是测试动画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();
        }

    }

}

And here's the image I used to create the test JFrame. 这是我用来创建测试JFrame的图像。

谷歌瓷砖

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM