Question

I expected to see close to 200,000 lines (196,608) of output from the loop in this code. It only prints one line. Can anyone spot the blunder?

import java.awt.*;
import java.util.*;
import javax.swing.*;

class SwingWorkerUnicodeTest {

    private String[] fontNameArray;
    private JLabel output = new JLabel("Processing..");
    private JProgressBar progressBar = new JProgressBar();

    class CodePointDetailWorker extends SwingWorker<Object, Object> {

        private ArrayList<Character.UnicodeBlock> unicodeBlockNames;
        private ArrayList<Character.UnicodeScript> unicodeScripts;
        private int[] glyphCount = new int[fontNameArray.length];

        public CodePointDetailWorker() {
            progressBar.setVisible(true);
            Arrays.fill(glyphCount, 0);
        }

        @Override
        protected Void doInBackground() throws Exception {
            // Check for for the first 3 planes.  The next 11 are unassigned
            int pS = 3*65536;
            for (int kk = 0; kk < pS; kk++) {
                System.out.println("doInBackground " + kk + " " + pS);
                doForEveryCodePoint(kk);
            }
            return null;
        }

        @Override
        public void done() {
            output.setText("Done!");
        }

        private final void doForEveryCodePoint(final int codePoint) {
            Character.UnicodeBlock block = Character.UnicodeBlock.of(codePoint);
            if (block != null && !unicodeBlockNames.contains(block)) {
                unicodeBlockNames.add(block);
            }

            Character.UnicodeScript us = Character.UnicodeScript.of(codePoint);
            if (us == null || us.toString() == null) {
            } else {
                if (!unicodeScripts.contains(us)) {
                    unicodeScripts.add(us);
                }
            }

            // fonts - test for points in all 6 defined blocks.
            for (int ii = 0; ii < fontNameArray.length; ii++) {
                Font f = new Font(fontNameArray[ii], Font.PLAIN, 16);
                if (f.canDisplay(codePoint)) {
                    glyphCount[ii]++;
                }
            }
        }
    }

    public SwingWorkerUnicodeTest() {
        GraphicsEnvironment ge =
                GraphicsEnvironment.getLocalGraphicsEnvironment();
        fontNameArray = ge.getAvailableFontFamilyNames();
        JPanel gui = new JPanel(new BorderLayout());

        gui.add(progressBar, BorderLayout.CENTER);
        gui.add(output, BorderLayout.PAGE_END);

        CodePointDetailWorker cpdw = new CodePointDetailWorker();
        cpdw.execute();

        JOptionPane.showMessageDialog(null, gui);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                new SwingWorkerUnicodeTest();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

Edit

Fixed code, based on the advice of the first 2 answers.

It now both implements the overridden method that reports errors, but initializes the arrays for ..much output and shows progress in the progress bar.

import java.awt.*;
import java.util.*;
import javax.swing.*;

class SwingWorkerUnicodeTest {

    private JLabel output = new JLabel("Processing..");
    // Check for for the first 3 planes.  The next 11 are unassigned
    int pS = 3 * 65536;
    private JProgressBar progressBar = new JProgressBar(0, pS);

    class CodePointDetailWorker extends SwingWorker<Object, Object> {

        private ArrayList<Character.UnicodeBlock> unicodeBlockNames;
        private ArrayList<Character.UnicodeScript> unicodeScripts;
        private int[] glyphCount;
        private String[] fontNameArray;

        public CodePointDetailWorker(String[] fontNameArray) {
            this.fontNameArray = fontNameArray;
            progressBar.setVisible(true);
            glyphCount = new int[fontNameArray.length];
            Arrays.fill(glyphCount, 0);
            unicodeBlockNames = new ArrayList<Character.UnicodeBlock>();
            unicodeScripts = new ArrayList<Character.UnicodeScript>();
        }

        @Override
        protected Void doInBackground() throws Exception {
            for (int kk = 0; kk < pS; kk++) {
                if (kk % 500 == 0) {
                    progressBar.setValue(kk);
                }
                doForEveryCodePoint(kk);
            }
            progressBar.setValue(0);
            return null;
        }

        @Override
        public void done() {
            try {
                get();
                output.setText("Done!");
            } catch (Exception ex) {
                ex.printStackTrace();
                output.setText("Bad: " + ex.getMessage());
            }
        }

        private final void doForEveryCodePoint(final int codePoint) {
            Character.UnicodeBlock block = Character.UnicodeBlock.of(codePoint);
            if (block != null && !unicodeBlockNames.contains(block)) {
                unicodeBlockNames.add(block);
            }

            Character.UnicodeScript us = Character.UnicodeScript.of(codePoint);
            if (us == null || us.toString() == null) {
            } else {
                if (!unicodeScripts.contains(us)) {
                    unicodeScripts.add(us);
                }
            }

            // fonts - test for points in all 6 defined blocks.
            for (int ii = 0; ii < fontNameArray.length; ii++) {
                Font f = new Font(fontNameArray[ii], Font.PLAIN, 16);
                if (f.canDisplay(codePoint)) {
                    glyphCount[ii]++;
                }
            }
        }
    }

    public SwingWorkerUnicodeTest(String[] names) {
        JPanel gui = new JPanel(new BorderLayout());

        gui.add(progressBar, BorderLayout.CENTER);
        gui.add(output, BorderLayout.PAGE_END);

        CodePointDetailWorker cpdw = new CodePointDetailWorker(names);
        cpdw.execute();

        JOptionPane.showMessageDialog(null, gui);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {

                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                String[] fontNames = ge.getAvailableFontFamilyNames();
                new SwingWorkerUnicodeTest(fontNames);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}
Was it helpful?

Solution

There is, likely, an Exception being thrown within the doInBackground method, which is, obviously, causing it to exit.

In your done method, even if it returns nothing, you should call get to ensure that nothing went wrong during the execution of the doInBackground method

@Override
public void done() {
    try {
        get();
        output.setText("Done!");
    } catch (InterruptedException | ExecutionException ex) {
        ex.printStackTrace();
        output.setText("Bad: " + ex.getMessage());
    }
}

OTHER TIPS

You're not initializing your ArrayLists

public CodePointDetailWorker() {
    unicodeBlockNames = new ArrayList<>();
    unicodeScripts = new ArrayList<>();
    ...
}

so a NPE is silently being thrown in the SwingWorker once this statement is encountered

if (block != null && !unicodeBlockNames.contains(block)) {
                       ^---null
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top