如何在JPanel中对齐仅包含文本的JLabel?

时间:2012-05-18 18:50:42

标签: java swing jpanel jlabel

通常情况下,我只需使用字符串作为第一个参数创建JLabel,并使用JLabel.CENTER作为第二个参数;使用BorderLayout.CENTER将标签添加到面板会导致标签中的文本在面板的中心对齐。

但是,我正在使用'RichJLabel'类来为我的文本留下阴影。为此,它会以对齐信息丢失的方式覆盖Component.paintComponent,并且无论我做什么,标签的文本都会绘制在面板的左上角。

据我所知,解决方法是将标签封装在另一个面板内;这样,我可以将面板本身对齐在父面板内,但我不确定如何做到这一点。

我的完整目标是:

  • 找出给定字符串填充其父JPanel所需的字体大小
  • 为该文字添加投影
  • 将文本置于其JPanel中

这是我到目前为止所得到的:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;

public class RichJLabel extends JLabel {

    private int tracking;

    public RichJLabel(String text, int tracking) {
        super(text, JLabel.CENTER);
        this.tracking = tracking;
    }

    private int left_x, left_y, right_x, right_y;
    private Color left_color, right_color;

    public void setLeftShadow(int x, int y, Color color) {
        left_x = x;
        left_y = y;
        left_color = color;
    }

    public void setRightShadow(int x, int y, Color color) {
        right_x = x;
        right_y = y;
        right_color = color;
    }

    public Dimension getPreferredSize() {
         String text = getText();
         FontMetrics fm = this.getFontMetrics(getFont());

         int w = fm.stringWidth(text);
         w += (text.length()-1)*tracking;
         w += left_x + right_x;
         int h = fm.getHeight();
         h += left_y + right_y;

         return new Dimension(w,h); 
}

public void paintComponent(Graphics g) {

        ((Graphics2D)g).setRenderingHint(
            RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        char[] chars = getText().toCharArray();

        FontMetrics fm = this.getFontMetrics(getFont());

        int h = fm.getAscent();
        int x = 0;

        for(int i=0; i<chars.length; i++) {
            char ch = chars[i];
            int w = fm.charWidth(ch) + tracking;

            g.setColor(left_color);
            g.drawString(""+chars[i],x-left_x,h-left_y);

            g.setColor(right_color);
            g.drawString(""+chars[i],x+right_x,h+right_y);

            g.setColor(getForeground());
            g.drawString(""+chars[i],x,h);

            x+=w;
    }

        ((Graphics2D)g).setRenderingHint(
            RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);

    } // end paintComponent()

public static void main(String[] args) {

  JPanel panel1 = new JPanel( new BorderLayout() );
  panel1.setBackground( Color.BLUE );
  panel1.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED ));

  JPanel interiorPanel = new JPanel( new BorderLayout() );
  panel1.add(interiorPanel, BorderLayout.CENTER);
  RichJLabel label = new RichJLabel("100", 0);
  label.setHorizontalAlignment(JLabel.CENTER);
  label.setVerticalAlignment(JLabel.CENTER);
  label.setVisible( true );
  label.setForeground( Color.YELLOW );

  interiorPanel.add(label, BorderLayout.CENTER);
  label.setFont(new Font("Arial", Font.BOLD, 140));
  label.setFont(label.getFont().deriveFont(140f));


  //resize code
  Font labelFont = label.getFont();
  String labelText = label.getText();
  int stringWidth = label.getFontMetrics(labelFont).stringWidth(labelText);
  int componentWidth = interiorPanel.getWidth();

  // Find out how much the font can grow in width.
  double widthRatio = (double)componentWidth / (double)stringWidth;
  int newFontSize = (int)(labelFont.getSize() * widthRatio);
  int componentHeight = interiorPanel.getHeight();

  // Pick a new font size so it will not be larger than the height of label.
  int fontSizeToUse = Math.min(newFontSize, componentHeight);
  // Set the label's font size to the newly determined size.
  label.setFont(new Font(labelFont.getName(), Font.BOLD, fontSizeToUse));
  label.setLeftShadow(-3,-3,Color.BLACK);     

  // drop shadow w/ highlight
  label.setRightShadow(2,3,Color.black);
  label.setForeground(Color.gray);

  JFrame frame = new JFrame("Label SSCCEE");
  frame.getContentPane().add(panel1);
  frame.pack();
  frame.setVisible(true);
 }
}

它现在做的是:

gray box inside blue panel

2 个答案:

答案 0 :(得分:3)

代码太快检查容器的大小。在显示之前,它的宽度/高度为0.

Text with shadow

更改代码

import java.awt.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;

public class RichJLabel extends JLabel {

    private int tracking;

    public RichJLabel(String text, int tracking) {
        super(text, JLabel.CENTER);
        this.tracking = tracking;
    }

    private int left_x, left_y, right_x, right_y;
    private Color left_color, right_color;

