Asked  6 Months ago    Answers:  5   Viewed   83 times

In connection with my question (may be), I found another exception type that I not able to catch and print-out from SwingWorker thread.

How can I to generate RepaintManager exceptions?

I read this CheckThreadViolationRepaintManager and this approach by Alexander Potochkin, but nothing seems to solve my issues.

 Answers

30

If it helps, the example below throws prints multiple variations of the following Exception, mostly for each phase of the frame's UI delegate initialization. I used CheckThreadViolationRepaintManager, but the AspectJ variation looks interesting, too.

java.lang.Exception
    at EDTViolation$CheckThreadViolationRepaintManager.checkThreadViolations(EDTViolation.java:43)
    at EDTViolation$CheckThreadViolationRepaintManager.addDirtyRegion(EDTViolation.java:37)
    at javax.swing.JComponent.repaint(JComponent.java:4734)
    at java.awt.Component.repaint(Component.java:3168)
    at javax.swing.JComponent.setFont(JComponent.java:2727)
    at javax.swing.LookAndFeel.installColorsAndFont(LookAndFeel.java:191)
    at javax.swing.plaf.basic.BasicPanelUI.installDefaults(BasicPanelUI.java:49)
    at javax.swing.plaf.basic.BasicPanelUI.installUI(BasicPanelUI.java:39)
    at javax.swing.JComponent.setUI(JComponent.java:662)
    at javax.swing.JPanel.setUI(JPanel.java:136)
    at javax.swing.JPanel.updateUI(JPanel.java:109)
    at javax.swing.JPanel.(JPanel.java:69)
    at javax.swing.JPanel.(JPanel.java:92)
    at javax.swing.JPanel.(JPanel.java:100)
    at javax.swing.JRootPane.createGlassPane(JRootPane.java:528)
    at javax.swing.JRootPane.(JRootPane.java:348)
    at javax.swing.JFrame.createRootPane(JFrame.java:255)
    at javax.swing.JFrame.frameInit(JFrame.java:236)
    at javax.swing.JFrame.(JFrame.java:159)
    at EDTViolation.main(EDTViolation.java:12)
...
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;

/** @see https://stackoverflow.com/questions/7787998 */
public class EDTViolation {

    public static void main(String args[]) {
        RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }

    private static class CheckThreadViolationRepaintManager extends RepaintManager {
    //http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

        private boolean completeCheck = true;
        private WeakReference<JComponent> lastComponent;

        public CheckThreadViolationRepaintManager(boolean completeCheck) {
            this.completeCheck = completeCheck;
        }

        public CheckThreadViolationRepaintManager() {
            this(true);
        }

        public boolean isCompleteCheck() {
            return completeCheck;
        }

        public void setCompleteCheck(boolean completeCheck) {
            this.completeCheck = completeCheck;
        }

        @Override
        public synchronized void addInvalidComponent(JComponent component) {
            checkThreadViolations(component);
            super.addInvalidComponent(component);
        }

        @Override
        public void addDirtyRegion(JComponent component, int x, int y, int w, int h) {
            checkThreadViolations(component);
            super.addDirtyRegion(component, x, y, w, h);
        }

        private void checkThreadViolations(JComponent c) {
            if (!SwingUtilities.isEventDispatchThread() && (completeCheck || c.isShowing())) {
                boolean repaint = false;
                boolean fromSwing = false;
                boolean imageUpdate = false;
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                for (StackTraceElement st : stackTrace) {
                    if (repaint && st.getClassName().startsWith("javax.swing.")
                        && // for details see 
                        // https://swinghelper.dev.java.net/issues/show_bug.cgi?id=1
                        !st.getClassName().startsWith("javax.swing.SwingWorker")) {
                        fromSwing = true;
                    }
                    if (repaint && "imageUpdate".equals(st.getMethodName())) {
                        imageUpdate = true;
                    }
                    if ("repaint".equals(st.getMethodName())) {
                        repaint = true;
                        fromSwing = false;
                    }
                    if ("read".equals(st.getMethodName()) && "javax.swing.JEditorPane".equals(st.getClassName())) {
                        // Swing reads html from a background thread
                        return;
                    }
                }
                if (imageUpdate) {
                //assuming it is java.awt.image.ImageObserver.imageUpdate(...) 
                    //image was asynchronously updated, that's ok 
                    return;
                }
                if (repaint && !fromSwing) {
                    //no problems here, since repaint() is thread safe
                    return;
                }
                //ignore the last processed component
                if (lastComponent != null && c == lastComponent.get()) {
                    return;
                }
                lastComponent = new WeakReference<JComponent>(c);
                violationFound(c, stackTrace);
            }
        }

        protected void violationFound(JComponent c, StackTraceElement[] stackTrace) {
            System.out.println();
            System.out.println("EDT violation detected");
            System.out.println(c);
            for (StackTraceElement st : stackTrace) {
                System.out.println("tat " + st);
            }
        }
    }
}
Tuesday, June 1, 2021
 
