JInternalFrame作为模态

我有以下代码:

import java.awt.AWTEvent; import java.awt.ActiveEvent; import java.awt.Component; import java.awt.EventQueue; import java.awt.MenuComponent; import java.awt.event.MouseEvent; import javax.swing.JInternalFrame; import javax.swing.SwingUtilities; public class modalInternalFrame extends JInternalFrame { // indica si aquest es modal o no. boolean modal = false; @Override public void show() { super.show(); if (this.modal) { startModal(); } } @Override public void setVisible(boolean value) { super.setVisible(value); if (modal) { if (value) { startModal(); } else { stopModal(); } } } private synchronized void startModal() { try { if (SwingUtilities.isEventDispatchThread()) { EventQueue theQueue = getToolkit().getSystemEventQueue(); while (isVisible()) { AWTEvent event = theQueue.getNextEvent(); Object source = event.getSource(); boolean dispatch = true; if (event instanceof MouseEvent) { MouseEvent e = (MouseEvent) event; MouseEvent m = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this); if (!this.contains(m.getPoint()) && e.getID() != MouseEvent.MOUSE_DRAGGED) { dispatch = false; } } if (dispatch) { if (event instanceof ActiveEvent) { ((ActiveEvent) event).dispatch(); } else if (source instanceof Component) { ((Component) source).dispatchEvent( event); } else if (source instanceof MenuComponent) { ((MenuComponent) source).dispatchEvent( event); } else { System.err.println( "Unable to dispatch: " + event); } } } } else { while (isVisible()) { wait(); } } } catch (InterruptedException ignored) { } } private synchronized void stopModal() { notifyAll(); } public void setModal(boolean modal) { this.modal = modal; } public boolean isModal() { return this.modal; } } 

然后我使用NetBeans GUI绘制我的JInternalFrame,但只是更改了类声明中的代码以扩展modalInternalFrame而不是JInternalFrame:

 public class myDialog extends modalInternalFrame { .... 

然后使用它来实际显示它从我的顶级“桌面”JFrame(包含jDesktopPane1):

 myDialog d = new myDialog(); d.setModal(true); d.setBounds(160, 180, 550, 450); jDesktopPane1.add(d); d.setVisible(true); 

我的问题是:如果内部框架有JComboBox或PopupMenu,当PopupMenu的一部分超出内部框架的边界时,该部分不处理鼠标事件(您无法滚动该部分)。

有任何想法吗?

如何使用JOptionPane.showInternalMessageDialog(...)

  • 我在Windows 7 x64上运行JDK 1.7.0_21:
 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class ModalInternalFrameTest { private final JDesktopPane desktop = new JDesktopPane(); private final String[] items = new String[] { "bananas", "pizza", "hot dogs", "ravioli" }; private final Action openAction = new AbstractAction("open") { @Override public void actionPerformed(ActionEvent e) { JComboBox combo = new JComboBox(items); combo.setEditable(true); JOptionPane.showInternalMessageDialog(desktop, combo); System.out.println(combo.getSelectedItem()); } }; public JComponent makeUI(JFrame frame) { frame.setJMenuBar(createMenuBar()); JButton button = new JButton(openAction); button.setMnemonic(KeyEvent.VK_S); JInternalFrame internal = new JInternalFrame("Button"); internal.getContentPane().add(button); internal.setBounds(20, 20, 100, 100); desktop.add(internal); internal.setVisible(true); JButton b = new JButton(new AbstractAction("beep") { @Override public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().beep(); } }); b.setMnemonic(KeyEvent.VK_B); JPanel p = new JPanel(new BorderLayout()); p.add(b, BorderLayout.SOUTH); p.add(desktop); return p; } private JMenuBar createMenuBar() { JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu("Frame"); menu.setMnemonic(KeyEvent.VK_F); menuBar.add(menu); JMenuItem menuItem = new JMenuItem(openAction); menuItem.setMnemonic(KeyEvent.VK_1); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK)); menu.add(menuItem); return menuBar; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } public static void createAndShowGUI() { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new ModalInternalFrameTest().makeUI(f)); f.setSize(640, 480); f.setLocationRelativeTo(null); f.setVisible(true); } } 

弹出窗口有三种类型:

  • 重量轻
  • 中等重量
  • 重量很重

唯一一个在模态状态下工作的是重量级弹出窗口。 改变弹出窗口权重的“官方”方法是通过setLightWeightPopupEnabled(boolean aFlag)方法。 如果将其设置为false,则弹出窗口在应用程序框架内时将为中等重量,而在超出框架边界时则为重量级。

要强制加权,必须使用名为javax.swing.ClientPropertyKey.PopupFactory_FORCE_HEAVYWEIGHT_POPUP的客户端属性。 使用此属性,您可以强制弹出窗口(或容器中的每个弹出窗口)都很重。 但访问它的唯一方法是通过reflection,因为它是私有的。

这是一个示例代码:

 try { Class enumElement = Class.forName("javax.swing.ClientPropertyKey"); Object[] constants = enumElement.getEnumConstants(); putClientProperty(constants[3], Boolean.TRUE); } catch(ClassNotFoundException ex) {} 

如果你把它放在modalInternalFrame的构造modalInternalFrame ,那么放在它上面的每个弹出窗口都会很重。