高人门先让看看第一个问题!
我可以再把这段程序简化一点:
class RepaintPanel extends JPanel
{
      public RepaintPanel()
      {
             btnTest=new JButton("RepaintTest");
             add(btnTest);
      }
      public void paintComponent(Graphics g)
      {
                    g.drawRect(10,10,40,50);
      }
      private JButton btnTest;
}
主程序类和Frame类是同样的。
我只是想在程序首先出现时,先在panel上有个Button和画好的矩形,然后在程序需要重画的时候重画这个画好的矩形,如果最大最小化了这个窗口后,在Button旁还会出现一个Button,这是什么道理呢?我在paintComponent的时候并没有重画这个Button呀?有什么好的办法可以解决啊?

解决方案 »

  1.   

    你在程序中最好不要直接调用paintComponent(Graphics g)方法的,此方法是为
    容器刷新时,由容器来调用的,除非改控件显示格式,否则最好不要调用,即使调用也应该首先在其方法中调用super.paintComponent(g);你程序逻辑是为了在刷新时画的图重画,所以你在控件重画时做此动作,此不妥,我给你写了相应的处理方法,如我给你的第二种解决方法。解决方法一:
    public void paintComponent(Graphics g)
    {
        //添加如下方法
        super.paintComponent(g);    if(flag==false)
            MyDraw(g);
    }
          
          
    解决方法二:(在panel的paint()中处理图像处理,RepaintPanel类改动如下,你可直接替换你的类)
    class RepaintPanel extends JPanel implements ActionListener
    {
        public RepaintPanel()
        {
            btnTest=new JButton("RepaintTest");
            add(btnTest);
            btnTest.addActionListener(this);
        }
        public void actionPerformed(ActionEvent evt)
        {
            flag=false;
            this.repaint();
        }
        public void paint(Graphics g) {
            super.paint(g);
            if(flag == false)
                g.drawRect(10,10,40,50);
        }      private JButton btnTest;
        private boolean flag=true;
    }      
      

  2.   

    在SWing组件中定制绘制复杂,是因为SWing组件本身是AWT容器。下面是绘制SWing组件的一些基本原则:
    Ù 如果需要控制组件本身的绘制过程,但又想用缺省的操作来绘制该组件的边框和子组件,则重载Jcomponent.paintComponent()
    Ù 如果需要完全控制组件、其边框和其子组件的绘制过程,请重载Jcomponent.paint()方法
    Ù 在重载Jcomponent.paintComponent()方法中调用super.paintComponent()以确保UI代表获得擦除不透明组件的背景和绘制的机会
    Ù 重载paintComponent方法时,不要绘制到组件的边衬中
    Ù 在计算最小、最大和首选尺寸时,要考虑组件的边衬大小
    &Ugrave; 如果SWing在更新时闪烁,则应该确保组件是双缓存的,而不是重载其他更新的方法---摘自<java 2 图形设计卷II SWing>
      

  3.   

    谢谢上面各位的解答了,我真后悔怎么不多设点分数呢?还是这里的高人多啊!
    我都在其他的论坛上挂了好多天了,还是不见有人回答啊!
    那再请问各位高人那第二第三个问题怎么来解决呢?
    在调用repaint方法的时候,是不是会调用paintComponent方法呢?在帮助上说的不是很清楚吗?谢谢各位高人的解答了哦!太谢谢了哦!
      

  4.   

    好了,我的第一个问题解决了,各位网友再来解决一下第二第三个问题好吗?
    我如果将程序改成这样:
    class RepaintPanel extends JPanel implements ActionListener
    {
          public RepaintPanel()
          {
                 btnTest=new JButton("RepaintTest");
                 add(btnTest);
                 btnTest.addActionListener(this);
          }
          public void actionPerformed(ActionEvent evt)
          {
                 repaint();
                 flag=false;
          }
          public void paintComponent(Graphics g)
          {
                 super.paintComponent(g);
                 if(flag==false)
                               g.drawRect(10,10,40,50);
          }
          private JButton btnTest;
          private boolean flag=true;
    }
    为什么在这时调用repaint方法的时候,还是会调用paintComponent方法呢?我记得repaint方法是通过调用update方法来重画组件的,而update是进行初始化(背景色填充、设置组件前景色)后调用paint()来绘制组件。并没有说会调用paintComponent方法呀!而paintComponent方法是在窗口第一次显示的时候和窗口需要重画的时候调用的呀!希望那位网友能再帮我解释一下!
    还有想请那位Java高人帮我解释一下在paintComponent方法中的帮助好吗?太谢谢了,分数一定送上的。
        
      

  5.   

    大概说一下,我也没深入源码。
    你的程序比较特殊,在一个面板panel中既有控件,又要画图。如果重载panel的paint()方法,而不调用父类的paint()来绘制组件,
    是不画其中包含的控件的,所以不调用控件paintComponent方法。
    panel没有paint()方法,其paint()方法是父类JComponent的,JComponent的paint()方法在最后会调用paintChildren()方法(696行),其中即
    是画包含控件,所以对你“窗口第一次显示的时候和窗口需要重画的时候调用”的说法不同意。
    你的问题是重载了paintComponent方法,而其中没有调用父类的paintComponent方法,就可能出问题。第三个问题我也不太懂,UI delegate大概指控件的图像代理,处理控件画图动作,一般的swing和awt控件都有,又叫对等体。
      

  6.   

    UI delegate 称为UI代表.
    组件把实现其用户界面(UI)的任务交给一个UI代表来完成。UI代表是在他们组件的构造方法中实例化的,是被自动调用并创建的。这里说一下UI代表的绘制:(Swing所有轻量组间组件绘制都是类似下面的过程)
    paint()方法的调用顺序是:先调用paintCoponent()来实现组件本身的绘制,然后再绘制边框,接下来再绘制子组件。
    而paintCoponent()其实完成的事情就是;调用该组件的UI代表的update方法,来实现组件绘制。一般不建议重载paint方法,而是重载paintComponent()方法。而且调用super。paintComponent()是必须的(对于不透明组件而言)。因为背景由组件的UI代表或者超类的paintComponent方法擦除。如果组件有一个UI代表,那么如果不调用super.component(),UI代表将没有机会进行绘制组件时它所要完成的那部分工作。强烈建议:<java 2 图形技术卷II Swing技术> 第一部分 Swing技术中对于这个有比较好的介绍.
    我也给你说不清楚:)
      

  7.   

    哎呀,上面说的还是很乱,另外试着说说:)1.Swing组件是由JComponent类的paint方法来完成绘制的.,该方法以一个要绘制的图形作为参数.(就是那个Graphics g啦!)2.JComponent.paint先绘制组件(paintComponent),然后绘制组件的边框(paintBorder),在绘制组件的子组件(paintChildren).调用的顺序确保组件,边框和子组件都是可视的.(人家已经做的很好的,不需要我们再重载这个方法啦.一般情况:)所以,当要重新定义如何绘制组件,就重载paintComponent()方法就可以了.3.JComponent.paint最先绘制组件,本来调用的是JComponent.paintComponentf()这个方法,而且在这个方法里边他调用了组件的UI代表来完成背景呀之类的工作的(UI代表很重要,但程序人员很少去管它:).但是想想,在这个时候,你重载了这个方法,那么就按照你的方法去办事了,而不能正确调用父类的方法,也就是无法完成JComponent.paintComponet()方法里边关于UI代表的工作的.其实就是调用不倒UI代表的update()方法了.有些事情就做不到了,比如说擦除背景,这就是你必须用
    super.PaintComponent()的原因了,就是为了请人家UI代表来工作一下嘛!4.UI代表和组件的边框都是以一个用来绘制组件的实际图形的拷贝(注意是拷贝,那就是原来的不受影响)为参数.
    因此,paintBorder和paintChildren方法可以改变传送给他们的图形(他们拿着拷贝做上一顿折腾,比如说原来的图形是个方的,他们给改成圆的了,但是这种改变仅仅发生在他们自己拷贝来的那份参数上,原来的正本并没有变成圆的,仍然是方的),
    这样互相工作就不牵扯啦.而不影响接下来图形的操作.
    (这段应该是你上面的那段英文的解释了吧,不知道是否满意?)有关graphics和设置的有关信息参看<java 图形设计1 AWT>
      

  8.   

    protected void paintComponent(Graphics g)If the UI delegate is non-null, calls its paint method. We pass the delegate a copy of the Graphics object to protect the rest of the paint code from irrevocable changes (for example, Graphics.translate()).这个应该是JCoponent的方法吧.下面还有一段的
    If you override this in a subclass you should not make permanent changes to the passed in Graphics. For example, you should not alter the clip Rectangle or modify the transform. If you need to do these operations you may find it easier to create a new Graphics from the passed in Graphics and manipulate it. Further, if you do not invoker super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts. 我想你看得明白的,如果你能看明白我上面写的那些:)
    我翻译一下:
    如果UI代表不为空的话(就是如果有一个UI代表的话)将调用他的paint方法。(我上面说组件为UI代表调用update方法,其实就是内部调用了UI。paint())。我们传递一个图形参数的拷贝作为他的参数是为了确保接下来的(以后)的绘制不受影响。如果你在子类中override(覆盖,我上面说的“重载”有失妥当,再仔细捉摸以下)这个方法的话,你不应该对传入的图形参数做永久性的修改。比如,你不应该裁剪矩形或者更新修改。如果你确实需要做修改,你会发现拷贝一份传入的图形参数并对其操作是很容易的完成你的要求。另外,如果你不调用(invoker)父类的实现的话,而且必须确保是不透明的,那就必须用一个的颜色整个填充(fill)整个背景。
    (哎,看着e文还明白点,结果一翻译就发现越来越不通顺了,你还是看e文的吧。第一次会帖子写了这么多的字,)强烈建议楼主请客!!!