【问题标题】:JFrame Glasspane is also over JDialog but shouldn'tJFrame Glasspane 也在 JDialog 之上,但不应该
【发布时间】:2013-05-19 22:05:34
【问题描述】:

我有一个带有 Glasspane 的 JFrame(未装饰)。 此框架打开一个 JDialog(也未装饰,也有一个 glassPane)并隐藏自身(setVisible(false))。 Glasspanes 使用 .setGlassPane() 设置。 对话框以 Frame 作为所有者打开。

GlassPane 扩展了 JPanel 并实现了 AWTEventListener。 我用它来调整框架和对话框的大小,所以它知道它是父级(框架/对话框)——这被称为“目标”。

GlassPane 中的事件是这样处理的:

public void eventDispatched(AWTEvent event) {

  if (target instanceof JFrame) {
     e = SwingUtilities.convertMouseEvent(
     ((MouseEvent) event).getComponent(),
     (MouseEvent) event, ((JFrame) target).getGlassPane());
  } else if (target instanceof JDialog) {
     e = SwingUtilities.convertMouseEvent(
     ((MouseEvent) event).getComponent(),
     (MouseEvent) event, this);
  }


  if (e.getID() == MouseEvent.MOUSE_PRESSED) {
    this.startPos = target.getLocationOnScreen();
  }
}

在“target.getLocationOnScree”处,当 JFrame 被隐藏并单击 JDialog 时,我得到一个 IllegalComponentStateException。它说“组件必须显示在屏幕上才能确定其位置”。这是因为 JFrame 的 GlassPane 获取了事件。但是 JDialog 的 Glasspane 应该得到它。我认为,JFrame 的 Glasspane 在 JDialog 前面。但为什么呢?

感谢您的帮助!

编辑:

这是一个例子:

import java.awt.AWTEvent;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;

import javax.swing.JDialog;
import javax.swing.JFrame;



public class Main {




    static JFrame frame;
static JDialog dialog;


public static void main(String[] args) {

    frame = new JFrame();
     frame.setSize(600,600);
    GlassPane frameGlas = new GlassPane(frame);
    frame.setGlassPane(frameGlas);
    frame.setVisible(true);

    frameGlas.setVisible(true);
    dialog = new JDialog(frame);

    dialog.setSize(100, 100);
    GlassPane dialogGlas = new GlassPane(dialog);

    dialog.setGlassPane(dialogGlas);
    AWTEventListener al = (AWTEventListener) frameGlas;
    Toolkit.getDefaultToolkit().addAWTEventListener(
            al,
            AWTEvent.MOUSE_MOTION_EVENT_MASK
                    | AWTEvent.MOUSE_EVENT_MASK);
    dialogGlas.setVisible(true);
    dialog.setVisible(true);
}


}


import java.awt.AWTEvent;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;

import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GlassPane extends JPanel implements AWTEventListener {

    /**
     * 
     */
    private static final long serialVersionUID = 5110857185182004819L;

    private final Window target;


    public GlassPane(Window target) {
        super(null);
        this.target = target;

    }



    public void eventDispatched(AWTEvent event) {
        if (event instanceof MouseEvent) {

            MouseEvent originalEvent = (MouseEvent) event;

            MouseEvent e = originalEvent;
        if (target instanceof JDialog) {
                e = SwingUtilities.convertMouseEvent(
                        ((MouseEvent) event).getComponent(),
                        (MouseEvent) event, this);
            }


            if (e.getID() == MouseEvent.MOUSE_PRESSED) {

                Point p  = target.getLocationOnScreen();
                System.out.println(p.getX());
            }
        }

        }



}

【问题讨论】:

  • 听起来更像是您的鼠标侦听器使用框架作为目标而不是对话框,但除非您提供问题的工作示例,否则将无法提供帮助。想到的另一个问题是,你为什么不直接使用 MouseListener?
  • 我添加了一个包含“Main”和“GlassPane”两个类的工作示例。抱歉,我本可以忽略“setUndecorated”。我不使用 MouseListener 因为这与其他一些东西冲突。老实说,我不太记得为什么。但我记得我在 MouseListeners 上遇到的麻烦比在 GlassPane 上要麻烦得多

标签: java jframe mouseevent jdialog glasspane


【解决方案1】:

查看您的源代码,您只需要将frame 的玻璃窗格注册到AWTListener。现在,从表面上看,这似乎不是一件坏事。 AWTListener 将被通知系统中的所有鼠标事件,但实际接收事件的GlassPane 实例只会知道frame...

基本上,这意味着dialogGlas 永远不会收到任何事件,因为它没有注册。

首先,您需要将frameGlasdialogGlas 都注册为侦听器。

其次,您不应该试图“猜测”目标。 MouseEvent(实际上所有事件)都有来源。您应该将源代码与target 进行比较,以便仅当事件发生在您感兴趣的组件上时才能对事件做出反应...

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main {

    static JFrame frame;
    static JDialog dialog;

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }


                frame = new JFrame();
                frame.setSize(600, 600);
                GlassPane frameGlas = new GlassPane(frame);
                frame.setGlassPane(frameGlas);
                frame.setVisible(true);

                frameGlas.setVisible(true);
                dialog = new JDialog(frame);

                dialog.setSize(100, 100);
                GlassPane dialogGlas = new GlassPane(dialog);
                dialog.setGlassPane(dialogGlas);
                dialogGlas.setVisible(true);
                dialog.setVisible(true);

                // Register a listener for the frameGlas
                Toolkit.getDefaultToolkit().addAWTEventListener(
                        frameGlas,
                        AWTEvent.MOUSE_MOTION_EVENT_MASK
                        | AWTEvent.MOUSE_EVENT_MASK);
                // Register a listener for the dialogGlas
                Toolkit.getDefaultToolkit().addAWTEventListener(
                        dialogGlas,
                        AWTEvent.MOUSE_MOTION_EVENT_MASK
                        | AWTEvent.MOUSE_EVENT_MASK);
            }
        });
    }

    public class GlassPane extends JPanel implements AWTEventListener {

        private static final long serialVersionUID = 5110857185182004819L;
        private final Window target;

        public GlassPane(Window target) {
            super(null);
            this.target = target;

        }

        @Override
        public void eventDispatched(AWTEvent event) {
            if (event instanceof MouseEvent) {

                MouseEvent originalEvent = (MouseEvent) event;

                MouseEvent e = originalEvent;
                Component source = e.getComponent();
                System.out.println("Source: " + source);
                System.out.println("Target: " + target);
                if (target != null && target.equals(source)) {
                    e = SwingUtilities.convertMouseEvent(
                            ((MouseEvent) event).getComponent(),
                            (MouseEvent) event, this);

                    if (e.getID() == MouseEvent.MOUSE_PRESSED) {

                        Point p = target.getLocationOnScreen();
                        System.out.println(p.getX());
                    }
                }
            }
        }
    }
}

现在,在我的脑海中,MouseListener 遇到的问题是它们是贪婪的,它们阻止事件级联超出它们注册的组件。

【讨论】:

  • 非常感谢!这很有帮助。有用。我只将框架的 GlassPane 注册到 Listener 是一个错误。我有两个 GlassPanes registert。为了简化示例,我想删除框架的侦听器,但意外删除了对话框的侦听器。无论如何 - 再次感谢。
猜你喜欢
  • 2011-08-07
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-07
  • 2012-02-05
  • 1970-01-01
  • 2015-06-30
相关资源
最近更新 更多