我创建了一个简单的 Java 应用程序,连续 10 秒的每一秒都会向 JTable
添加一个新行。它由三个类组成。
程序启动后调用的主类
public class JarBundlerProblem {
public static void main(String[] args)
{
System.err.println("Initializing controller");
new Controller();
}
}
创建 GUI 并通过 doWork()
进行更改的 Controller 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();
}
}
}
}
最后,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
)相关联,我必须使用 Apple Jar Bundler 将我的 JAR
文件捆绑到一个 APP
中。我成功地做到了这一点,我的应用程序打开,数到十,每秒写出一次。现在,对于问题
默认情况下,双击
.jarbundlerproblem
并将文件与我的应用程序相关联,不会将我双击的文件作为参数传递给应用程序。显然,这只是 OS X 上的 Java 工程。由于我需要能够查看双击的文件,因此我使用了 OSXAdapter,它是 Apple 为此目的制作的 Java 库。这个,我通过改变我的
Controller
类的构造函数并添加了另一个方法 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();
}
}
但是在这个(小)修改之后,我的应用程序开始起作用。有的时候打不开,虽然我在Console里可以看到它刚刚启动(写的是Initializing controller
),但是经过几次尝试,它最终还是会启动,但是前10秒窗口会完全空白,之后,将添加 10 行。帮助
现在,我为此苦苦挣扎,似乎没有很多关于 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());
}