圆形包装文本需要稍微调整

时间:2014-07-13 23:39:24

标签: java geometry trigonometry

你可能无法说出那么多,但由于某种原因,由于我的算法存在缺陷,一些角色会以某种方式被抵消...如果有人能弄清楚导致它的原因,我会非常感激它和任何批评都是受欢迎的,因为我在java上还是很新。

enter image description here

编辑:如果你看一下上面的图像,那就是我在左右两侧偏移的E

编辑:我认为可能是我计算文字大小与圆圈大小

编辑:好的,所以当我为宽度和高度输入600时,一切似乎都落到了位置,但是因为它从250开始变得更小,例如角色开始变得更偏移和重叠

主要课程:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

/**
 * Created by John on 7/11/2014.
 */
public class Prog14_05 extends Application {
    @Override
    public void start(Stage primaryStage) {
        // Create Pane
        circularText phrase = new circularText("WE ARE ANONYMOUS, " +
                "WE ARE LEGION, WE DO NOT FORGIVE, WE DO NOT FORGET ",
                480, 480);

        // Place clock and label in border pane
        GridPane pane = new GridPane();
        pane.setPadding(new Insets(phrase.getTextSize() * 2));
        pane.setAlignment(Pos.CENTER);
        pane.setStyle("-fx-background-color: black");
        pane.getChildren().add(phrase);

        // Create a scene and place it in the stage
        Scene scene = new Scene(pane);
        primaryStage.setTitle("Exercise14_05");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

circularText类:

import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;

/**
 * Created by John on 7/11/2014.
 */
public class circularText extends Pane {
    double textSize = 30;
    String string = "";
    String fontName = "";
    Font font;
    // Pane's width and height
    private double w = 250, h = 250;

    /** Create Constructor */
    public circularText (String phrase, double w, double h) {
        this.w = w;
        this.h = h;
        this.string = phrase;
        textSize = (this.w / this.string.length()) * 2;
        Font font = new Font("Times Roman", textSize);

        paintText(this.string, this.font);
    }

    /** Set new font */
    public void setFont(String name) {
        Font font = new Font(name, textSize);
        this.font = font;
        this.fontName = name;
        paintText(this.string, this.font);
    }

    /** Return textSize */
    public double getTextSize() {
        return this.textSize;
    }

    /** Set textSize */
    public void setTextSize(double textSize) {
        this.textSize = textSize;
        Font font = new Font(fontName, textSize);
        this.font = font;
        paintText(this.string, this.font);
    }

    /** Return pane's width */
    public double getW() {
        return w;
    }

    /** Set pane's width */
    public void setW(double w) {
        this.w = w;
        textSize = (this.w / this.string.length()) * 2;
        paintText(this.string, this.font);
    }

    /** Return pane's height */
    public double getH() {
        return h;
    }

    /** Set pane's height */
    public void setH(double h) {
        this.h = h;
        textSize = (this.w / this.string.length()) * 2;
        paintText(this.string, this.font);
    }

    /** Paint the Letters */
    protected void paintText(String phrase, Font font) {
        // Initialize parameters
        double radius = Math.min(w, h) * 0.8 * 0.5;
        double centerX = w / 2;
        double centerY = h / 2;
        double size = radius / 4 - this.getTextSize();

        // Draw circle
        Circle circle = new Circle(centerX - size - textSize, centerY - size,
            radius);
        circle.setFill(null);
        circle.setStroke(null);
        getChildren().clear();
        getChildren().add(circle);

        // Place text in a circular pattern
        int i = 0;
        double degree = 360 / phrase.length();
        for (double degrees = 0; i < phrase.length(); i++, degrees += degree) {
            double pointX = circle.getCenterX() + circle.getRadius() *
                Math.cos(Math.toRadians(degrees));
            double pointY = circle.getCenterY() + circle.getRadius() *
                Math.sin(Math.toRadians(degrees));
            Text letter = new Text(pointX, pointY, phrase.charAt(i) + "");
            letter.setFont(font);
            letter.setFill(Color.LIME);
            letter.setRotate(degrees + 90);
            getChildren().add(letter);
        }

    }
}

3 个答案:

答案 0 :(得分:1)

我的触发不是很好,所以我无法帮助你。我正在思考&#34; W&#34;可以抵消,而不是&#34; E&#34;。我知道其他版本的Swing&#34; W&#34;以前造成了绘画问题,但我不记得细节。因此,我可能会建议您尝试使用不同的字符来查看这两个位置是否仍有相同的问题。

这是我很久以前在网上发现的圆形绘画的另一个例子。我试过你的文字&#34; WE&#34;是重叠的。我改变了&#34; W&#34;到了&#34; R&#34;它似乎工作正常,所以也许这证实了我的上述陈述?

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Font;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
//import com.sun.awt.AWTUtilities;

public class SplashPortalPanel6 extends JPanel
{
    private static final long serialVersionUID = 1L;
//    private static final char[] MESSAGE = "  SplashPortal.net".toCharArray();
    private static final char[] MESSAGE = "  WE ARE ANONYMOUS, WE ARE LEGION, WE DO NOT FORGIVE, WE DO NOT FORGET ".toCharArray();
//    private static final char[] MESSAGE = "  RE ARE ANONYMOUS, RE ARE LEGION, RE DO NOT FORGIVE, RE DO NOT FORGET ".toCharArray();

    private static final double R90 = Math.toRadians(90);
    private static final double R_90 = Math.toRadians(-90);

    private AffineTransform cumalativeRotation = new AffineTransform();
    private double rotation = Math.toRadians(360.0 / MESSAGE.length);

    private Font font = new Font("Impact",Font.ITALIC,40);

    private final Timer timer = new Timer(1000/76, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            repaint();//just repaint
        }
    });

