0

我正在经历一个奇怪的情况。在某些情况下(不活动超时),我必须锁定我的摆动窗口(和任何子窗口),并且在通过有效凭据再次解锁后,我需要将它们全部解锁。

我正在使用 glasspane 敌人,我的两个功能如下

主锁模块

public void lock(boolean minimize) {
    if (!locked) {
        locked = true;
        lockMinimized = minimize;
        logger.debug(context + "Locking Target...");
        // Lock all frames using the AWT event dispatching thread.
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                Frame[] frames = Frame.getFrames();
                Window[] subwindows;
                for (Frame frame : frames) {
                    // Lock the frame itself
                    lockWindow(frame);

                    // Lock subwindows owned by the frame
                    subwindows = frame.getOwnedWindows();
                    for (Window subwindow : subwindows) {
                        if (subwindow instanceof RootPaneContainer) {
                            lockWindow(subwindow);
                        }
                    }
                }
                //do additional stuff - lock out of process windows
                if (lockUnlockInterface != null) {
                    logger.info("calling locking for out of jvm process ");
                    lockUnlockInterface.lock();
                }
            }
        });
        logger.debug(context + "Target locked.");
    }
}

分锁方式

private void lockWindow(final Window window) {
    logger.debug(context + "Locking window: " + window.getClass().toString());
    Vector exemptWindowClassNames = getExemptList();
    if (window instanceof RootPaneContainer
            && ((RootPaneContainer) window).getRootPane() != null
            && !lockedWindows.containsKey(window)
            && !(exemptWindowClassNames.contains(window.getClass().toString()))) {
        logger.debug(context + "Locking window...");
        try {
            // Create an object to store original details for the locked window.
            LockedWindow lockedWindow = new LockedWindow();
            lockedWindows.put((RootPaneContainer) window, lockedWindow);

            // Remember the original glass pane and visibility before locking.
            lockedWindow.originalGlassPane = ((RootPaneContainer) window).getGlassPane();
            lockedWindow.wasVisible = ((RootPaneContainer) window).getContentPane().isVisible();

            // Add a LockedGlassPane to the window.
            LockedGlassPane lgp = new LockedGlassPane();
            lgp.setVisible(true); //hide the contents of the window
            ((RootPaneContainer) window).setGlassPane(lgp);
            ((RootPaneContainer) window).getContentPane().setVisible(false);
            lgp.setVisible(true); //redisplays the lock message after set as glassPane.
            ((RootPaneContainer) window).getContentPane().invalidate();

            // Minimize the window (if requested), while keeping a record of
            // which windows have been minimized so that they can be restored
            // later when the TimeoutTarget is unlocked.
            if (window instanceof Frame) {
                Frame frame = (Frame) window;
                // Remember the original minimized state of the window.
                lockedWindow.minimized = (frame.getExtendedState() & Frame.ICONIFIED) != 0;
                if (lockMinimized) {
                    frame.setExtendedState(Frame.ICONIFIED);
                }
            }

            //
            //Note required now, but keeping in case the requirement changes again.
            //
            // Prevent the window from being closed while this target is
            // locked.
            // lockedWindow.windowListeners = window.getWindowListeners();
            //  for (WindowListener wl : lockedWindow.windowListeners) {
            //     window.removeWindowListener(wl);
            // }
            //if (window instanceof JFrame) {
            // JFrame jframe = (JFrame) window;
            // lockedWindow.originalDefaultCloseOperation = jframe.getDefaultCloseOperation();
            // jframe.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
            //} else if (window instanceof JDialog) {
            //  JDialog jdialog = (JDialog) window;
            // lockedWindow.originalDefaultCloseOperation = jdialog.getDefaultCloseOperation();
            // jdialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
            //}
        } catch (Exception e) {
            logger.error(context + "Failed to lock window.", e);
        }
    }
    if (exemptWindowClassNames.contains(window.getClass().toString())) {
        window.toFront();
    }
}

解锁主要方法

