3

我有一个JFrame和一堆JComponents在上面JFrame。我需要使用JGlassPane并且我使用这个实现来设置它。

   JPanel glass = new JPanel();
   frame.setGlassPane(glass);
   glass.setVisible(true);
   glass.setOpaque(false);

JButtons这样做后,我无法JComponentsJGlassPane.

有没有一种方法可以只选择组件上的组件,GlassPane同时仍然能够选择组件下的组件GlassPane

编辑我忘了提到(不知道这是否相关)我确实将 aMouseListener和 a都附加MouseMotionListener到了玻璃窗格上。有没有办法将鼠标事件传递给其他组件并仅在需要时使用它们?

4

3 回答 3

6

让你的 mouseListener 调度它不想处理的事件。

下面的示例代码是混合使用的,使用了@whiskeyspider的漂亮 SSCCE 和教程(顺便说一句:查看教程是解决问题的良好开端:-)

ml = new MouseListener() {
    @Override
    public void mousePressed(MouseEvent e) {
        dispatchEvent(e);
    }
    // same for all methods
    // ....

    private void dispatchEvent(MouseEvent e) {
        if (isBlocked)
            return;
        Point glassPanePoint = e.getPoint();
        Container container = frame.getContentPane();
        Point containerPoint = SwingUtilities.convertPoint(glass,
                glassPanePoint, container);

        if (containerPoint.y < 0) { // we're not in the content pane
            // Could have special code to handle mouse events over
            // the menu bar or non-system window decorations, such as
            // the ones provided by the Java look and feel.
        } else {
            // The mouse event is probably over the content pane.
            // Find out exactly which component it's over.
            Component component = SwingUtilities.getDeepestComponentAt(
                    container, containerPoint.x, containerPoint.y);

            if (component != null) {
                // Forward events to component below
                Point componentPoint = SwingUtilities.convertPoint(
                        glass, glassPanePoint, component);
                component.dispatchEvent(new MouseEvent(component, e
                        .getID(), e.getWhen(), e.getModifiers(),
                        componentPoint.x, componentPoint.y, e
                                .getClickCount(), e.isPopupTrigger()));
            }
        }
    }
};

glass.addMouseListener(ml);
glassButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
        if (isBlocked) {
            // glass.removeMouseListener(ml);
            glassButton.setText("Block");
        } else {
            // ml = new MouseAdapter() { };
            // glass.addMouseListener(ml);
            glassButton.setText("Unblock");
        }

        isBlocked = !isBlocked;
    }
});
于 2012-11-07T10:20:21.480 回答
2

这是玻璃窗格中的 JButton 示例,单击该按钮将切换捕获鼠标事件(无法单击测试按钮)。

public class Test
{
    private static boolean isBlocked = false;
    private static MouseListener ml;

    public static void main(String[] args)
    {
        JButton button = new JButton("Test");
        button.setPreferredSize(new Dimension(100, 100));

        final JButton glassButton = new JButton("Block");

        JPanel panel = new JPanel();
        panel.add(button);

        final JPanel glass = new JPanel();
        glass.setOpaque(false);
        glass.add(glassButton);

        final JFrame frame = new JFrame();
        frame.setGlassPane(glass);
        glass.setVisible(true);
        frame.setContentPane(panel);
        frame.pack();
        frame.setVisible(true);

        glassButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (isBlocked) {
                    glass.removeMouseListener(ml);
                    glassButton.setText("Block");
                } else {
                    ml = new MouseAdapter() { };
                    glass.addMouseListener(ml);
                    glassButton.setText("Unblock");
                }

                isBlocked = !isBlocked;
            }
        });
    }
}
于 2012-11-06T22:42:56.803 回答
2

另一种不中断 Swing 事件链的解决方案是使用 aAWTEventListener代替。我已经实现了 aBetterGlassPane来代替常规的JPanel玻璃窗格,如下所示:

JFrame frame = ...; // any JRootPane will do...
BetterGlassPane glass = new BetterGlassPane(frame);

这也适用于“传统”方式,如您的问题所示:

JPanel glass = new BetterGlassPane();
frame.setGlassPane(glass);    
glass.setRootPane(frame);

希望这可以帮助。随意在 GitHub 上克隆项目或使用 Maven 依赖项:

<dependency>
  <groupId>lc.kra.swing</groupId>
  <artifactId>better-glass-pane</artifactId>
  <version>0.1.3</version>
</dependency>
<repositories>
  <repository>
    <id>better-glass-pane-mvn-repo</id>
    <url>https://raw.github.com/kristian/better-glass-pane/mvn-repo/</url>
    <snapshots>
      <enabled>true</enabled>
      <updatePolicy>always</updatePolicy>
    </snapshots>
  </repository>
</repositories>

简短、自包含、正确、示例(SSCCE,没有强制性的 Maven 依赖):

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import lc.kra.swing.BetterGlassPane;

public class TestBetterGlassPane {
    public static void main(String[] args) {
        final JFrame frame = new JFrame("BetterGlassPane Test");
        frame.setLayout(null);
        frame.setSize(400,300);
        frame.setResizable(false);
        frame.setLocationByPlatform(true);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        BetterGlassPane glassPane = new BetterGlassPane(frame.getRootPane()) {
            private static final long serialVersionUID = 1L;
            @Override protected void paintComponent(Graphics graphics) {
                super.paintComponent(graphics);
                graphics.setColor(Color.BLACK);
                graphics.drawRect(20,160,360,50);
                graphics.setFont(graphics.getFont().deriveFont(Font.BOLD));
                graphics.drawString("I'm the glass pane, click me!",120,190);
            }
        };
        glassPane.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent event) {
                if(new Rectangle(20,180,360,50).contains(event.getPoint()))
                    JOptionPane.showMessageDialog(frame,"I'm the glass pane!");
            }
        });
        glassPane.setLayout(null);

        ActionListener defaultActionListener = new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                JOptionPane.showMessageDialog(frame,
                    ((JButton)event.getSource()).getText());
            }
        };

        JButton frameButton = new JButton("I'm on the frame!");
        frameButton.addActionListener(defaultActionListener);
        frameButton.setBounds(20,20,360,50);
        frame.add(frameButton);

        JButton glassPaneButton = new JButton("I'm on the glass pane!");
        glassPaneButton.addActionListener(defaultActionListener);
        glassPaneButton.setBounds(20,90,360,50);
        glassPane.add(glassPaneButton);

        frame.setVisible(true);
    }
}
于 2016-01-04T20:51:18.550 回答