    public SplashPortalPanel6() {
      setPreferredSize(new java.awt.Dimension(600, 600));
      setOpaque(false);
    }

    //This method is called when the panel is connected to a native
    //screen resource.  It's an indication we can now start painting.
    public void addNotify() {
        super.addNotify();
        timer.start();
    }
    public void removeNotify() {
        super.removeNotify();
        timer.stop();
    }

    private static final GradientPaint gradient = new GradientPaint(0F, 0F, Color.BLUE, 5F, 10F, Color.CYAN, true);

    private static final int x = 0, y = 0, w = 100, h = 100;

    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2.setFont(font);
        g2.translate( getWidth()/2, getHeight()/2 );
        cumalativeRotation.rotate(rotation/50);
        g2.transform( cumalativeRotation );

        for(int i = 0; i < MESSAGE.length; i++) {
            // fill the rectangle
            g2.translate(250, 0);
            g2.rotate(R90);
            g2.setColor(Color.BLACK);
//            g2.fillRect(x,y,w,h);
            // draw the border
            g2.setColor(Color.WHITE);
//            g2.drawRect(x,y,w,h);
            // draw the character
            g2.setPaint(gradient);
            g2.drawChars(MESSAGE,i, 1, x+30, y+50);
            g2.rotate(R_90);
            g2.translate(-250, 0);
            g2.rotate(rotation);
        }
    }

    public static void createAndShowSplashScreen() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setUndecorated(true);
        frame.setContentPane(new SplashPortalPanel6());
        frame.pack();
        frame.setLocationRelativeTo(null);
//        AWTUtilities.setWindowOpaque(frame, false);
        //frame.setAlwaysOnTop(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowSplashScreen();
            }
        });
    }
}

注意,如果您取消注释&#34; fillRect&#34;和&#34; drawRect&#34;语句您将看到代码的原始实现。当然,您需要使用较短的第一个消息字符串来查看效果。

答案 1 :(得分:1)

添加

    letter.setTextAlignment(TextAlignment.CENTER);
    letter.setWrappingWidth(100);

不确定JavaFX Text渲染是怎么回事。

数学看似正确。为了清楚起见,编码时会建议添加明确的输入,以确保不会将浮点数与整数混合使用。而不是

双中心Y = h / 2;

double centerY = h / 2.0d;

(还要拿出额外的“这个。”杂乱,许多方法都没有像“setH”那样使用,并且使类名称大写为CircularText)

答案 2 :(得分:0)

这就是我到目前为止所做的事情,让我知道你们的想法以及可以改进的地方......

import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;

/**
 * Created by John on 7/11/2014.
 */
public class CircularText extends Pane {
    private double circleWidth;
    private double circleHeight;
    private double textSize;
    private double textStartDegree;
    private double textRotate;
    private double gapSpacing;
    private double offSetX;
    private double offSetY;
    private Font font;
    private Paint textFill;
    private String fontName;
    final String text;

    /** Default Constructor */
    public CircularText(String text) {
        this.circleWidth = 250;
        this.circleHeight = 250;
        this.text = text;
        textSize = (this.circleWidth / this.text.length()) * 2;
        this.font = new Font("Times Roman", textSize);
        this.textFill = Color.BLACK;
        this.textStartDegree = 240;
        this.textRotate = 90;
        this.gapSpacing = 0.975;
        this.offSetX = 4;
        this.offSetY = 3;
        paintText(this.text, this.font);
    }

    /** Create Constructor */
    public CircularText (String text, double w, double h) {
        this.circleWidth = w;
        this.circleHeight = h;
        this.text = text;
        textSize = (this.circleWidth / (this.text.length()) * 2);
        this.font = new Font("Times Roman", textSize);
        this.textFill = Color.BLACK;
        this.textStartDegree = 240;
        this.textRotate = 90;
        this.gapSpacing = 0.975;
        this.offSetX = 4;
        this.offSetY = 3;
        paintText(this.text, this.font);
    }