公共无效解锁(){锁定=假;锁定最小化 = 假;

    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            Window[] subwindows;
            for (RootPaneContainer window : lockedWindows.keySet()) {
                // Unlock the frame itself.
                unlockWindow(window);

                // Unlock subwindows owned by the frame.
                if (window instanceof Frame) {
                    subwindows = ((Frame) window).getOwnedWindows();
                    for (Window subwindow : subwindows) {
                        if (subwindow instanceof RootPaneContainer) {
                            unlockWindow((RootPaneContainer) subwindow);
                        }
                    }
                }
            }

            lockedWindows.clear();

          //do additional stuff - lock out of process windows
            if (lockUnlockInterface != null) {
                logger.info("calling unlocking for out of jvm process ");
                lockUnlockInterface.unlock();
            }
        }
    });
}

子解锁方法

private void unlockWindow(RootPaneContainer window) {
    try {
        LockedWindow lockedWindow = lockedWindows.get(window);
        logger.debug(context + "Unlocking window: " + window);
        if (lockedWindow != null) {
            logger.debug(context + "Unlocking...");
            // Restore the original glasspane for the window
            if (lockedWindow.originalGlassPane != null) {
                logger.debug(context + "Reset original glass pane.");
                window.setGlassPane(lockedWindow.originalGlassPane);
            }
            //make content pane visible again.
            (window).getContentPane().setVisible(lockedWindow.wasVisible);
            (window).getRootPane().invalidate();

            // Restore (un-minimize) the window if it wasn't minimized before
            // the lock.
            if (!lockedWindow.minimized && window instanceof Frame) {
                ((Frame) window).setExtendedState(((Frame) window).getExtendedState()
                        & ~Frame.ICONIFIED);
            }
            // Restore the original default close operation from before the
            // lock, which will normally allow the window to be closed.
            if (window instanceof Window) {
                if (lockedWindow.windowListeners != null) {
                    for (WindowListener wl : lockedWindow.windowListeners) {
                        ((Window) window).addWindowListener(wl);
                    }
                }
                if (window instanceof JFrame) {
                    ((JFrame) window)
                            .setDefaultCloseOperation(lockedWindow.originalDefaultCloseOperation);
                } else if (window instanceof JDialog) {
                    ((JDialog) window)
                            .setDefaultCloseOperation(lockedWindow.originalDefaultCloseOperation);
                }
            }
            logger.debug(context + "Window has been unlocked");
        }
    } catch (Exception e) {
        logger.error(context + "Failed to unlock window.", e);
    }

}

只是再次重复我的锁定和解锁确实成功发生。解锁不成功,因为解锁后我的解锁窗口上仍然有一个忙碌的光标。它和消失一样好。无用。

我从日志中看到我成功地从解锁呼叫中退出。然后我不知道帽子会导致那个忙碌的光标出现并阻止我窗口上的任何东西。

我也有这些日志,它们很好

我不确定是什么原因造成的呢?

可能的罪魁祸首和我尝试过的事情

  1. 在锁定解锁时不做无效
  2. 将 glasspane 显式设置为 null
  3. 不做任何听众的事情

所有这些都无济于事,形势依然惨淡。

有谁有过同样的经历,可以指点一下吗?

我的一个限制是我不能离开玻璃板方法,为了保持应用程序之间的同质性,我必须使用它。所以我必须让这个工作,没有其他选择。

更新

@trashgod 我已经采取了线程转储不幸的是无法附加它。我需要调查什么?最后三行是“VM Thread”prio=10 tid=0x28688000 nid=0x5e58 runnable

“VM 周期性任务线程”prio=10 tid=0x28721c00 nid=0x2bc0 等待条件

JNI 全球参考:19887

对此有什么帮助吗?我应该看什么?“VM 周期性任务线程” ?? 一些具体的州是哪一个?

我如何获得有关线程转储的帮助。我没有通过 SO,在这里超过了字符限制。

4

1 回答 1

0

我解决了这个问题。

这个答案对我帮助很大。java swing清除事件队列事实上关键概念是相同的。

所以对于代码部分,我修改了模块

锁窗

