Как показать JOptionPane над немодальным JDialog - PullRequest
1 голос
/ 04 июня 2019

Я хочу, чтобы JOptionPane появлялся над немодальными диалогами. Например, в следующем приложении нажмите кнопку JDialog, чтобы отобразить немодальное диалоговое окно, а затем нажмите кнопку JOptionPane, чтобы отобразить диалоговое окно подтверждения JOptionPane. К сожалению, JOptionPane появляется под немодальным диалогом.

В моем реальном приложении у меня есть несколько немодальных JDialogs, и я использую JOptionPane из нескольких разных мест.

Как я могу легко сделать так, чтобы панель JOptionPane отображалась над всеми немодальными экземплярами JDialog? Под «легко» я подразумеваю добавление 1 или 2 строк к каждой немодальной конструкции JDialog или к каждому вызову JOptionPane.

Один из способов, которым я пытался сделать, - создать новый временный JFrame, не имеющий доступа, с опцией Always-on-top в качестве владельца JOptionPane. Это делает JOptionPane сверху, но JOptionPane находится в центре экрана, а не в центре оригинального JFrame, и я беспокоюсь, что пользователь может этого не заметить.

Другой способ, которым я пытался сделать, - сделать все немодальные диалоги невидимыми, прежде чем показывать панель JOptionPane, а затем снова сделать их видимыми. Но этот способ нелегко обойти все вызовы JOptionPane, потому что (я полагаю) для надежной работы требуется блок try-finally.

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;

public class App {
    public static void main(String[] args) {
        JFrame f = new JFrame("App Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton btnDialog = new JButton("JDialog");
        JButton btnOptionPane = new JButton("JOptionPane");

        btnDialog.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JDialog dlg = new JDialog(f, "Modeless Dialog", false);
                dlg.setSize(256, 256);
                dlg.setLocationRelativeTo(f);
                dlg.setVisible(true);
            }
        });

        btnOptionPane.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showConfirmDialog(f, "Confirm JOptionPane");
            }
        });

        f.add(btnDialog, BorderLayout.WEST);
        f.add(btnOptionPane, BorderLayout.EAST);
        f.setSize(512, 512);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

JOptionPane showing under modeless JDialog

Ответы [ 2 ]

2 голосов
/ 04 июня 2019

Попробовав и экспериментировав с идеей @ Sergiy об использовании статических методов Window, я пришел к следующему:

import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.*;

public class App {
    static JFrame hideOwnedWindows(JFrame f) {
        ArrayList<Window> arHidden = new ArrayList();
        WindowAdapter wa = new WindowAdapter() {
            @Override
            public void windowActivated(WindowEvent e) {
                for (Window w : arHidden)
                    w.setVisible(true);
                f.removeWindowListener(this);
            }
        };
        for (Window w : f.getOwnedWindows()) {
            if (w.isVisible()) {
                w.setVisible(false);
                arHidden.add(w);
            }
        }
        f.addWindowListener(wa);
        return f;
    }

    public static void main(String[] args) {
        JFrame f = new JFrame("App Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton btnDialog = new JButton("JDialog");
        JButton btnOptionPane = new JButton("JOptionPane");

        btnDialog.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JDialog dlg = new JDialog(f, "Modeless Dialog", false);
                dlg.setSize(256, 256);
                dlg.setLocationRelativeTo(f);
                dlg.setVisible(true);
            }
        });

        btnOptionPane.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showConfirmDialog(hideOwnedWindows(f), "Confirm JOptionPane");
            }
        });

        f.add(btnDialog, BorderLayout.WEST);
        f.add(btnOptionPane, BorderLayout.EAST);
        f.setSize(512, 512);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

}

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

2 голосов
/ 04 июня 2019

Вам необходимо установить правильный родительский элемент для вашей панели параметров. Чтобы определить это, вы можете использовать список всех открытых окон. В моем примере я использую последнее открытое окно.

import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class App {

    public static void main(String[] args) {
        JFrame f = new JFrame("App Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton btnDialog = new JButton("JDialog");
        JButton btnOptionPane = new JButton("JOptionPane");

        btnDialog.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JDialog dlg = new JDialog(f, "Modeless Dialog", false);
                dlg.setSize(256, 256);
                dlg.setLocationRelativeTo(f);
                dlg.setVisible(true);
            }
        });

        btnOptionPane.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showConfirmDialog(findLatestWindow(), "Confirm JOptionPane");
            }
        });

        f.add(btnDialog, BorderLayout.WEST);
        f.add(btnOptionPane, BorderLayout.EAST);
        f.setSize(512, 512);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static Window findLatestWindow() {
        Window result = null;
        for (Window w : Window.getWindows()) {
            if (w.isVisible()) {
                result = w;
            }
        }
        return result;
    }
}

Если у вас открыто более одного диалогового окна одновременно, и пользователь может переключаться между этими диалоговыми окнами, поэтому вам нужно еще несколько строк кода. Потому что в вашем случае после нажатия кнопки рамка всегда является владельцем фокуса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...