我有一个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);
}
}
答案 0 :(得分:0)
这是我想出的。它并不完美,但能胜任。回想一下,我有一个JFrame
,我需要一个模态SWT Shell
,表现得像一个模态JDialog
。
启动的Shell
无法存在于AWT事件派发线程中。我们需要访问该线程以便稍后拦截鼠标和窗口事件。因此,请在新的Shell
Thread
我GlassPane
在JFrame
打开时放置了Shell
。目的是阻止框架中的其他交互式Swing组件及其容器并拦截所有鼠标事件。我需要鼠标事件,所以我不能简单地做Frame.setEnabled(false)
。
我在框架上使用WindowListener
,MouseListener
上使用了GlassPane
我在DisposeListener
上使用了Shell
来检测JFrame
必须丢失GlassPane
的时刻以及Shell
所做的其他修改{ {1}}现场直播。
要使用我的Swing侦听器控制Shell
的可见性,我需要访问SWT事件线程。这是通过Runnable
执行{{{}}来完成的。 1}}
这是我启动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