如果我理解正确,您需要显示某种正在进行的进度,直到按钮完成其工作。
如果是这样,您可以使用 CardLayout 和不确定的 JProgressBar。
CardLayout 是一个LayoutManager(例如BorderLayout、FlowLayout 等...),它允许您定义卡片。每个卡片都是一个Component(例如Container和其他Components,例如JPanel)。任何时候都只能看到一张卡片。每个 card 都与一个字符串相关联,以识别它并能够将其选择为在其他卡片上可见。你可以阅读更多关于CardLayout in the corresponding Java tutorial的信息。
JProgressBar 是一个进度条,即JComponent,它向您显示正在进行的任务的进度。有两种模式:确定和不确定。在确定模式下,您可以指定问题的大小并通过代码自己推进进度条。在不确定模式下,指示旋钮不断旋转(这让用户知道有一个正在进行的任务正在进行中,并且程序不知道需要多长时间)。 JProgressBar 可以用作用户的简单视觉指示器。你可以阅读更多关于JProgressBar in the corresponding Java tutorial的信息。
因此,在您的情况下,您可以将CardLayout 与两张卡片一起使用,其中一张卡片包含“帮助”按钮,另一张卡片包含不确定的JProgressBar。当用户点击“帮助”时,您会显示进度条卡片,当进度完成时,您会切换回“帮助”按钮卡片。
现在,如果您在“帮助”按钮的ActionListener 内执行进度,它将在事件调度线程(或简称 EDT)上运行。因此,您的卡将无法切换,因为切换也在 EDT 内部完成。在这种情况下,我们将创建一个单独的SwingWorker 来处理进度。所以ActionListener 唯一能做的就是创建并启动这样一个SwingWorker。这样会让ActionListener在进度结束之前结束,所以卡片会被切换。
考虑以下示例代码:
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class MyPanel extends JPanel {
private static final Dimension PANEL_SIZE = new Dimension(500, 500);
public MyPanel() {
//Always prefer a layout instead of setting it to null.
super(new CardLayout()); //Set the layout of the main panel to CardLayout, so we can add the cards...
//Obtain the CardLayout we just created for this panel:
final CardLayout cardLayout = (CardLayout) super.getLayout();
//String names of each card:
final String nameForCardWithButton = "BUTTON",
nameForCardWithProgress = "PROGRESS";
//Creating first card...
final JPanel cardWithButton = new JPanel(new GridBagLayout());
/*Using a GridBagLayout in a panel which contains a single component (such as the
cardWithButton panel, containing a single JButton) will layout the component in
the center of the panel.*/
final JButton btnH = new JButton("HELP");
cardWithButton.add(btnH);
// Action listener to listen to button click and display pop-up when received.
btnH.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
cardLayout.show(MyPanel.this, nameForCardWithProgress); //Switch to progress bar card...
//Create and start worker Thread:
new SwingWorker() {
@Override
protected Object doInBackground() throws Exception {
/*Simulate a long ongoing process without blocking the EDT...
Well, actually, the JOptionPane will block the EDT I think, so I will leave
it here for demonstration puprposes only.*/
JOptionPane.showMessageDialog(null, "Helpful info...", "info", JOptionPane.INFORMATION_MESSAGE);
return null; //Not sure if returning null here is a good practice or not.
}
@Override
protected void done() {
cardLayout.show(MyPanel.this, nameForCardWithButton); //Switch back to button card, when the job has finished.
}
}.execute();
}
});
//Creating second card...
final JPanel cardWithProgress = new JPanel(new FlowLayout());
final JProgressBar bar = new JProgressBar();
bar.setIndeterminate(true); //Here we initialize the progress bar to indeterminate mode...
cardWithProgress.add(bar);
super.add(cardWithButton, nameForCardWithButton);
super.add(cardWithProgress, nameForCardWithProgress);
super.setPreferredSize(PANEL_SIZE);
}
private static void createAndDisplay() {
JFrame frame = new JFrame("Frame");
frame.getContentPane().add(new MyPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createAndDisplay();
}
});
}
}
您可以在这里看到MyPanel 的创建和初始化,它是带有CardLayout 的容器。在其中,我们添加了两张卡。一个带有按钮,一个带有进度条。