java - 调整 JFrame 大小时的黑色轮廓

标签 java swing user-interface jframe transition

我正在尝试创建从一个 JPanel 到下一个 JPanel 的平滑动画,其中第二个 JPanel 比第一个 JPanel 更高更宽,需要我重新缩放 JFrame。为此,我创建了以下代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;

public class Example1 extends JFrame
{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public Example1()
    {
        initComponents();
    }

    public static void main(String[] args) 
    {
        try 
        {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // get look and feel based on OS
        } 
        catch (ClassNotFoundException ex) // catch all errors that may occur
        {
            Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
        } 
        catch (InstantiationException ex) 
        {
            Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
        } 
        catch (IllegalAccessException ex) 
        {
            Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
        } 
        catch (UnsupportedLookAndFeelException ex) 
        {
            Logger.getLogger(Example1.class.getName()).log(Level.SEVERE, null, ex);
        }

        EventQueue.invokeLater(new Runnable()
        {
            public void run() // run the class's constructor, therefore starting
                                // the UI being built
            {
                new Example1().setVisible(true);;
            }
        });
    }

    private WindowListener exitListener = new WindowAdapter() 
    {
        @Override
        public void windowClosing(WindowEvent e) 
        {
            closingEvent(); // if window closing, go to exit menu
        }
    };