    public void setLeftShadow(int x, int y, Color color) {
        left_x = x;
        left_y = y;
        left_color = color;
    }

    public void setRightShadow(int x, int y, Color color) {
        right_x = x;
        right_y = y;
        right_color = color;
    }

    public Dimension getPreferredSize() {
         String text = getText();
         FontMetrics fm = this.getFontMetrics(getFont());

         int w = fm.stringWidth(text);
         w += (text.length()-1)*tracking;
         w += left_x + right_x;
         int h = fm.getHeight();
         h += left_y + right_y;

         return new Dimension(w,h);
}

public void paintComponent(Graphics g) {

        ((Graphics2D)g).setRenderingHint(
            RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        char[] chars = getText().toCharArray();

        FontMetrics fm = this.getFontMetrics(getFont());

        int h = fm.getAscent();
        int x = 0;

        for(int i=0; i<chars.length; i++) {
            char ch = chars[i];
            int w = fm.charWidth(ch) + tracking;

            g.setColor(left_color);
            g.drawString(""+chars[i],x-left_x,h-left_y);

            g.setColor(right_color);
            g.drawString(""+chars[i],x+right_x,h+right_y);

            g.setColor(getForeground());
            g.drawString(""+chars[i],x,h);

            x+=w;
    }

        ((Graphics2D)g).setRenderingHint(
            RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);

    } // end paintComponent()

public static void main(String[] args) {

  JPanel panel1 = new JPanel( new BorderLayout() );
  panel1.setBackground( Color.BLUE );
  panel1.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED ));

  JPanel interiorPanel = new JPanel( new BorderLayout() );
  panel1.add(interiorPanel, BorderLayout.CENTER);
  RichJLabel label = new RichJLabel("100", 0);
  label.setLeftShadow(-3,-3,Color.BLACK);

  // drop shadow w/ highlight
  label.setRightShadow(2,3,Color.black);

  label.setHorizontalAlignment(JLabel.CENTER);
  label.setVerticalAlignment(JLabel.CENTER);
  label.setVisible( true );
  label.setForeground( Color.YELLOW );

  interiorPanel.add(label, BorderLayout.CENTER);
  label.setFont(new Font("Arial", Font.BOLD, 140));
  label.setFont(label.getFont().deriveFont(140f));

  //resize code
  Font labelFont = label.getFont();

  JFrame frame = new JFrame("Label SSCCEE");
  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  frame.setContentPane(panel1);
  frame.pack();
  frame.setVisible(true);

  int componentWidth = interiorPanel.getWidth();
  String labelText = label.getText();
  int stringWidth = label.getFontMetrics(labelFont).stringWidth(labelText);
  // Find out how much the font can grow in width.
  double widthRatio = (double)componentWidth / (double)stringWidth;
  int newFontSize = (int)(labelFont.getSize() * widthRatio);
  int componentHeight = interiorPanel.getHeight();

  // Pick a new font size so it will not be larger than the height of label.
  int fontSizeToUse = Math.min(newFontSize, componentHeight);
  System.out.println("fontSizeToUse: " + fontSizeToUse);
  if (fontSizeToUse<1) {
      System.err.println("Font size less than 1!");
      System.exit(1);
  }

  // Set the label's font size to the newly determined size.
  label.setFont(new Font(labelFont.getName(), Font.BOLD, fontSizeToUse));
  label.setForeground(Color.gray);
 }
}

答案 1 :(得分:1)

如果是RichJLabel,请查看paintComponent。我建议制作自己的阴影标签,可能包含两个阴影标签和一个前景标签。我没想到会看到每个角色的3次绘图。有问题:效率低下,无法使用阿拉伯语或组合变音字符(一个字母,另一个重音)等脚本语言。

在某些方面,黑客攻击是不值得的。如果你看过这些消息来源,谁知道。

我不确定我是否拥有正确的代码。它当然可能是一个非常早期的版本。


RichJLabel有getPreferredSize()适合布局。 JPanel.setBounds(int, int, int, int)是调整大小的唯一方法。因此,您可以在JPanel(null布局)中使用绝对布局。

public class EPanel2 extends JPanel {

    private RichJLabel label = new RichJLabel("", 0);
    public EPanel2(String text) {
        super(null);
        setBackground(Color.GREEN.brighter().brighter());

        label.setFont(new Font("Univers", Font.BOLD, 48));
        label.setText(text);
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setVerticalAlignment(JLabel.CENTER);
        label.setForeground(Color.BLUE);
        label.setLeftShadow(2, 2, Color.RED);
        label.setRightShadow(2, 2, Color.ORANGE);
        label.setVisible(true);
        add(label);
    }

    @Override
    public void setBounds(int x, int y, int width, int height) {
        super.setBounds(x, y, width, height);
        Dimension labelSize = label.getPreferredSize();
        int labelX = (width - labelSize.width) / 2;
        int labelY = (height - labelSize.height) / 2;
        label.setBounds(labelX, labelY, labelSize.width, labelSize.height);
    }

}