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
中的示例集成
运行你的程序不会对我造成高 CPU 消耗。
此外,TextField 可能需要不断重新绘制以使闪烁的光标具有动画效果。每秒重绘一次是一个合理的期望,这是我在控制台上看到的。
我更简洁地重写了您的代码,将其(大部分)放在一个文件中以简化此过程。第一的,
不断重绘是由插入克拉的blink引起的。但是要用 gradientPaint
做你想做的事,最好使用 JLayer
。还有一些其他事情可以促进您的代码。
- 不要扩展 JFrame。它的方法很少被覆盖,因此没有必要这样做。只需使用一个实例。
- 不是使用构造函数调用的
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 用法。
感谢您的宝贵建议。
经过几天的研究,恳请您的帮助。以下代码有效,但会产生大量 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
中的示例集成运行你的程序不会对我造成高 CPU 消耗。
此外,TextField 可能需要不断重新绘制以使闪烁的光标具有动画效果。每秒重绘一次是一个合理的期望,这是我在控制台上看到的。
我更简洁地重写了您的代码,将其(大部分)放在一个文件中以简化此过程。第一的,
不断重绘是由插入克拉的blink引起的。但是要用 gradientPaint
做你想做的事,最好使用 JLayer
。还有一些其他事情可以促进您的代码。
- 不要扩展 JFrame。它的方法很少被覆盖,因此没有必要这样做。只需使用一个实例。
- 不是使用构造函数调用的
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 用法。
感谢您的宝贵建议。