我创建了一个简单的Java应用程序,该应用程序在连续10秒内每秒每秒向中添加新行JTable。它包括三个类。
程序启动后被调用的主类
public class JarBundlerProblem { public static void main(String[] args) { System.err.println("Initializing controller"); new Controller(); } }
创建GUI并通过更改它的控制器 doWork()
public class Controller { public Controller() { doWork(null); } public static void doWork(String s) { GUI gui = new GUI(); for (int i=0; i<10; i++) { gui.addRow("Line "+(i+1)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
And finally, the GUI
import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class GUI { private JFrame frame = new JFrame(); private DefaultTableModel model = new DefaultTableModel(); private JTable table = new JTable(model); private JScrollPane pane = new JScrollPane(table); public GUI() { model.addColumn("Name"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(pane); frame.pack(); frame.setVisible(true); } public void addRow(String name) { model.addRow(new Object[]{name}); } }
由于我是为OS X开发的,因此我需要将我的应用程序与某种文件类型关联(比如说.jarbundlerproblem),因此我必须将JAR文件捆绑到一个APP使用Apple Jar Bundler的文件中。我已成功完成此操作,我的应用程序打开,计数到十,每秒写一次。
Now, for the problem
默认情况下,双击a .jarbundlerproblem并将文件与我的应用程序关联,不会将我双击的文件作为参数传递给应用程序。显然,这只是OS X上的Java。
由于我需要查看双击的文件,因此我使用OSXAdapter,这是Apple为此目的制造的Java库。这是通过更改Controller类的构造函数并添加另一个方法来实现的registerForMacOSXEvents():
OSXAdapter
registerForMacOSXEvents()
public Controller() { registerForMacOSXEvents(); //doWork(null); } public void registerForMacOSXEvents() { try { OSXAdapter.setFileHandler(this, getClass().getDeclaredMethod("doWork", new Class[] { String.class })); } catch (Exception e) { System.err.println("Error while loading the OSXAdapter:"); e.printStackTrace(); } }
但是,在进行此(较小的)修改之后,我的应用程序开始起作用。有时,即使我在控制台中看到它刚刚启动(Initializing controller被编写),它也没有打开,但是经过几次尝试,它最终还是会启动,但是在开始的10秒钟内,窗口将完全空白。之后,将添加10行。
Initializing controller
Help
现在,我为此付出了很多努力,似乎关于OSXAdapter和Jar Bundler的文档都很少。我究竟做错了什么?还是我不应该首先使用OSXAdapter或Jar Bundler?
完成此操作后,我不完全相信SwingWorker是一个更简单(又称更好)的解决方案-仍然需要其他线程同步(在工作线程和传入文件/名称的“外部”线程之间)。无论如何(利用学习的机会,并避免错误:),以下是基本思想的概念证明示例:
开放式问题
public class GUI { private JFrame frame = new JFrame(); private DefaultTableModel model = new DefaultTableModel(); private JTable table = new JTable(model); private JScrollPane pane = new JScrollPane(table); public GUI() { model.addColumn("Name"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(pane); frame.pack(); frame.setVisible(true); } public void addRow(String name) { model.addRow(new Object[] { name }); } /** * Controller is a SwingWorker. */ public static class Controller extends SwingWorker<Void, String> { private GUI gui; private List<String> pending; public Controller() { gui = new GUI(); } public void doWork(String newLine) { if (pending == null) { pending = new ArrayList<String>(); pending.add(newLine); execute(); } else { pending.add(newLine); } } @Override protected Void doInBackground() throws Exception { while (pending.size() > 0) { publish(pending.remove(0)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } /** * @inherited <p> */ @Override protected void process(List<String> chunks) { for (String object : chunks) { gui.addRow(object); } } } /** * Simulating the adapter. * * Obviously, the real-thingy wouldn't have a reference * to the controller, but message the doWork refectively */ public static class Adapter implements Runnable { Controller controller; public Adapter(Controller controller) { this.controller = controller; } @Override public void run() { for (int i=0; i<10; i++) { controller.doWork("Line "+(i+1)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { System.err.println("Initializing controller"); new Adapter(new Controller()).run(); } @SuppressWarnings("unused") private static final Logger LOG = Logger.getLogger(GUI.class.getName()); }