Как заставить jButton.setVisible () работать мгновенно? - PullRequest
0 голосов
/ 04 февраля 2020

Я написал тестовую программу, которая делает 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 раз и не возвращается назад, jButton исчезает только после завершения for-l oop. Как сделать так, чтобы jButton мгновенно исчезал?

Ответы [ 2 ]

2 голосов
/ 04 февраля 2020

Вы не можете использовать метод Thread.sleep в Swing Thread (все слушатели вызываются в 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();
            }
        });
    }
}
0 голосов
/ 04 февраля 2020

Как указывает @Sergiy - убедитесь, что вы бежите из EDT, и не спите на EDT, вместо этого используйте таймер поворота.

Чтобы ваш jButton выглядел "невидимым", вы может сделать что-то вроде этого:

public void setInvisible(jButton jb) {
  jb.setOpaque(false);
  jb.setContentAreaFilled(false);
  jb.setBorderPainted(false);
  jb.setText("");
}

// Assuming you have the original text saved in a variable
public void setRevisible(jButton jb) {
  jb.setOpaque(true);
  jb.setContentAreaFilled(true);
  jb.setBorderPainted(true);
  jb.setText(originalString);
}

В зависимости от того, хотите ли вы нажимать кнопку, когда она невидима, вы также можете добавить btn.setEnabled(bool);

...