V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Newyorkcity
V2EX  ›  问与答

一个 Java 入门 GUI 小程序,就是不太明白为什么我会多一个假 button 块

  •  1
     
  •   Newyorkcity · 2018-03-25 21:34:48 +08:00 · 2121 次点击
    这是一个创建于 2470 天前的主题,其中的信息可能已经有所发展或是发生改变。

    图片

    上面的那个 button 按钮是假的,第一鼠标移动上去不变样子,第二点也点不了
    点下面那个真的我代码安排好的,很正常.并且点了一次之后上面那个假的也会消失,程序正常运行,色块变色
    程序代码如下:

    package SimpleGui3;
    import javax.swing.*;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.event.*;
    
    public class SimpleGui3 {    
        public static void main(String[] args) {
            MyFrame gui = new MyFrame();
        }
    }
    
    class MyFrame extends JFrame implements ActionListener {
        JButton button;
        MyDrawPanel draw_panel;
        
        public MyFrame() {    
            this.setVisible(true);
            this.setSize(300, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            
            button = new JButton("click to change colors");
            button.addActionListener(this);
            this.getContentPane().add(BorderLayout.SOUTH,button);
            
            draw_panel = new MyDrawPanel();
            this.getContentPane().add(BorderLayout.CENTER,draw_panel);
            
        }
        
        public void actionPerformed(ActionEvent event) {
            this.repaint();
        }
    }
    //无关紧要的部分↓
    class MyDrawPanel extends JPanel {
        public void paintComponent(Graphics g) {
            int[] color_array = new int[3];
            for(int i=0;i<color_array.length;i++) {
                color_array[i] = (int)(Math.random() * 255);
            }
            Color c = new Color(color_array[0],color_array[1],color_array[2]);
            g.setColor(c);
            g.fillRect(20, 50, 100, 100);
        }
    }
    

    到底是咋回事儿啊,求大佬解答,谢谢..

    第 1 条附言  ·  2018-03-26 09:04:22 +08:00
    感谢第三楼的大佬解答,我把认为无关紧要的部分全部注释之后,虽然色块没有了,但多余的假 button 块也确实没了..
    但覆盖 paintComponent 后我并没有在新 paintComponent 里要求 super().paintComponent()呀,为何会发生这种情况?
    而且就算发生了 super().paintComponent(),又为什么会生成一个假 button 块呢?
    第 2 条附言  ·  2018-03-26 23:52:58 +08:00
    在 sementfault 上一位大佬说把构造器中放在开头的 this.setVisible(true);放到构造器的尾巴上(就构造器最后)
    居然真的解决了这个问题诶!!!
    这背后的运行机制到底是怎么回事啊?
    14 条回复    2018-03-27 09:17:49 +08:00
    kaneg
        1
    kaneg  
       2018-03-25 21:47:46 +08:00   ❤️ 1
    我的 mac 上运行没有你描述的问题,Java 为 jdk1.8.0_162。你的运行环境是什么? OS 和 Java
    Newyorkcity
        2
    Newyorkcity  
    OP
       2018-03-25 22:30:16 +08:00
    @kaneg 谢谢 win10+eclipse

    ->java -version

    java version "9.0.4"
    Java(TM) SE Runtime Environment (build 9.0.4+11)
    Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)
    justinwu
        3
    justinwu  
       2018-03-26 01:36:48 +08:00 via iPhone   ❤️ 1
    @Newyorkcity 那个无关紧要的代码确定木有问题?

    override paintComponent 后,是不是也要 call super.paintComponent,猜的,试试看。
    night98
        4
    night98  
       2018-03-26 02:22:22 +08:00 via Android
    这个代码在手机上看可以说是非常难受了
    736531683
        5
    736531683  
       2018-03-26 08:06:09 +08:00 via Android
    爪机无力,现在还写 java 的 gui 吗?…之前 java 课被迫写了几个感觉没什么用
    play78
        6
    play78  
       2018-03-26 08:43:36 +08:00
    好像我也会耶
    Newyorkcity
        7
    Newyorkcity  
    OP
       2018-03-26 09:02:40 +08:00
    @justinwu 在把我认为无关紧要的那块代码改为注释之后,确实没有再出现问题诶!
    但覆盖 paintComponent 后我并没有在新 paintComponent 里要求 super().paintComponent()呀,为何会发生这种情况?
    vve2ex
        8
    vve2ex  
       2018-03-26 10:29:18 +08:00
    win7 1.8 eclipse 测试没有出现多余按钮
    Newyorkcity
        9
    Newyorkcity  
    OP
       2018-03-26 11:00:57 +08:00 via Android
    @vve2ex 编译运行两三次试试?我重启之后第一次编译运行也无问题。。
    justinwu
        10
    justinwu  
       2018-03-26 11:22:03 +08:00   ❤️ 1
    @Newyorkcity 自绘控件,需保证其可视区域都被绘制或刷新,除非有意为之。你的 paintComponent 只画了一小片区域,其他没画的部分,图形缓冲区的内容是不可预料的,不画的就会是残留的内容或不可预料内容。JPanel 或其父类会绘制控件背景,你覆盖了此行为,就该自己画控件背景或是委托父类绘制背景。

    class MyDrawPanel extends JPanel {
    public void paintComponent(Graphics g) {
    super.paintComponent(g);
    ...
    }
    }

    有些系统或平台或不同 Java 版本并不一定会出现问题。这涉及多个方面因素。说来话长,有兴趣可自行研究 GUI 框架代码。
    vve2ex
        11
    vve2ex  
       2018-03-26 11:52:42 +08:00
    @Newyorkcity 运行多次也没有出现你这种现象
    看了 justinwu 的答案觉得比较合理
    kaneg
        12
    kaneg  
       2018-03-26 20:15:04 +08:00
    根据楼主的补充的 java 版本的信息,推测是 Java 9 的 swing paint 跟 Java 8 不一样。目前手头没有 Java 9,暂时无法验证。要么是 Java9 的 bug,要么是其行为变化了
    Newyorkcity
        13
    Newyorkcity  
    OP
       2018-03-26 23:53:18 +08:00
    @justinwu
    @kaneg
    @vve2ex
    在 sementfault 上一位大佬说把构造器中放在开头的 this.setVisible(true);放到构造器的尾巴上(就构造器最后)
    居然真的解决了这个问题诶!!!
    这背后的运行机制到底是怎么回事啊?
    vve2ex
        14
    vve2ex  
       2018-03-27 09:17:49 +08:00
    @Newyorkcity 把 segmentfault 的链接贴上看一下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1001 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:51 · PVG 03:51 · LAX 11:51 · JFK 14:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.