Akarun
answered 6 Months ago
24

If you have access to action's source code, insert a try/catch block in that method; otherwise, create a new tryAction method which wraps the call to action in a try/catch block.

Wednesday, June 23, 2021
 
Crashthatch
answered 6 Months ago
49

Have a look at Project Lombok. It generates code as you ask when you write:

public class MyClass {
  @Getter @Setter private String alias;
}

It also does a lot more if you need it. I know you asked for no external tools, but you would basically be recreating this.

Sunday, August 1, 2021
 
Smandoli
answered 4 Months ago
66

See the 'JavaFX in Swing' tutorial. You are performing JavaFX operations which should run on the JavaFX thread on the Swing thread (Event Dispatch Thread).

Luckily they learnt from their previous mistakes and now throw exceptions when you perform operations on the wrong thread. That is the exception you encountered.

Use the Platform#runLater as shown in that tutorial

Platform.runLater(new Runnable() {
        @Override
        public void run() {
          //javaFX operations should go here
        }
   });

The construction of the JFXPanel can remain on the EDT (which is also illustrated in that tutorial)

Monday, August 2, 2021
 
iteong
answered 4 Months ago
67

Finally I write DIY repaint management class .. :(

import java.awt.event.*;
import java.util.*;

import javax.swing.*;
import javax.swing.Timer;

/**
 * EffectTimer
 */
public class EffectTimer {

    /**
     * All of effect timers in instance of this class.
     */
    static class GlobalTimer implements ActionListener {

        List<EffectTimer> registeredEffects = new ArrayList<>();

        Timer timer = new Timer(16, this);

        public void start(final EffectTimer t) {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    internalStart(t);
                }

            });
        }

        void internalStart(EffectTimer t) {
            int initialDelay = Math.max(0, (int) (t.getEffectStartTime() - System.currentTimeMillis()));
            if(timer.getInitialDelay() >= initialDelay) {
                timer.setInitialDelay(initialDelay);
            }
            if(!registeredEffects.contains(t)) {
                registeredEffects.add(t);
                if(registeredEffects.size() == 1) {
                    timer.start();
                }
            }
        }

        void stop(final EffectTimer t) {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    registeredEffects.remove(t);
                    checkStop();
                }

            });
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            long now = e.getWhen();

            Iterator<EffectTimer> iter = registeredEffects.iterator();
            while(iter.hasNext()) {
                EffectTimer t = iter.next();
                long elapsedMs = now - t.getEffectStartTime();

                if(elapsedMs > 0) {
                    float p = elapsedMs / (float)t.getEffectLengthMs();
                    if(p >= 1.0f) {
                        iter.remove();
                        t.stop();
                    } else {
                        if(t.isReversed()) {
                            p = 1.0f - p;
                        }
                        t.progressChanged(p);
                    }
                }
            }

            checkStop();
        }

        void checkStop() {
            if(registeredEffects.isEmpty()) {
                timer.stop();
            }
        }

        public int getRunningTimerCount() {
            return registeredEffects.size();
        }

        public void stopAll() {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    registeredEffects.clear();
                    checkStop();
                }

            });
        }

    }

    static final GlobalTimer GTIMER = new GlobalTimer();

    int effectLengthMs = -1;

    long effectStartMs = -1;

    float progress = 0.0f;

    boolean reversed = true;

    public long getEffectStartTime() {
        return effectStartMs;
    }

    public int getEffectLengthMs() {
        return effectLengthMs;
    }

    public void start(int lengthMs) {
        start(lengthMs, System.currentTimeMillis());
    }

    public void start(int lengthMs, long startMs) {
        effectLengthMs = lengthMs;
        effectStartMs = startMs;

        reversed = false;
        progress = 0.0f;
        GTIMER.start(this);
    }

    public boolean isReversed() {
        return reversed;
    }

    public void reverse(final int lengthMs) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                internalReverse(lengthMs);
            }

        });
    }

    void internalReverse(int lengthMs) {
        reversed = !reversed;

        effectLengthMs = lengthMs;
        int adjust = reversed ? (int)(lengthMs * (1.0f - progress)) : (int)(lengthMs * progress);
        effectStartMs = System.currentTimeMillis() - adjust;

        GTIMER.start(this);
    }

    final public void progressChanged(float p) {
        progress = p;
        run(p);
    }

    /**
     * 0.0f to 1.0f effect progress.
     * <code>Float.compare(progress, 1.0f) >= 0</code> to end progress.
     */
    protected void run(float p) {}

    public void stop() {
        progress = reversed ? 0.0f : 1.0f;
        GTIMER.stop(this);
    }

    public boolean isRunning() {
        return 0.0f < progress && progress < 1.0f;
    }

    public float getProgress() {
        return progress;
    }

    public static int getRunningTimerCount() {
        return GTIMER.getRunningTimerCount();
    }

    public static void stopAll() {
        GTIMER.stopAll();
    }

}
Thursday, August 19, 2021
 
Wickethewok
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share