[英]How can I block a JComponent from another class?
I am trying to disable a JComponent
from another class, similar to a modal dialogue. 我试图从另一个类禁用JComponent
,类似于模式对话框。 In my case, I'm invoking a JavaFX dialogue from a Swing component; 就我而言,我正在从Swing组件调用JavaFX对话。 more specifically a FileChooser
. 更具体地说是FileChooser
。 Since, for example, showOpenDialog
expects an javafx.stage.Window
as argument, passing the JComponent
is not an option. 例如,由于showOpenDialog
希望将javafx.stage.Window
作为参数,因此不能选择传递JComponent
。
I tried using setEnabled(false)
and setEnabled(true)
, but this has a strange side effect: Upon invoking setEnabled(true)
, the JFrame
will be minimized. 我尝试使用setEnabled(false)
和setEnabled(true)
,但这有一个奇怪的副作用:调用setEnabled(true)
, JFrame
将被最小化。 Invoking setVisible(true)
solves this but causes the screen to “flash”, because the frame will still disappear for a short time. 调用setVisible(true)
可以解决此问题,但会导致屏幕“闪烁”,因为框架仍会在短时间内消失。
The problem only occurs when I'm using a CountDownLatch
to await the return of the file chooser, which is necessary because otherwise it would return immediately and I wouldn't be able to access the return value. 仅当我使用CountDownLatch
等待文件选择器的返回时,才会发生此问题,这是必需的,因为否则它将立即返回,并且我将无法访问返回值。
Here is a SSCCE to reproduce the issue: 这是SSCCE来重现该问题:
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame("Test");
JButton button = new JButton("Click me!");
JFXPanel jfxPanel = new JFXPanel();
FileChooser fileChooser = new FileChooser();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.setEnabled(false);
CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(() -> {
fileChooser.showOpenDialog(null);
latch.countDown();
});
try {
latch.await();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
frame.setEnabled(true);
}
});
frame.add(button);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
});
}
Is there another option to block the component? 还有其他阻止组件的选项吗?
My answer is based on this article https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html 我的答案基于本文https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html
The idea is that when FileChooser
is opened we use custom GlassPane
that intercepts all mouse events. 这个想法是,当FileChooser
打开时,我们使用自定义的GlassPane
来拦截所有鼠标事件。 It's not ideal solution, because you can still minimize, maximize and close underlying JFrame
. 这不是理想的解决方案,因为您仍然可以最小化,最大化和关闭底层JFrame
。
public class MyGlassPane extends JComponent implements PropertyChangeListener {
public MyGlassPane() {
CBListener listener = new CBListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
setVisible(((Number) evt.getNewValue()).intValue() == 1);
}
}
public class CBListener extends MouseInputAdapter {
public void mouseMoved(MouseEvent e) {
consume(e);
}
public void mouseDragged(MouseEvent e) {
consume(e);
}
public void mouseClicked(MouseEvent e) {
consume(e);
}
public void mouseEntered(MouseEvent e) {
consume(e);
}
public void mouseExited(MouseEvent e) {
consume(e);
}
public void mousePressed(MouseEvent e) {
consume(e);
}
public void mouseReleased(MouseEvent e) {
consume(e);
}
private void consume(MouseEvent e) {
e.consume();
}
}
With above classes you can put below FileChooser fileChooser = new FileChooser();
通过上述类,您可以在FileChooser fileChooser = new FileChooser();
line code like this: 像这样的行代码:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.firePropertyChange("disabled", 0, 1);
Platform.runLater(() -> {
fileChooser.showOpenDialog(null);
frame.firePropertyChange("disabled", 1, 0);
});
}
});
MyGlassPane mgp = new MyGlassPane();
frame.setGlassPane(mgp);
frame.addPropertyChangeListener("disabled", mgp);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.