    private void initComponents() // method to build initial view for user for installation
    {
        // instantiating elements of the GUI
        pnlStart = new JPanel();
        lblMain = new JLabel();
        lblDivider = new JLabel();
        lblTextPrompt = new JLabel();
        txtAccNum = new JTextField();
        btnNext = new JButton();
        btnExit = new JButton();

        pnlStart.setVisible(true);
        add(pnlStart); // adding the panel to the frame

        removeWindowListener(exitListener);
        addWindowListener(exitListener); // removing before adding the windowlistener, ensures there is only one listener there
        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // setting "x" button to do nothing except what exitListener does
        setPreferredSize(new Dimension(600, 400)); // setting measurements of jframe

        setTitle("Example 1.0"); // setting title on JFrame
        setResizable(false); // disabling resizing
        setLayout(null); // ensuring I can specify element positions
        setBackground(Color.WHITE); // setting background color

        lblMain.setText("<html>Please input a number below how many accounts you would like to<br>create: </html>"); // main label that explains what happens, html used for formatting
        lblMain.setFont(lblMain.getFont().deriveFont(18.0f)); // changing font size to 16
        lblMain.setBounds(27, 60, 540, 100); // setting position and measurements
        add(lblMain); // adding label to JFrame

        lblTextPrompt.setText("Amount of accounts (1-10):");
        lblTextPrompt.setFont(lblMain.getFont().deriveFont(16.0f));
        lblTextPrompt.setBounds(166, 190, 198, 18);
        lblTextPrompt.setLabelFor(txtAccNum);
        add(lblTextPrompt);

        txtAccNum.setFont(lblMain.getFont());
        txtAccNum.setBounds(374, 187, 50, 26);
        txtAccNum.addKeyListener(new KeyAdapter() 
        {
            public void keyTyped(KeyEvent e) 
            {
                if (txtAccNum.getText().length() >= 4) // limit textfield to 3 characters
                    e.consume();
            }
        });
        txtAccNum.addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent e) 
            {
                AccDetails(Integer.parseInt(txtAccNum.getText()));
            }
        });
        add(txtAccNum);

        lblDivider.setText(""); // ensuring no text in label
        lblDivider.setBounds(10, 285, 573, 10); // setting bounds and position of dividing line
        lblDivider.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.LIGHT_GRAY)); // setting border to label for the dividing
        add(lblDivider); // adding it to JFrame

        btnNext.setText("Next"); // adding text to button for starting
        btnNext.setFont(lblMain.getFont().deriveFont(14.0f)); // setting font size
        btnNext.setBounds(495, 315, 80, 35); // positioning start button
        btnNext.addActionListener(new ActionListener() // add listener for action to run method
        {
            public void actionPerformed(ActionEvent evt) 
            {
                AccDetails(Integer.parseInt(txtAccNum.getText()));
            }
        });
        add(btnNext); // adding button to JFrame

        btnExit.setText("Exit"); // adding text to button for exiting
        btnExit.setFont(btnNext.getFont()); // getting font from start button
        btnExit.setBounds(20, 315, 80, 35); // positioning on form
        btnExit.addActionListener(new ActionListener() // add listener for action to run method
        {
            public void actionPerformed(ActionEvent evt) 
            {
                closingEvent(); // running cancel method (same method as hitting the "x" button on the form)
            }
        });

        add(btnExit); // adding button to JFrame
        repaint(); // repainting what is displayed if going coming from a different form
        revalidate(); // revalidate the elements that will be displayed
        pack(); // packaging everything up to use
        setLocationRelativeTo(null); // setting form position central
        txtAccNum.requestFocusInWindow(); // setting focus on start button when everything is loaded
    }

    private void AccDetails(int accNum) 
    {
        getContentPane().removeAll();
        // instantiating elements of the GUI
        pnlAccDetails = new JPanel();

        pnlAccDetails.setVisible(true);
        add(pnlAccDetails); // adding the panel to the frame

        removeWindowListener(exitListener);
        addWindowListener(exitListener); // removing before adding the windowlistener, ensures there is only one listener there
        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // setting "x" button to do nothing except what exitListener does

        while (sizeW != 750 && sizeH != 500)
        {
            setBackground(Color.BLACK);
            Point loc = getLocationOnScreen();
            setPreferredSize(new Dimension(sizeW, sizeH));
            pnlAccDetails.setPreferredSize(new Dimension(sizeW, sizeH));
            repaint();
            revalidate();
            pack();

            sizeW += 1.5;
            sizeH += 1;
            if (toggle)
            {
                setLocation((int)(loc.getX() - 0.75), (int)(loc.getY() - 0.5));
                toggle = false;
            }
            else
            {
                toggle = true;
            }

            try 
            {
                Thread.sleep(1);
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
        }

        setTitle("Example 1.0"); // setting title on JFrame
        setResizable(false); // disabling resizing
        setLayout(null); // ensuring I can specify element positions
        setBackground(Color.WHITE); // setting background color

        repaint(); // repainting what is displayed if going coming from a different form
        revalidate(); // revalidate the elements that will be displayed
        pack(); // packaging everything up to use
        setLocationRelativeTo(null); // setting form position central
    }

    private void closingEvent() 
    {
        if (JOptionPane.showConfirmDialog(null, "<html><center>Are you sure you want to quit?</center></html>", "Quit?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) 
            System.exit(0); // output warning that it would cancel installation, if accepted...
        else // if not accepted...
        {
        }
    }

    // objects used in UI
    private JPanel pnlStart;
    private JPanel pnlAccDetails;
    private JLabel lblMain;
    private JLabel lblDivider;
    private JLabel lblTextPrompt;
    private JTextField txtAccNum;
    private JButton btnNext;
    private JButton btnExit;

    private int sizeW = 600;
    private int sizeH = 400;
    private boolean toggle = false;
}

虽然此代码确实有效,但在调整大小期间,表单不会保留其背景颜色,而是具有带有新测量值的黑色轮廓。据我所知,根据我所做的研究,这是由于所使用的渲染引擎造成的。是否有办法强制渲染引擎在每次迭代时运行,或者是否有其他方法可以做到这一点?我已经看到了使用通用补间引擎的建议,但是我找不到任何调整大小的示例,特别是对于 JFrame。 提前致谢

最佳答案

如上述评论(@Sergiy Medvynskyy)所述,阻塞 Swing 线程会导致其无法正确渲染。通过使用 Swing Timer,动画可以顺利运行。我用于解决方案的代码是:

    timer = new Timer (10, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent arg0) 
        {
            Point loc = getLocationOnScreen();
            setPreferredSize(new Dimension(sizeW, sizeH));
            pnlAccDetails.setPreferredSize(new Dimension(sizeW, sizeH));
            repaint();
            revalidate();
            pack();

            sizeW += 3;
            sizeH += 2;
            if (toggle)
            {
                setLocation((int)(loc.getX() - 0.75), (int)(loc.getY() - 0.5));
                toggle = false;
            }
            else
            {
                toggle = true;
            }

            if (sizeW == 750 && sizeH == 500)
            {
                timer.stop();
            }
        }
    });

    timer.start();

上面的代码用于代替我原来问题中的 while 循环。感谢 Sergiy Medvynskyy 的回答。

关于java - 调整 JFrame 大小时的黑色轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44653202/

相关文章:

java - 使用 Jetty 8 内存 promise 不断增加,直到服务器因 spring 缓存而失败

java - Eclipse插件开发: Vertically scrolling table?

animation - Alive GUI 库,支持 Haskell 的 FRP

java - 如何继承/使用多个类的方法

java - 如何根据用户输入在 TreeSet 中添加特定数量的对象?

java - 从 JTree 中的文本文件动态填充树模型

Java Swing 制作具有自定义尺寸的盒子

java - 如何使JTextField和JComboBox圆角无边框和背景图像?

java - 如何在 Selenium 中跳过 NoSuchElementException

java - 设置 JButton 不可点击但不灰显