当前位置: 首页 > 知识库问答 >
问题:

通过玻璃窗锁定解锁后,Swing进入等待状态

乌甫
2023-03-14

我遇到了一个奇怪的情况。在某些情况下(非活动超时),我必须锁定我的swing窗口(以及任何子窗口),在通过有效凭据再次解锁后,我需要重新解锁它们。

我正在使用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显式设置为空
  3. 不做任何听众的事

所有这些都无济于事,形势依然严峻。

任何人都有过同样的经历,能给我一些建议吗?

我的一个限制是我不能离开glasspane方法,为了保持应用程序之间的一致性,我必须使用它。所以我只能让它工作,别无选择。

更新

@垃圾上帝,我已经把线程转储了,不幸的是无法连接它。我需要调查什么?最后三行是“VM线程”prio=10 tid=0x28688000 nid=0x5e58 runnable

"VM定期任务线程"prio=10 tid=0x28721c00 nid=0x2bc0等待条件

JNI全球参考文献:19887

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

我如何在线程转储上接受帮助。我没有通过SO,在这里超过了char限制。

共有1个答案

凌永逸
2023-03-14

我解决了这个问题。

这个答案对我帮助很大。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() {
};

我还收集了threaddumps,并按照@trashgood的说法对其进行了分析。我发现这也是正确的,嗯,没有什么阻碍/错误。虽然是的,但AWTEventQueue-0始终处于同一个代码点。

 类似资料:
  • 问题内容: 我正在使用Hibernate,试图模拟2个并发更新到数据库中的同一行。 编辑:我将em1.getTransaction()。commit移到em1.flush()之后;我没有收到任何StaleObjectException,两个事务已成功提交。 我在上遇到以下异常。为什么? 问题答案: 好吧,您正试图陷入僵局,并且成功了:-) Transaction1开始,与您的实体更新(和锁定)行。

  • 问题内容: 以下代码取自的JavaDoc: 想象一下, 消费者 和 生产者这 两个线程,一个正在使用,一个在单个实例上。 假设 消费者 先运行,然后锁定,然后循环运行。 现在, 生产者 如何才能通过锁定已由 消费者 持有的来进入方法? 我在这里想念什么?是线程正在等待其条件之一时“临时释放”吗?锁的重新 进入 到底意味着什么? 问题答案: 双方并允许一个线程等待的时候,另一个线程可以获得锁放弃锁。

  • 我使用一个restendpoint来启动一个java进程,使用executeWithLock,它接收一个LockingTaskExecutor。TaskWithResult(TaskWithResult的调用方法调用java进程/方法)。这很好,它只允许在任何时间点执行java进程,我可以从TaskResult获得执行状态。在某些情况下,java进程长时间运行,而rest调用在进程仍在执行时暂停,

  • 在我的Rails 4应用程序中,我有一个对Postgres 9.4数据库的查询: 很受这个相关回答的启发dba.SE. 我只想让我的查询找到并更新第一行(随机地,用< code>LIMIT),其中< code>available = true并将其更新为< code>available = false,我需要在执行此操作的同时锁定该行,但不需要发出新的请求来等待前一个锁的释放,因为有许多并发调用将

  • 问题内容: 在我的Rails 4应用程序中,我将查询查询到Postgres 9.4 数据库: dba.SE上的相关答案极大地启发了我们。 我只希望查询在其中找到并更新第一行(并将其随机更新为),然后将其更新为,而我需要在执行此操作时锁定该行,但无需发出新的请求来等待释放先前的锁,因为许多将使用此查询的 并发调用 。 但我也看到了选择。我不确定我是否理解使用和选项之间的区别,在我看来它们似乎可以实现

  • 我正在编写一个应用程序来管理或自定义Android设备的解锁屏幕。它的工作原理如下: 用户使用电源按钮锁定屏幕。 用户尝试解锁屏幕,从而再次按下电源按钮 我的活动弹出--屏幕仍然锁定 用户回答问题,如果答案正确,屏幕解锁 我已经为第三步创建了一个活动,并将以下代码添加到其方法中: 这工作正常,完全符合我的期望。我的问题是第四步。我已经搜索并找到了许多解决方案,但没有一个适合我。 如何以编程方式锁定