private void lockWindow(final Window window) {
    if (window instanceof RootPaneContainer
            && ((RootPaneContainer) window).getRootPane() != null
            && !lockedWindows.containsKey(window)) {
        java.util.Timer timer = null;
        try {

            //don't do invalidate, invalidate as the first step
            //((RootPaneContainer) window).getContentPane().invalidate();

            // Create an object to store original details for the locked window.
            LockedWindow lockedWindow = new LockedWindow();
            lockedWindows.put((RootPaneContainer) window, lockedWindow);

            lockedWindow.originalGlassPane = ((RootPaneContainer) window).getGlassPane();


            //okk may be glasspane only in integrated scenario is causing the issue
            //comment it and check, we are still putting it in the map  above but its doing nothing
            /*
            // Remember the original glass pane and visibility before locking.

            //okk is this the only issue? What should be the originalGlassPane first time? null?
            lockedWindow.originalGlassPane = ((RootPaneContainer) window).getGlassPane();
            System.err.println("Original galss pane : " + ((RootPaneContainer) window).getGlassPane());

            lockedWindow.wasVisible = ((RootPaneContainer) window).getContentPane().isVisible();

            // Add a LockedGlassPane to the window.
            LockedGlassPane lgp = new LockedGlassPane();
            lgp.setVisible(true); //hide the contents of the window
            ((RootPaneContainer) window).setGlassPane(lgp);

            //don't do this stuff too
            ((RootPaneContainer) window).getContentPane().setVisible(false);

            lgp.setVisible(true); //redisplays the lock message after set as glassPane.
            */
            LockedGlassPane lgp = new LockedGlassPane();
            ((RootPaneContainer) window).setGlassPane(lgp);
            timer = switchToBusyCursor(window);

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                //do nothing
                System.err.println("Am I interrupted?");
            }
            //okk the above thing worked, it doesnt lock naturlly, now try if setting visible code is an issue?
            //great this thing works so this also is not an issue, only galsspane in SiteManager is
            lockedWindow.wasVisible = ((RootPaneContainer) window).getContentPane().isVisible();

            ((RootPaneContainer) window).getContentPane().repaint();

            // Minimize the window (if requested), while keeping a record of
            // which windows have been minimized so that they can be restored
            // later when the TimeoutTarget is unlocked.

          //don't do this stuff too - as unlock is not working investigating that
            if (window instanceof Frame) {
                Frame frame = (Frame) window;
                // Remember the original minimized state of the window.
                lockedWindow.minimized = (frame.getExtendedState() & Frame.ICONIFIED) != 0;
                if (lockMinimized) {
                    frame.setExtendedState(Frame.ICONIFIED);
                }
            }

            //
            //Note required now, but keeping in case the requirement changes again.
            //
            // Prevent the window from being closed while this target is
            // locked.
            // lockedWindow.windowListeners = window.getWindowListeners();
            //  for (WindowListener wl : lockedWindow.windowListeners) {
            //     window.removeWindowListener(wl);
            // }
            //if (window instanceof JFrame) {
            // JFrame jframe = (JFrame) window;
            // lockedWindow.originalDefaultCloseOperation = jframe.getDefaultCloseOperation();
            // jframe.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
            //} else if (window instanceof JDialog) {
            //  JDialog jdialog = (JDialog) window;
            // lockedWindow.originalDefaultCloseOperation = jdialog.getDefaultCloseOperation();
            // jdialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
            //}
        } catch (Exception e) {
            System.err.println(getThreadPrefix()  + " Failed to lock window." + e.getLocalizedMessage());
        } finally {
            switchToNormalCursorEventThread(window, timer);
        }
    }        
}

解锁窗口

