【问题标题】:JInternalFrame As ModalJInternalFrame 作为模态
【发布时间】:2013-05-07 15:29:32
【问题描述】:

我有以下代码:

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 的一部分超出内部框架的边界时,该部分不处理鼠标事件(您无法滚动该部分)。

有什么想法吗?

【问题讨论】:

  • d.setModal(true);仅在定义父级的情况下才有效,请参阅 JDialog API,如果需要在运行时进行更改,则可能使用 ModalityTypes 代替
  • 好的,我知道它工作正常,但我的问题是如果内部框架有 JComboBox 或 PopupMenu,当 PopupMenu 的一部分超出内部框架的边界时,该部分不处理鼠标事件(你无法滚动该部分)。
  • 不知道发布SSCCE,简短,可运行,可编译,关于您评论中的问题,

标签: java swing modal-dialog jdialog jinternalframe


【解决方案1】:

使用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<String> combo = new JComboBox<String>(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);
  }
}

【讨论】:

    【解决方案2】:

    弹窗分为三种:

    • 重量轻
    • 中等重量
    • 重量级

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

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

    这是一个示例代码:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-01
      • 2013-08-28
      • 1970-01-01
      • 2017-02-21
      相关资源
      最近更新 更多