paintComponent() TextField 导致无限循环(自身 + 父级)

paintComponent() TextField causes Infinite loop (itself + parent)

经过几天的研究,恳请您的帮助。以下代码有效,但会产生大量 CPU 消耗。似乎这个简单的文本字段在一个循环中执行 "paintComponent",不仅是它自己,还有它的父级 (JPanel)。你能给我一个纠正的方法吗?

谢谢:)

package view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.BorderFactory;
import javax.swing.JTextField;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;

import constants.Colors;
import constants.Polices;
import constants.Spacing;

public class FieldText extends JTextField 
{
    private static final long serialVersionUID = 4526307090633268880L;
    private int xheight = 96;
    public Boolean hinted = false;                      // Définit si le     contenu == au hint ou si le contenu a été entré par l'utilisateur.
    protected Color bgColor = Colors.INPUT;             // Background normal.
    protected Color textColor = Colors.TEXT_INPUT;      // Couleur du texte normal.
    protected Color bgHinted = Colors.INPUT;            // Background lors que le placeholder est actif.
    protected Color textHinted = Colors.TEXT_INPUT;     // Couleur du texte placeholder.
    protected Font textFont = Polices.INPUTS;           // Police texte utilisateur.
    protected Font textHintFont = Polices.INPUTS_HINT;  // Police     placeholder.

    public FieldText()
    {   
        super();
        init(null, null);
    }


    /**
     * @param text String Texte du champ (valeur) 
     * @param text String PlaceHoler
     */
        public FieldText( String text, String hint )
        {   
            super();
            init(text, hint);
        }

    /**
     * @param hint Sting Texte du champ (valeur).
     */
        public FieldText( String hint )
        {   
            super();
            init(null, hint);
        }


    private void init( String text, String hint )
    {
        setOpaque(false);
        setBackground(bgColor);
        setForeground(textColor);
        setMinimumSize( new Dimension( 200, 64 ) );
        setBorder( new CompoundBorder (
                                                BorderFactory.createMatteBorder(0, 5, 0, 0, Colors.GREEN), 
                                            new EmptyBorder(     Spacing.PADDING_INPUTS )   
                                       ) 
        );
        setFont( Polices.INPUTS );

        if ( text != null && text.length() > 0 )
        {
            setText(text);  
        }

        setHeight(-1);          // Height by default.
    }


    /**
     * Définit la hauteur de l'élément. 
     * @param height int Hauteur à attribuer à l'élément. -1 pour utiliser la hauteur par défaut (xheight).
     */
        public void setHeight( int height )
        {
            setPreferredSize( new Dimension(this.getWidth(), (height>-1)     ? height : xheight) );
        }