private void unlockWindow(RootPaneContainer window) {
    try {
        LockedWindow lockedWindow = lockedWindows.get(window);
        //System.err.println(getThreadPrefix()  + " Unlocking window::: " + lockeWindow.isDisplayable());
        if (lockedWindow != null && ((Frame) window).isDisplayable()) {
            System.err.println(getThreadPrefix() + "Unlocking..." + lockedWindow);
            // Restore the original glasspane for the window

            //okk may be glasspane only in integrated scenario is causing the issue
            //comment it and check, we are still putting it in the map  above but its doing nothing


            //okk is this the only issue? What should be the originalGlassPane first time? null?
            if (lockedWindow.originalGlassPane != null) {
                System.err.println(getThreadPrefix() + "Reset original glass pane.");
                window.setGlassPane(lockedWindow.originalGlassPane);
                //lockedWindow.originalGlassPane.setVisible(true);
            }


            //make content pane visible again.
            //(window).getContentPane().setVisible(lockedWindow.wasVisible);

            //okk try this
            //(window).getContentPane().setVisible(true);
            //(window).getRootPane().invalidate();

            //okk the above thing worked, it doesnt lock naturlly, now try if setting visible code is an issue?
            //great this thing works so this also is not an issue
            (window).getContentPane().setVisible(lockedWindow.wasVisible);

            (window).getRootPane().repaint();

            // Restore (un-minimize) the window if it wasn't minimized before
            // the lock.
            //do this tuff anyways
            if (!lockedWindow.minimized && window instanceof Frame) {
                ((Frame) window).setExtendedState(((Frame) window).getExtendedState()
                        & ~Frame.ICONIFIED);
            }


            // Restore the original default close operation from before the
            // lock, which will normally allow the window to be closed.

            //dont do listeneres??
            if (window instanceof Window) {
                if (lockedWindow.windowListeners != null) {
                    for (WindowListener wl : lockedWindow.windowListeners) {
                        System.err.print("windowlistener is not null " + wl);
                        ((Window) window).addWindowListener(wl);
                    }
                }
                if (window instanceof JFrame) {
                    ((JFrame) window)
                            .setDefaultCloseOperation(lockedWindow.originalDefaultCloseOperation);
                } else if (window instanceof JDialog) {
                    ((JDialog) window)
                            .setDefaultCloseOperation(lockedWindow.originalDefaultCloseOperation);
                } 
            }

            //try this too
            //((RootPaneContainer)window).setGlassPane(null);

            //lockedWindows.remove(window);
          //stopEventTrap
            stopEventTrap((Frame)window);
            System.err.println(getThreadPrefix()  + " Window has been unlocked");
        }
    } catch (Exception e) {
        System.err.println(getThreadPrefix()  + " Failed to unlock window. " + e.getLocalizedMessage());
    }

}

添加了从上述答案中获取的这些新方法,并根据我的用例进行了修改

public static java.util.Timer switchToBusyCursor(final Window frame) {
    startEventTrap(frame);
    java.util.TimerTask timerTask = new java.util.TimerTask() {

        public void run() {
            startWaitCursor(frame);
        }

    };
    final java.util.Timer timer = new java.util.Timer();
    timer.schedule(timerTask, DELAY_MS);
    return timer;
}

public static void switchToNormalCursorEventThread(final Window window, final java.util.Timer timer) {

    Runnable r = new Runnable() {

        public void run() {
            switchToNormalCursor(window, timer);
        }

    };

    javax.swing.SwingUtilities.invokeLater(r);

}

public static void switchToNormalCursor(final Window window, final java.util.Timer timer) {
    timer.cancel();
    stopWaitCursor(window);
    //stopEventTrap(window);
}

private static void startWaitCursor(Window window) {
    ((RootPaneContainer) window).getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
    ((RootPaneContainer) window).getGlassPane().addMouseListener(mouseAdapter);
    ((RootPaneContainer) window).getGlassPane().setVisible(true);
}

private static void stopWaitCursor(Window window) {
    ((RootPaneContainer) window).getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
    //((RootPaneContainer) window).getGlassPane().removeMouseListener(mouseAdapter);
    //((RootPaneContainer) window).getGlassPane().setVisible(false);
}

private static void startEventTrap(Window window) {
    ((RootPaneContainer) window).getGlassPane().addMouseListener(mouseAdapter);
    ((RootPaneContainer) window).getGlassPane().setVisible(true);
}

private static void stopEventTrap(Window window) {
    java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
    ((RootPaneContainer) window).getGlassPane().removeMouseListener(mouseAdapter);
    ((RootPaneContainer) window).getGlassPane().setVisible(false);
}

private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {
};

正如@trashgod 所说,我还采取了线程转储并对其进行了分析。我发现这也是正确的,恕我直言,那里没有任何阻塞/错误。虽然是的,但 AWTEventQueue-0 始终位于同一代码点。

于 2013-12-12T06:43:38.207 回答