首页 > 解决方案 > 如何让 jButton.setVisible() 立即工作?

问题描述

我编写了一个测试程序,使 jButton 不可见和可见:

import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;

public class Blink
{
    private JButton btn;
    private static JFrame f;

    public static void delay(int ms)
    {
        try
        {
            Thread.sleep(ms);
        }
        catch(InterruptedException ex)
        {
            Thread.currentThread().interrupt();
        }
    }

    public Blink()
    {
        f = new JFrame("Blink");
        f.setPreferredSize(new Dimension(500, 500));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        btn = new JButton("Click me and I'll blink!");
        f.add(btn);
        btn.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                buttonClicked();
            }
        });

        f.pack();
        f.setVisible(true);
    }

    private void buttonClicked()
    {
        for (int i = 0; i < 5; i++)
        {
            delay(300);
            btn.setVisible(false);
            delay(300);
            btn.setVisible(true);
        }
    }

    public static void main(String[] args)
    {
        new Blink();
    }
}

不幸的是,jButton 不闪烁。并且当 buttonClicked() 函数发生变化时,将 jButton 设置为 5 次不可见并且不设置为可见,仅当 for 循环完成时 jButton 才会消失。如何让 jButton 瞬间消失并重新出现?

标签: javaswingjbutton

解决方案


您不能在 Swing Thread 中使用 Thread.sleep 方法(所有侦听器都在 Event Dispatcher Thread - EDT 中调用)。要实现闪烁,您必须使用javax.swing.Timer类。有关更多信息,请查看此处此处

这是您重新设计的示例:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Blink {
    private JButton btn;

    private JFrame f;

    public void delay(int ms, boolean show) {
        Timer timer = new Timer(ms, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                btn.setVisible(show);
                btn.getParent().revalidate();
                btn.getParent().repaint();
            }
        });
        timer.setRepeats(false);
        timer.start();
    }

    public Blink() {
        f = new JFrame("Blink");
        f.setPreferredSize(new Dimension(500, 500));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        btn = new JButton("Click me and I'll blink!");
        f.add(btn);
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                buttonClicked();
            }
        });

        f.pack();
        f.setVisible(true);
    }

    private void buttonClicked() {
        for (int i = 1; i <= 10; i += 2) {
            delay(300 * i, false);
            delay(300 * (i + 1), true);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Blink();
            }
        });
    }
}

对于一些复杂setVisible(false)的布局,调用可能会有副作用。在这种情况下,应该使用带有组件的CardLayout和一个空面板。

这是变体CardLayout

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Blink {

    private static final String BUTTON_CARD = "button";

    private static final String EMPTY_CARD = "empty";

    private JButton btn;

    private JFrame f;

    private final CardLayout cardLayout = new CardLayout();

    public void delay(int ms, boolean show) {
        Timer timer = new Timer(ms, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                cardLayout.show(btn.getParent(), show ? BUTTON_CARD : EMPTY_CARD);
                btn.getParent().revalidate();
                btn.getParent().repaint();
            }
        });
        timer.setRepeats(false);
        timer.start();
    }

    public Blink() {
        f = new JFrame("Blink");
        f.setPreferredSize(new Dimension(500, 500));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(cardLayout);
        btn = new JButton("Click me and I'll blink!");
        f.add(btn, BUTTON_CARD);
        f.add(new JPanel(), EMPTY_CARD);
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                buttonClicked();
            }
        });

        f.pack();
        f.setVisible(true);
    }

    private void buttonClicked() {
        for (int i = 1; i <= 10; i += 2) {
            delay(300 * i, false);
            delay(300 * (i + 1), true);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Blink();
            }
        });
    }
}

推荐阅读