我应该在EDT中创建摆动元素吗?
我在编辑非线程安全的图形元素时遇到了并发性问题,但我正在创建它们,但尚未显示出来,如果它们太多或需要花费一些时间来分配,这将冻结GUI,但不会。是吗?
这是我使用EDT显示但不创建GUI结构的示例:
public class Launcher { private final SwingWorker worker; private final JFrame frame; private final JLabel label; private final JProgressBar progressBar; public Launcher() { // init user interface frame = new JFrame(); JPanel panel = new JPanel(new BorderLayout()); label = new JLabel("Launching...", SwingConstants.CENTER); progressBar = new JProgressBar(0, 100); progressBar.setIndeterminate(true); panel.add(label, BorderLayout.CENTER); panel.add(progressBar, BorderLayout.PAGE_END); initUI(panel); worker = new LauncherWorker(this); worker.addPropertyChangeListener((PropertyChangeListener)this); } private void initUI(final Component panel) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { DirectaChatLauncher.this.initUI(panel); } //run() }); return; } Container contentPane = frame.getContentPane(); contentPane.setLayout(new BorderLayout()); contentPane.add(panel, BorderLayout.PAGE_END); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); progressBar.setValue(progress); } } private void setProgression(final String msg) { label.setText(msg); } class LauncherWorker extends SwingWorker<Boolean, String> { private final Launcher LAUNCHER; public LauncherWorker(Launcher launcher) { super(); LAUNCHER = launcher; } @Override protected Boolean doInBackground() throws Exception { setProgress(0); publish("Started"); ... setProgress(100); publish("Launched"); Thread.sleep(1000); return Boolean.TRUE; } @Override protected void process(List<String> chunks) { LAUNCHER.setProgression(chunks.get(0)); } @Override public void done() { LAUNCHER.done(); } } }
因为元素还没有显示好吗?还是我应该全部搬进去initUI()?
initUI()
在Swing 可分离模型体系结构中 ,视图组件侦听其模型。因为视图可以任意响应模型更新生成的事件,所以相应的模型 也 必须在EDT上进行更新。您可以通过以下两种基本方法之一来减少延迟:
使用EventQueue.invokeLater()从一个单独的线程,如图所示这里。
EventQueue.invokeLater()
使用SwingWorker以获得额外的好处列举在这里。
SwingWorker
由于大小,您一定要在后台加载文件,以避免阻塞事件分发线程;SwingWorker是一个常见的选择。与其使用a Document,不如考虑更新aTableModel并在a的行中显示文本行JTable。这具有几个优点:
结果将立即开始显示,并且可以减少感知到的延迟。
JTable使用flyweight模式进行渲染,该模式可以很好地扩展到数兆字节,百万行的范围。
您可以在读取输入时对其进行解析,以创建任意列结构。
您可以利用排序和过滤的功能JTable,为例子。
您可以用来TablePopupEditor将重点放在一行上。
附录:以下示例DefaultTableModel为方便起见。为了降低开销,扩展AbstractTableModel和管理List或List,如图所示这里。该示例显示不确定的进度;显示中间进度的更改在此处显示。
码:
import java.awt.BorderLayout; import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.List; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingWorker; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; /** * @see https://stackoverflow.com/a/25526869/230513 */ public class DisplayLog { private static final String NAME = "/var/log/install.log"; private static class LogWorker extends SwingWorker<TableModel, String> { private final File file; private final DefaultTableModel model; private LogWorker(File file, DefaultTableModel model) { this.file = file; this.model = model; model.setColumnIdentifiers(new Object[]{file.getAbsolutePath()}); } @Override protected TableModel doInBackground() throws Exception { BufferedReader br = new BufferedReader(new FileReader(file)); String s; while ((s = br.readLine()) != null) { publish(s); } return model; } @Override protected void process(List<String> chunks) { for (String s : chunks) { model.addRow(new Object[]{s}); } } } private void display() { JFrame f = new JFrame("DisplayLog"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); JProgressBar jpb = new JProgressBar(); f.add(jpb, BorderLayout.NORTH); f.add(new JScrollPane(table)); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); LogWorker lw = new LogWorker(new File(NAME), model); lw.addPropertyChangeListener((PropertyChangeEvent e) -> { SwingWorker.StateValue s = (SwingWorker.StateValue) e.getNewValue(); jpb.setIndeterminate(s.equals(SwingWorker.StateValue.STARTED)); }); lw.execute(); } public static void main(String[] args) { EventQueue.invokeLater(() -> { new DisplayLog().display(); }); } }