【问题标题】:Components Only get drawn when hovered over组件仅在悬停时绘制
【发布时间】:2012-11-13 09:29:12
【问题描述】:

谁能解释为什么我的组件只有在我将鼠标悬停在它们应该在的位置时才会被绘制?

我设置了一个可以拖动到任何地方的无边框框架,并且我试图在右上角创建一个退出按钮,但直到我将鼠标悬停在它上面才会被绘制。我在 JFrame 上绘制一个背景图像,然后绘制我的按钮并将整个内容设置为可见。

import java.awt.*;
import java.awt.event.*;
import javax.imageio.ImageIO;
import javax.swing.*;

public class GUI extends JFrame
{
    private Image Background = null;
    private static Point Offset = new Point();

    public GUI() {
        this.setUndecorated(true);
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        AddListeners();
        SetCustomTheme();
        LoadBackground();
        Layout();
        pack();
        this.setSize(300, 300);
        this.setVisible(true);
    }

    private void Layout() {
        GroupLayout Info = new GroupLayout(this.getContentPane());
        this.getContentPane().setLayout(Info);
        JButton Button = new JButton();

        Info.setHorizontalGroup(
            Info.createSequentialGroup()
               .addComponent(Button)
         );

        Info.setVerticalGroup(
            Info.createParallelGroup()
                .addComponent(Button)
        );
    }

    private void SetCustomTheme() {
        try {
            UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
        }
    }

    private void LoadBackground() {
        try {
            Background = ImageIO.read(getClass().getResource("Images/meh.png"));
        } catch (Exception Ex) {

        }
    }

    private void SetCustomIcon() {
        Image Icon = Toolkit.getDefaultToolkit().getImage("Images/lol.jpg");
        setIconImage(Icon);
    }

    private void AddListeners() {
        this.addMouseListener(new MouseAdapter() {
            @Override public void mousePressed(MouseEvent e) {
              Offset.x = e.getX();
              Offset.y = e.getY();
            }
          });

        this.addMouseMotionListener(new MouseMotionAdapter() {
            @Override public void mouseDragged(MouseEvent e) {
              Point p = getLocation();
              setLocation(p.x + e.getX() - Offset.x, p.y + e.getY() - Offset.y);
            }
          });
    }

    @Override public void paint(Graphics g) {
        g.drawImage(Background, 0,0,this.getWidth(),this.getHeight(), null);
    }
}

【问题讨论】:

    标签: java swing


    【解决方案1】:
    1. 与 UI 的所有交互都必须在事件调度线程中执行
    2. 您应该避免从顶级容器扩展,例如JFrame,而是使用JPanel
    3. 未能遵守 paint 链合约会阻止任何子组件开始绘制
    4. 执行自定义绘画的首选重写方法是paintComponent

    您可能想通读一遍

    试试这样吧;

    public class BadPaint01 {
    
        public static void main(String[] args) {
            new BadPaint01();
        }
    
        public BadPaint01() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame();
                    Image Icon = Toolkit.getDefaultToolkit().getImage("Images/lol.jpg");
                    frame.setIconImage(Icon);
                    frame.setUndecorated(true);
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new GUI());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public static class GUI extends JPanel {
    
            private Image Background = null;
            private static Point Offset = new Point();
    
            public GUI() {
                AddListeners();
                SetCustomTheme();
                LoadBackground();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 300);
            }
    
            private void Layout() {
                GroupLayout Info = new GroupLayout(this);
                setLayout(Info);
                JButton Button = new JButton();
    
                Info.setHorizontalGroup(
                        Info.createSequentialGroup()
                        .addComponent(Button));
    
                Info.setVerticalGroup(
                        Info.createParallelGroup()
                        .addComponent(Button));
            }
    
            private void SetCustomTheme() {
                try {
                    UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
            }
    
            private void LoadBackground() {
                try {
                    Background = ImageIO.read(getClass().getResource("Images/meh.png"));
                } catch (Exception Ex) {
                }
            }
    
            private void AddListeners() {
                this.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
                        Offset.x = e.getX();
                        Offset.y = e.getY();
                    }
                });
    
                this.addMouseMotionListener(new MouseMotionAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        Point p = getLocation();
                        setLocation(p.x + e.getX() - Offset.x, p.y + e.getY() - Offset.y);
                    }
                });
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
                g.drawImage(Background, 0, 0, this.getWidth(), this.getHeight(), null);
            }
        }
    }
    

    你也可能想通读Code Conventions for the Java Programming Language,你不会因为忽略他们而结交任何朋友;)

    【讨论】:

    • 那为什么 Netbeans 是从 JFrame 而不是 JPanel 扩展的呢? :S
    • 因为它不是一个无效的操作,只是一个不明智的操作。有时您可能希望向JFrame 添加其他功能,但在您的情况下,您并没有添加任何价值。此外,在顶级容器上绘画不是一个好主意,因为 1- 它们不是双缓冲的,并且 2- 框架顶部有一个 JRootPane,其中包含内容窗格,因此您所做的任何绘画要么完成在内容的下方或上方,这在您的情况下是不可取的,因为根窗格将隐藏您的工作(如果您实际上正确使用了绘制机制。
    • Java 将允许您从任何线程更新 UI 组件,但这被认为是不好的做法,开发人员和 API 之间有一个理解契约,而您可以打破这个契约,期待事情快速变成梨形。
    • @DavidKroukamp 看到“那为什么我的车能以每小时 220 公里的速度行驶?” ;)
    【解决方案2】:

    如果我没记错的话,ToolKit.getImage 返回一个可能没有完全加载的Image。当您将鼠标悬停在它上面时,它可能同时已在后台加载。 而是这样做(类似于您的背景行):

    ImageIcon Icon = new ImageIcon(ImageIO.read(getClass().getResource("Images/lol.png")));
    setIconImage(Icon);
    

    (为了更好地理解,您可能需要搜索MediaTracker,我相信这是用来确保图像已完全加载的。)

    【讨论】:

      猜你喜欢
      • 2011-09-18
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 2015-01-27
      • 1970-01-01
      • 2023-03-26
      • 2017-10-19
      相关资源
      最近更新 更多