    @Override
    protected void paintComponent(Graphics g) 
    {       
        Graphics2D g2d = (Graphics2D)g;

        GradientPaint gp = new GradientPaint (
            0, 0, new Color( 255, 255, 255, 50 ),
            0, 20, new Color( 179, 179, 179, 50 ) 
        );

        g2d.setPaint( gp );
        g2d.fillRoundRect(0, 0, getWidth()-1, getHeight()-1, 10, 10);

        super.paintComponent(g2d);

        System.out.println("======> inside FieldText.paintComponent() ");
    }
}`

JTextField 在 JFrame 的 JPanel 中。

抱歉我的英语不好...

Here a little example who causes the loop.

编辑: src/views/GuestLoginView

中的示例集成

Here is the full src

运行你的程序不会对我造成高 CPU 消耗。

此外,TextField 可能需要不断重新绘制以使闪烁的光标具有动画效果。每秒重绘一次是一个合理的期望,这是我在控制台上看到的。

我更简洁地重写了您的代码,将其(大部分)放在一个文件中以简化此过程。第一的, 不断重绘是由插入克拉的blink引起的。但是要用 gradientPaint 做你想做的事,最好使用 JLayer。还有一些其他事情可以促进您的代码。

  1. 不要扩展 JFrame。它的方法很少被覆盖,因此没有必要这样做。只需使用一个实例。
  2. 不是使用构造函数调用的 init(),而是让多个构造函数使用 this 调用主构造函数。喜欢this(null, null)

JLayer 允许 Swing 组件在其子组件上绘制。这正是您要在程序中执行的操作。我已将此 link 包括在内,以便您可以看到 tutorial 和随附的视频。我使用了视频中的字段名称来帮助理解您自己代码中的解释。最后,当我 运行 时,我没有看到 2% CPU 我在 Windows 10 with a quad core i7 processor.

上的所有进程的利用率
    package view;

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.awt.GradientPaint;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridLayout;

    import javax.swing.BorderFactory;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLayer;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.border.CompoundBorder;
    import javax.swing.border.EmptyBorder;
    import javax.swing.plaf.LayerUI;

    import constants.Colors;
    import constants.Polices;
    import constants.Spacing;

    public class TestFrame {
       private static final long serialVersionUID = 818148271075948079L;
       private TestPanel         panelContent;
       private FieldText         field1, field2;

       JFrame                    frame            = new JFrame();

       public TestFrame() {

          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          field1 = new FieldText("your text 1", null);
          field2 = new FieldText("your text 2", null);
          panelContent = new TestPanel();
          panelContent.add(field1);
          panelContent.add(field2);
          LayerUI<JComponent> layerUI = new MyLayerUISubClass();
          JLayer<JComponent> jlayer = new JLayer<>(panelContent, layerUI);

          panelContent.setPreferredSize(new Dimension(500, 256));
          frame.add(jlayer);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }

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

    }

    class MyLayerUISubClass extends LayerUI<JComponent> {
       @Override
       public void paint(Graphics g, JComponent c) {
          super.paint(g, c);
          Graphics2D g2d = (Graphics2D) g.create();

          GradientPaint gp = new GradientPaint(0, 0, new Color(255, 255, 255, 50),
                0, 20, new Color(179, 179, 179, 50));

          g2d.setPaint(gp);
          // g2d.fillRect(0, 0, c.getWidth() - 1, c.getHeight() - 1);
          g2d.fillRoundRect(0, 0, c.getWidth() - 1, c.getHeight() - 1, 10, 10);

          System.out.println("======> inside FieldText.paintComponent() ");
          g2d.dispose();
       }

    }

    class TestPanel extends JPanel {
       private static final long serialVersionUID = -4236642932453746731L;

       public TestPanel() {
          setLayout(new GridLayout(2, 1));
          setBackground(Color.black);

       }

       @Override
       protected void paintComponent(Graphics g) {
          // TODO Auto-generated method stub
          super.paintComponent(g);

          System.out.println("======> inside TestPanel.paintComponent() ");
       }
    }

    class FieldText extends JTextField {
       private static final long serialVersionUID = 4526307090633268880L;
       private int               xheight          = 96;
       public Boolean            hinted           = false;               // Définit si le contenu == au hint ou si le contenu a été entré par
                                                                         // l'utilisateur.
       protected Color           bgColor          = Colors.INPUT;        // Background normal.
       protected Color           textColor        = Colors.TEXT_INPUT;   // Couleur du texte normal.
       protected Color           bgHinted         = Colors.INPUT;        // Background lors que le placeholder est actif.
       protected Color           textHinted       = Colors.TEXT_INPUT;   // Couleur du texte placeholder.
       protected Font            textFont         = Polices.INPUTS;      // Police texte utilisateur.
       protected Font            textHintFont     = Polices.INPUTS_HINT; // Police placeholder.

       public FieldText(String text, String hint) {
          setOpaque(true);
          setBackground(bgColor);
          setForeground(textColor);
          setMinimumSize(new Dimension(200, 64));
          setBorder(new CompoundBorder(
                BorderFactory.createMatteBorder(0, 5, 0, 0, Colors.GREEN),
                new EmptyBorder(Spacing.PADDING_INPUTS)));
          setFont(Polices.INPUTS);

          if (text != null && text.length() > 0) {
             setText(text);
          }
          setHeight(-1); // Height by default.
       }

       public FieldText() {
          this(null, null);
       }

       public FieldText(String hint) {
          this(null, hint);
       }

       /**
        * Définit la hauteur de l'élément.
        * 
        * @param height
        *        int Hauteur à attribuer à l'élément. -1 pour utiliser la hauteur par
        *        défaut (xheight).
        */
       public void setHeight(int height) {
          setPreferredSize(new Dimension(this.getWidth(), (height > -1) ? height
                : xheight));
       }
    }

我发现了问题。

它不在字段中,而是在我的自定义按钮的 paintComponent() 中。

我有

  ImageIcon bicon = ( mouseHover ) ? new ImageIcon( iconHover ) : new ImageIcon( icon );
        setIcon(bicon);
        getIcon().paintIcon( this, g2, getIconX(), getIconY() ); 

==> paintComponent 中的 setIcon 不是一个好主意,它导致循环和 CPU 用法。

感谢您的宝贵建议。