Swing переходит в состояние ожидания после блокировки разблокировки через стекло

Я испытываю странную ситуацию. При некотором условии (тайм-аут бездействия) я должен заблокировать свое качающееся окно (и любые подокна), и после повторной разблокировки с помощью действительных учетных данных мне нужно разблокировать их все обратно.

Я использую стеклянное стекло, и мои две функции приведены ниже.

Модуль главного замка

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. установка стекла на нуль явно
  3. не делать никаких вещей для прослушивания

Все это безрезультатно, ситуация остается безрадостной.

Кто-нибудь сталкивался с подобным, подскажите, пожалуйста?

У меня есть одно ограничение: я не могу отказаться от метода стеклянного стекла, чтобы поддерживать однородность между приложениями, которые я должен использовать. Поэтому я должен заставить это работать, без альтернатив.

ОБНОВЛЕНИЕ

@trashgod Я взял дамп темы, к сожалению, не смог его прикрепить. Что мне нужно, чтобы изучить это? Последние три строки: "VM Thread" prio=10 tid=0x28688000 nid=0x5e58 runnable

«Поток периодических задач VM» prio=10 tid=0x28721c00 nid=0x2bc0 ожидание по условию

Глобальные ссылки JNI: 19887

Любая помощь в этом? На что мне смотреть? "Поток периодических задач VM" ?? некоторые конкретные состояния, которые?

Как я могу получить помощь по дампу потока. Я блв не через SO, здесь превышение лимита символов.


person manocha_ak    schedule 06.12.2013    source источник
comment
цикл внутри Window[] wins = Window.getWindows();, проверить, не является ли оно нулевым, isDisplayable, забыл для ZOO с подокнами, удалить, заблокировать выполнение этого кода, виртуальный -100 для вопроса такого характера   -  person mKorbel    schedule 06.12.2013
comment
справочный код в форме SSCCE Удалить контейнер верхнего уровня во время выполнения   -  person mKorbel    schedule 06.12.2013
comment
следует за этой веткой   -  person mKorbel    schedule 06.12.2013
comment
Я на самом деле не понял, что вы имеете в виду здесь. нить кажется на чем-то другом?   -  person manocha_ak    schedule 06.12.2013
comment
@mKorbel предлагает вам искать ошибочные нарушения EDT или заблокированные потоки в вашем коде.   -  person trashgod    schedule 06.12.2013
comment
@manocha_ak мой sscce посвящен тому, как получить все зарегистрированные контейнеры верхнего уровня из текущей JVM, возможно, в вашем случае существует не только одна JVM (тогда ваша проблема), тогда невозможно ответить на ваш вопрос, отсутствует ваш вопрос (s) для конкретного метода или API, ваш вопрос о том, кто-то кодирует аналогичный проект, закончился с аналогичным исключением, а не я, нет, вы, вероятно, потеряли два-три массива, содержащие одни и те же вещи, используйте только один, по запросу   -  person mKorbel    schedule 06.12.2013
comment
@trashgod Я обновил вопрос, получил трассировку стека, не могли бы вы взглянуть   -  person manocha_ak    schedule 06.12.2013
comment
@mKorbel да, у меня есть только один jvm, так что вот чем он отличается, если вы говорите о нескольких ... трассировка стека у меня все еще есть, как сказал трэшбог, можете помочь в этом?   -  person manocha_ak    schedule 06.12.2013
comment
нет, я не сомневаюсь, вы можете поиграть с (создать 10 экземпляров и зациклить внутри массива JFrames) 1. мой как Window[] выигрывает = Window.getWindows(); 2. а затем, чтобы проверить свой способ, вы можете программно скрыть/показать GlassPanes   -  person mKorbel    schedule 06.12.2013
comment
Извините, без понятия; вы можете сравнить своего делегата мыши с делегатом в примере, приведенном здесь.   -  person trashgod    schedule 06.12.2013


Ответы (1)


Я решил проблему.

Этот ответ мне очень помог. 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 всегда был в одной и той же кодовой точке.

person manocha_ak    schedule 12.12.2013