Question

I am not sure what I am doing wrong...

I wanted to make a JComponent showing a string with custom font, custom colors (including gradient background), etc. It works fine, but I see the bottom of the string in the upper-left part of my component. The code below simplifies a lot the component to allow to concentrate on the issue...

InfoPanel.java

import java.awt.*;
import java.awt.font.*;
import java.awt.geom.Rectangle2D;

import javax.swing.*;

/**
 * Panel showing information.
 */
@SuppressWarnings("serial")
class InfoPanel extends JComponent
{
  private String m_information;
  private Font m_font;
  private Color m_colorForeground;
  private Color m_colorBackground;

  protected float heightFactor;
  protected int m_alignment = SwingConstants.CENTER;

  InfoPanel(String info, Font font, Color colorFore, Color colorBackground)
  {
    m_information = info;
    m_font = font;
    m_colorForeground = colorFore;

    if (colorFore == null)
    {
      m_colorForeground = Color.BLACK;
    }
    if (colorBackground == null)
    {
      m_colorBackground = Color.GRAY;
    }
    else
    {
      m_colorBackground = colorBackground;
    }
    setOpaque(true);
  }

  @Override
  protected void paintComponent(Graphics g)
  {
    final Graphics2D g2d = (Graphics2D) g.create();
    g2d.setFont(m_font);

    g2d.setColor(m_colorBackground);
    Dimension d = getSize();
    g2d.fillRect(0, 0, d.width, d.height);
    g2d.setColor(m_colorForeground);

    // Get the text bounds
    FontRenderContext fontContext = g2d.getFontRenderContext();
    TextLayout layout = new TextLayout(m_information, m_font, fontContext);
    layout.draw(g2d, 0, 0);
    Rectangle2D bounds = layout.getBounds();

    int posX = 10;
    int width = (int) bounds.getWidth();
    int height = (int) bounds.getHeight();
    if (m_alignment == SwingConstants.CENTER)
    {
      posX = (d.width - width) / 2;
    }
    else if (m_alignment == SwingConstants.RIGHT)
    {
      posX = d.width - width - posX;
    }
    // Center vertically
    FontMetrics fm = g2d.getFontMetrics();
    int posY = d.height / 2 + height / 2 - fm.getDescent();

    g2d.drawString(m_information, posX, posY);
    // Only drawString shows this problem!
    g2d.drawLine( posX, posY + 5, posX + width, posY + 5 );

    g2d.dispose();
  }
}

TestInfoPanel.java

import java.awt.*;

import javax.swing.*;

public class TestInfoPanel
{
  private JPanel m_panel;

  TestInfoPanel()
  {
  }

  private JScrollPane getContent()
  {
    m_panel = new JPanel(new GridLayout(0, 1));
    m_panel.add(new InfoPanel("A Title jqpgy_@,;!§",
        new Font("Arial", Font.PLAIN, 24),
        Color.RED, Color.LIGHT_GRAY));
    m_panel.add(new InfoPanel("A Sub-Title jqpgy_@,;!§",
        new Font("Tahoma", Font.PLAIN, 18),
        Color.BLUE, Color.YELLOW));
    m_panel.add(new JPanel());
    return new JScrollPane(m_panel);
  }

  public static void main(String[] args)
  {
    final TestInfoPanel tm = new TestInfoPanel();
    SwingUtilities.invokeLater(new Runnable()
    {
      @Override
      public void run()
      {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setTitle(tm.getClass().getName());
        f.setContentPane(tm.getContent());
        f.setSize(800, 400);
        f.setLocation(200, 200);
        f.setVisible(true);
      }
    });
  }
}

Here is what I see: Graphics Bug: echo of text Tested on Windows 7, seen in Java 5, 6, 7.

Was it helpful?

Solution

It seems like layout.draw draws the text in the top-left corner, and then you draw it again using g2d.drawString. You can just remove the g2d.drawString and pass the proper position directly to layout.draw instead.

layout.draw(g2d, posX, posY);

(Or remove layout and use only g2d.drawString; seems to work as well.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top