实时向 JFrame 添加多个 JPanel
我正在编写一个工具来对文本文件执行任务。该任务需要一些时间才能执行,因此我制作了一个面板来显示文件名和进度百分比。 用户可以在一个或多个文件上运行该任务,因此我需要为每个文件显示一个面板。问题是没有添加面板。 我正在将我的代码更新为独立的,如下所示:
package sscce.jpanel;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnAbort;
JButton btnClose;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
for(int i = 0; i < 10; i++) {
frame.addTask(i, "Task"+i);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
getContentPane().setLayout(null);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea();
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
getContentPane().add(newTaskPanel);
validate();
repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
setLayout(null);
lblTaskDescription = new JLabel(id + " " + fileName);
//lblTaskDescription.setBounds(10, 11, 632, 14);
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " + e.getMessage());
}
}
}
}
I am writing a tool take performs a task on text file. The task takes some time to perform so I made a panel that displays the file name and the progress in percentage.
The user may run the task on one or on several files, so I need to display a panel for each file. The problem is that the panels are not being added. I am updating my code to be self contained as suggested below:
package sscce.jpanel;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnAbort;
JButton btnClose;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
for(int i = 0; i < 10; i++) {
frame.addTask(i, "Task"+i);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
getContentPane().setLayout(null);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea();
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
getContentPane().add(newTaskPanel);
validate();
repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
setLayout(null);
lblTaskDescription = new JLabel(id + " " + fileName);
//lblTaskDescription.setBounds(10, 11, 632, 14);
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " + e.getMessage());
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
调用
validate()
,然后调用repaint()
。这是 SSCCE 的黑客版本。不确定最终的要求是什么,但我添加了一个按钮,允许在 GUI 可见后添加新任务。似乎不需要
repaint()
调用,所以我将其编辑掉。Call
validate()
thenrepaint()
.This is a hacked version of your SSCCE. Not sure what the final requirement is, but I added a button that allows addition of new tasks after the the GUI is visible. Seems the
repaint()
call is not needed, so I edited it out.您可以尝试从
PanelTaskProgress
中删除setLayout(null);
。JPanel
默认情况下有FlowLayout
,每个面板都有两个水平居中对齐的组件。You can try to remove
setLayout(null);
fromPanelTaskProgress
.JPanel
hasFlowLayout
by default and every panel have two component which you align horizontal center.有两件事:
首先,您的面板是空的,因为您在
PanelTaskProgress
构造函数中调用了setLayout(null);
。调用setLayout(new FlowLayout());
即可看到它们的内容。其次,更有趣的是:您的 main 方法在主线程中运行,而不是在事件调度线程中运行。当您在框架上调用
setVisible()
时,EDT 开始执行操作。不久之后的某个随机时间,您开始更改布局,同样不是从 EDT 开始更改布局。这势必会产生问题。您必须在事件调度线程上创建和修改布局。将您的主要方法包装在
所有 Swing 程序中都应该执行此操作。
Two things:
First, your panels are empty because you call
setLayout(null);
in yourPanelTaskProgress
constructor. CallsetLayout(new FlowLayout());
instead and you'll see their contents.Second, and more interestingly: Your main method is running in the main thread, not the event dispatch thread. When you call
setVisible()
on the frame, the EDT starts doing things. At a random time shortly after, you start changing the layout, again not from the EDT. This is bound to create problems. You have to create and modify the layout on the event dispatch thread.Wrap your main method in
All Swing programs should do this.