来自AWT JFrame的真正的应用程序模态SWT shell

时间:2015-08-13 09:09:22

标签: java swing shell swt awt

我有一个Java Swing应用程序,我正在为它嵌入一个SWT小部件。我尝试在AWT Shell中显示SWT JFrame,但无法使其成为应用模式。 JFrame仍然可以聚焦,按钮点击将注册到EDT。我采取了哪些步骤使Shell表现得像模态AWT对话框?

我已阅读this outdated tutorial但它只解释了如果应用程序在SWT事件线程上运行,该怎么做。我也尝试使用模态JDialog来破解它,但这种行为充其量只是丑陋。从最小工作示例中删除注释以演示它。 SWT.ON_TOP本身很麻烦,因为shell会保持在每个窗口的顶部。

This question没有帮助。

SSCE

public class ModalDialogExample extends JFrame {

public ModalDialogExample()
{
    this.setSize(500, 500);
    this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}

public static void main(String[] args)
{
    JFrame frame = new ModalDialogExample();
    JButton button = new JButton("CLick me");
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
//              JDialog modalDialog = new JDialog();
//              modalDialog.setSize(new Dimension(0,0));
//              modalDialog.setModalityType(ModalityType.APPLICATION_MODAL);
            Display display = new Display();
            Shell shell = new Shell(display, SWT.CLOSE | SWT.TITLE | SWT.BORDER | SWT.OK | SWT.ON_TOP | SWT.APPLICATION_MODAL);
            shell.setSize(200,200);
            shell.open();
            shell.forceActive();
//              modalDialog.setVisible(true);
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch())
                    display.sleep();
            }
            display.dispose();
        }
    });
    frame.getContentPane().add(button);
    frame.setVisible(true);
}
}

1 个答案:

答案 0 :(得分:0)

这是我想出的。它并不完美,但能胜任。回想一下,我有一个JFrame,我需要一个模态SWT Shell,表现得像一个模态JDialog

  1. 启动的Shell无法存在于AWT事件派发线程中。我们需要访问该线程以便稍后拦截鼠标和窗口事件。因此,请在新的Shell

  2. 中启动Thread
  3. GlassPaneJFrame打开时放置了Shell。目的是阻止框架中的其他交互式Swing组件及其容器并拦截所有鼠标事件。我需要鼠标事件,所以我不能简单地做Frame.setEnabled(false)

  4. 我在框架上使用WindowListenerMouseListener上使用了GlassPane

  5. 我在DisposeListener上使用了Shell来检测JFrame必须丢失GlassPane的时刻以及Shell所做的其他修改{ {1}}现场直播。

  6. 要使用我的Swing侦听器控制Shell的可见性,我需要访问SWT事件线程。这是通过Runnable执行{{{}}来完成的。 1}}

  7. 这是我启动shell.getDisplay().syncExec(...),激活Shell,附加"模态听众"并在GlassPane关闭时删除它们。 Shell在新线程中启动。

    Shell

    这是new Thread(new Runnable() { @Override public void run() { final Shell shell = myWidget.getShell(); final EditorWindowListener ewl = new EditorWindowListener(shell); myFrame.addWindowListener(ewl); final EditorClickListener ecl = new EditorClickListener(shell); myFrame.getGlassPane().addMouseListener(ecl); myFrame.getGlassPane().setVisible(true); shell.addDisposeListener(new DisposeListener() { //Remove the disabled status @Override public void widgetDisposed(DisposeEvent arg0) { myFrame.removeWindowListener(ewl); myFrame.getGlassPane().removeMouseListener(ecl); myFrame.getGlassPane().setVisible(false); } }); //The method that starts the shell myWidget.show(); } }).start(); 中发生的事情(标准SWT内容,无需修改)

    myWidget.show()

    以下是我添加到框架和glassPane的两个监听器。首先检测玻璃窗格点击的shell.open(); shell.forceActive(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); ,如果发现任何事件,将MouseListener置于顶部。我知道在一个完美的模态对话框中不需要这个,并且在这种情况下大多数情况下都不需要,但是一些双监视器设置导致了这个监听器解决的问题。

    Shell

    然后class EditorClickListener extends MouseAdapter { private Shell shell; public EditorClickListener(Shell s) { this.shell = s; } @Override public void mouseClicked(MouseEvent e) { shellToFront(shell); } } 附加到框架。它确保框架处于活动状态时,外壳会跳到顶部。

    WindowListener

    最后通过弹出贝壳的方法来创造一种模态感。请注意,需要在SWT事件线程中分配所有事件。将最小化状态设置为class EditorWindowListener extends WindowAdapter { Shell shell; public EditorWindowListener(Shell s) { this.shell = s; } @Override public void windowOpened(WindowEvent e) { shellToFront(shell); } @Override public void windowDeiconified(WindowEvent e) { shellToFront(shell); } @Override public void windowActivated(WindowEvent e) { //Set the shell on top of the frame //Fixes some problems with dual monitor setups. final java.awt.Point framePoint = myFrame.getLocation(); shellToFront(shell); shell.getDisplay().syncExec(new Runnable() { @Override public void run() { shell.setMinimized(false); shell.setActive(); org.eclipse.swt.graphics.Point shellPoint = aikataulu.getLocation(); shellPoint.x = (int) framePoint.getX(); shellPoint.y = (int) framePoint.getY(); shell.setLocation(shellPoint); } }); } } 时遇到了一些麻烦。所以我必须添加一个人工最小化,以防false没有被最小化,并且确实落后于其他窗口。这导致在某些用例中出现了一个愚蠢的不必要的动画,但是现在它将完成

    Shell