JAR Bundler使用OSXAdapter导致应用程序滞后或终止

kba*_*kba 4 java macos swing jarbundler

我创建了一个简单的Java应用程序,每秒连续10秒为a添加一个新行JTable.它由三个类组成.

程序启动后调用的主类

public class JarBundlerProblem {
    public static void main(String[] args)
    {
        System.err.println("Initializing controller");
        new Controller();
    }
}
Run Code Online (Sandbox Code Playgroud)

一个控制器,用于创建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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,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});
    }
}
Run Code Online (Sandbox Code Playgroud)

由于我正在为OS X开发,我需要能够将我的应用程序与某种文件类型相关联(比方说.jarbundlerproblem),我必须将我的JAR文件捆绑到APP使用Apple Jar Bundler中.我已成功完成此操作,我的应用程序打开,计数到十,每秒写出来.

现在,针对这个问题

默认情况下,双击a .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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但经过这次(次要)修改后,我的应用程序开始起作用.有时,它不会打开,即使我可以在控制台中看到它刚刚启动(Initializing controller写入),但经过几次尝试后,它最终会启动,但是前10秒窗口将完全空白,并且之后,将添加10行.

救命

现在,我已经很努力了,似乎没有很多关于OSXAdapter和Jar Bundler的文档.我究竟做错了什么?或者我不应该首先使用OSXAdapter或Jar Bundler?

tra*_*god 6

看起来你正在阻止事件派发线程(EDT).SwingWorker将是一个更好的选择,但这个例子实现Runnable.

附录:您可以查看此项目以获取MVC架构的示例.它还展示了如何在不使用JAR Bundler的情况下构建Mac OS应用程序包.有关MVC的更多信息,请点击此处.

顺便说一下,这个例子展示了一种自动滚动方法JTable.点击拇指暂停滚动; 释放恢复.

附录:您的应用程序在启动时滞后10秒.因为这是Controller睡觉的确切时间,所以它肯定会在美国东部时间睡觉.一个sscce将是决定性的.相反,在另一个线程上完成工作并在EDT上更新模型.SwingWorker有一个process()自动执行此操作的方法,或者您可以使用invokeLater()如下所示的方法.在您的应用程序正确同步之前,没有希望让Apple事件发挥作用.

附录:您可以调用isDispatchThread()Controller检查.引用的项目包括一个.dmg带有Mac应用程序的ant文件和一个通过目标在原位构建软件包的文件dist2.

附录:另请参见此处显示的替代方法.

在此输入图像描述

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/** @seehttps://stackoverflow.com/questions/7519244 */
public class TableAddTest extends JPanel implements Runnable {

    private static final int N_ROWS = 8;
    private static String[] header = {"ID", "String", "Number", "Boolean"};
    private DefaultTableModel dtm = new DefaultTableModel(null, header) {

        @Override
        public Class<?> getColumnClass(int col) {
            return getValueAt(0, col).getClass();
        }
    };
    private JTable table = new JTable(dtm);
    private JScrollPane scrollPane = new JScrollPane(table);
    private JScrollBar vScroll = scrollPane.getVerticalScrollBar();
    private JProgressBar jpb = new JProgressBar();
    private int row;
    private boolean isAutoScroll;

    public TableAddTest() {
        this.setLayout(new BorderLayout());
        jpb.setIndeterminate(true);
        this.add(jpb, BorderLayout.NORTH);
        Dimension d = new Dimension(320, N_ROWS * table.getRowHeight());
        table.setPreferredScrollableViewportSize(d);
        for (int i = 0; i < N_ROWS; i++) {
            addRow();
        }
        scrollPane.setVerticalScrollBarPolicy(
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        vScroll.addAdjustmentListener(new AdjustmentListener() {

            @Override
            public void adjustmentValueChanged(AdjustmentEvent e) {
                isAutoScroll = !e.getValueIsAdjusting();
            }
        });
        this.add(scrollPane, BorderLayout.CENTER);
        JPanel panel = new JPanel();
        panel.add(new JButton(new AbstractAction("Add Row") {

            @Override
            public void actionPerformed(ActionEvent e) {
                addRow();
            }
        }));
        this.add(panel, BorderLayout.SOUTH);
    }

    private void addRow() {
        char c = (char) ('A' + row++ % 26);
        dtm.addRow(new Object[]{
                Character.valueOf(c),
                String.valueOf(c) + String.valueOf(row),
                Integer.valueOf(row),
                Boolean.valueOf(row % 2 == 0)
            });
    }

    private void scrollToLast() {
        if (isAutoScroll) {
            int last = table.getModel().getRowCount() - 1;
            Rectangle r = table.getCellRect(last, 0, true);
            table.scrollRectToVisible(r);
        }
    }

    @Override
    public void run() {
        while (true) {
            EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    addRow();
                }
            });
            EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    scrollToLast();
                }
            });
            try {
                Thread.sleep(1000); // simulate latency
            } catch (InterruptedException ex) {
                System.err.println(ex);
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                TableAddTest nlt = new TableAddTest();
                f.add(nlt);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
                new Thread(nlt).start();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)