    /** Get font color */
    public Paint getTextFill() {
        return textFill;
    }

    /** Set font color */
    public void setTextFill(Paint textFill) {
        this.textFill = textFill;
        this.font = new Font(fontName, textSize);
        paintText(this.text, this.font);
    }

    /** Get starting position for text */
    public double getTextStartDegree() {
        return textStartDegree;
    }

    /** Set starting position for text */
    public void setTextStartDegree(double textStartDegree) {
        this.textStartDegree = textStartDegree;
        this.font = new Font(fontName, textSize);
        paintText(this.text, this.font);
    }

    /** Get letter rotation */
    public double getTextRotate() {
        return textRotate;
    }

    /** Set letter rotation */
    public void setTextRotate(double textRotate) {
        this.textRotate = textRotate;
        this.font = new Font(fontName, textSize);
        paintText(this.text, this.font);
    }

    /** Get spacing between ending and beginning of phrase */
    public double getGapSpacing() {
        return gapSpacing;
    }

    /** Set spacing between ending and beginning of phrase */
    public void setGapSpacing(double gapSpacing) {
        this.gapSpacing = gapSpacing;
        this.font = new Font(fontName, textSize);
        paintText(this.text, this.font);
    }

    /** Get current font */
    public Font getFont() {
        return this.font;
    }

    /** Set new font */
    public void setFont(String name) {
        this.font = new Font(name, textSize);
        this.fontName = name;
        paintText(this.text, this.font);
    }

    /** Return textSize */
    public double getTextSize() {
        return this.textSize;
    }

    /** Set textSize */
    public void setTextSize(double textSize, double offSetX, double offSetY) {
        this.textSize = textSize;
        this.offSetX = offSetX;
        this.offSetY = offSetY;
        this.font = new Font(fontName, textSize);
        paintText(this.text, this.font);
    }

    /** Return circle's width */
    public double getCircleWidth() {
        return circleWidth;
    }

    /** Set circle's width */
    public void setCircleWidth(double w) {
        this.circleWidth = w;
        textSize = (this.circleWidth / this.text.length()) * 2;
        paintText(this.text, this.font);
    }

    /** Return circle's height */
    public double getCircleHeight() {
        return circleHeight;
    }

    /** Set circle's height */
    public void setCircleHeight(double h) {
        this.circleHeight = h;
        textSize = (this.circleWidth / this.text.length()) * 2;
        paintText(this.text, this.font);
    }

    /** Paint the Letters */
    protected void paintText(String text, Font font) {
        getChildren().clear();
        // Initialize parameters
        double radius = Math.min(circleWidth, circleHeight) * 0.8 * 0.5;
        double centerX = circleWidth / 2;
        double centerY = circleHeight / 2;

        // Place text in a circular pattern
        int i = 0;
        double degree = 360.0 / (text.length() / this.gapSpacing);
        for (double degrees = this.textStartDegree;
             i < text.length(); i++, degrees += degree) {
            double pointX = centerX + radius *
                Math.cos(Math.toRadians(degrees)) - (this.textSize) *
                this.offSetX;
            double pointY = centerY + radius *
                Math.sin(Math.toRadians(degrees)) - (this.textSize) *
                this.offSetY;
            Text letter = new Text(pointX, pointY,
                String.valueOf(text.charAt(i)));
            letter.setFont(font);
            letter.setFill(this.textFill);
            letter.setRotate(degrees + this.textRotate);
            letter.setTextAlignment(TextAlignment.CENTER);
            getChildren().add(letter);
        }

    }
}

使用Courier New字体测试后,它看起来完美无瑕。我还用其他字体测试了这一点,一切仍然正确呈现。看来我的代码中的缺陷与我为故障排除创建的Circle对象相关,并且由于某种原因决定在我的算法中使用。删除此Circle对象并修复代码中的小缺陷并增加灵活性后,一切都运行良好:)

Wrapping Text in a Circular Pattern

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 * Created by John on 7/11/2014.
 */
public class Prog14_05 extends Application {
    @Override
    public void start(Stage primaryStage) {
        // Create Pane
        CircularText phrase = new CircularText("TESTING MY CIRCULAR" +
                "TEXT OBJECT CLASS",
                500, 500);
        phrase.setFont("Courier New");
        phrase.setTextFill(Color.LIME);
        phrase.setTextSize(20);

        // Place clock and label in border pane
        GridPane pane = new GridPane();
        pane.setPadding(new Insets(phrase.getTextSize()));
        pane.setAlignment(Pos.CENTER);
        pane.setStyle("-fx-background-color: black");
        pane.getChildren().add(phrase);

        // Create a scene and place it in the stage
        Scene scene = new Scene(pane);
        primaryStage.setTitle("Exercise14_05");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

P.S测试我的代码并告诉我您是否发现任何错误,感谢大家的帮助