Formatting with java: Mixing text and pictures - java

I have a certain text, that i want to annotate for the user. Unfortunately i don't even see where to begin. My algorithm gives as output a range on a string. What i am going for is something like this:
I would need two ways to marker the Characters ( Blue line, red line), maybe also to invert the character (Give a character a different background), or make them fat. What is especially difficult is aligning the Pictures (here designated by two black dots) with the characters. Since the characters should be in Courier New, i could know where to put the offset, but i cannot seem to do it.
Lastly i would have to apply a break after X characters and begin a new line, just like in the picture. I have not found any example how to approach this with java yet. With python i could use ImageDraw, but i am out of the water with java.
is it possible to show this in a canvas on the screen and export this as svg or pdf? I dont know any libraries that could do this. So i would be happy to receive some suggestions/examples also along this way.

The key is to deal with the FontMetrics API. The best you can do is looking at this reference doc.
Here is a sample code demonstrating this usage. It draws red and blue lines around an "Hello world" text according a range of chars.
The text is inside a JLabel, but you can adapt the paint method on any component (but you will have to call graphics.drawChars to paint the text.)
(the code is not very nice, but it demonstrates the usage of FontMetrics)
package com.example.swing;
import javax.swing.*;
import java.awt.*;
public class DemoFontMetrics {
public static void main(String[] args){
JFrame frame = new JFrame();
DecoratedLabel label = new DecoratedLabel("hello world !",new int[]{2,4}, new int[]{6,9});
JPanel textContainer = new JPanel(new FlowLayout());
textContainer.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
textContainer.add(label);
frame.getContentPane().add(textContainer);
frame.pack();
frame.setVisible(true);
}
private static class DecoratedLabel extends JLabel{
int startBlue;
int endBlue;
int startRed;
int endRed;
private DecoratedLabel(String text, int[] blueRange, int[] redRange) {
super(text);
startBlue = blueRange[0];
endBlue = blueRange[1];
startRed = redRange[0];
endRed = redRange[1];
}
#Override
public void paint(Graphics g) {
super.paint(g); //draw text
//set line with : 3
Stroke stroke = new BasicStroke(3f);
((Graphics2D)g).setStroke(stroke);
FontMetrics fm = g.getFontMetrics();
int h = fm.getHeight();
//compute blue line coordonate
fm.stringWidth(getText().substring(0,startBlue));
int x1 = fm.stringWidth(getText().substring(0, startBlue));
int x2 = fm.stringWidth(getText().substring(0, endBlue));
g.setColor(Color.BLUE);
g.drawLine(x1,0,x2,0);// draw blue line
//compute red line coordonates
int x3 = fm.stringWidth(getText().substring(0,startRed));
int x4 = fm.stringWidth(getText().substring(0, endRed));
g.setColor(Color.RED);
g.drawLine(x3,h-1,x4,h-1); // draw redline
}
}
}

If the text is displayed via JTextPane you can conveniently define a custom HighlightPainter, that draws lines above or under the text.
Then you can add highlights to the text pane programmatically by calling:
textPane.getHighlighter().addHighlight(startPos, endPos,
myLineHighlightPainter);
Images may as well easily be added to the pane, by:
textPane.setIcon(myImageIcon);

You can create svg directly for example: http://xmlgraphics.apache.org/batik/ it's an xml based vector graphics format.
EDIT: You can display svg in java, you can create pdf's with it from java. You can publish it in the web (simply as svg).

Related

Is it possible to highlight a character partially?

Is it possible to achieve something like this in Swing :
Notice here A is colored partially.
I know may be its not possible with DefaultHighlighter class alone.
(Text displayed on JTextArea)
Any solutions to achieve this in Swing's alone or have to apply CSS?
EDIT:
If that is not possible with swing, any solution with the below tags ?
Something like this is possible with Java 2D but not with JTextArea. So you can create code which renders this in a frame but I don't think you'll find an easy way to add support for this to the text editors (well, you could always embed an image in a text editor but that's probably not what you want).
[EDIT] For a text display for a karaoke player, Java 2D is the way to go. The Java editor APIs will just get in your way.
Here is an example for rendering text with a gradient:
public void sayWorld(Graphics2D g2D, int x, int y, boolean shear) {
final String txt = "Hello World!";
// gradient color from blue to red
GradientPaint gp = new GradientPaint((float)x, (float)y, Color.blue,
x+100, y+20, Color.red);
g2D.setPaint(gp);
if (shear) g2D.shear(-0.5,0.0);
else g2D.shear(+0.5, 0);
g2D.drawString(txt, x, y);
FontRenderContext frc = new FontRenderContext(null,false,false);
TextLayout tl = new TextLayout(txt, font, frc);
AffineTransform textAt = new AffineTransform();
//textAt.translate(0, (float)tl.getBounds().getHeight());
textAt.translate(x,y);
//textAt.shear(-0.5,0.0);
Shape outline = tl.getOutline(textAt);
g2D.setColor(Color.yellow);
BasicStroke wideStroke = new BasicStroke(2);
g2D.setStroke(wideStroke);
g2D.draw(outline);
}
(source)
Basically, you render get the text layout from a single line of the lyrics, then convert that into a shape (= the outline of each letter). You can then use this shape as a clip area to render the gradient.
In your case, you need an abrupt gradient which is twice as wide as the longest text line that you want to render. Shift it appropriately to get the gradient change in the place of the text where you need it.

Positioning GUI Components with Absolute Layout

I know there are many questions on here already about positioning components using absolute layout, but they don't seem to answer my questions.
I'm working on creating a Solitaire game in java to better learn GUI components. I seem to understand the various ActionListener classes I'm using, but I'm having trouble positioning components where I want them in the window.
I'm trying to set up the window in a format that resembles the basic solitaire layout (deck, discard pile, 4 suit stacks at the top and 7 solitaire stacks below them). My thought process was that I'd need to use an absolute layout in my JFrame component to manually place the different stack elements where they should go (maybe this isn't the best approach?). In doing so, I've tried using setLocation(x, y), setLocation(Point), setBounds(x, y, width, height), etc and nothing seems to work. I just get a blank window.
Here's an example of my code trying to manually place components in the window:
public class SolitaireTable extends JFrame {
public static final int SUIT_STACK_CNT = 4;
public static final int SOL_STACK_CNT = 7;
public static final Point DECK_POS = new Point(5,5);
public static final Point DISCARD_POS = new Point(73+10, 5); //73 is width of card images and 10 gives it a 5 px border to left and right
public static final Point SUIT_STACK_POS = new Point(DISCARD_POS.x + 73 + 92, 5);
public static final Point SOL_STACK_POS = new Point(DECK_POS.x, DECK_POS.y + 97 + 5); //97 is heigh of card image. 5 gives it a border of 5
public SolitaireTable()
{
setLayout(null);
ImageIcon cardImg = new ImageIcon("images/2c.gif");
Card card1 = new Card(cardImg);
add(card1);
card1.setBounds(50, 50, card1.getWidth(), card1.getHeight());
}
public static void main(String[] args)
{
SolitaireTable table = new SolitaireTable();
table.setTitle("Solitaire");
table.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table.setVisible(true);
table.setSize(800, 600);
}
}
public class Card extends JComponent {
private ImageIcon img;//current image displayed (either front or back of card)
private Point coords;
private String suit;
private int face; //use ints instead of strings to make descending face pattern calculations easier. 0 = ace, 1= 2, 10 = j, 12 = k, etc
private String color;
private boolean revealed; //whether see face or back of card
private ImageIcon frontImage; //image of card's face side (set in constructor)
public Card(ImageIcon img){
this.img = img;
}
public void moveTo(Point p) {
coords = p;
}
//================================================================= getWidth
public int getWidth() {
return img.getIconWidth();
}
//================================================================ getHeight
public int getHeight() {
return img.getIconHeight();
}
}
I've been scouring the internet for days trying to figure out how to position components in an absolute layout but haven't found much. Any help would be greatly appreciated. Thanks.
You create your Card class with an ImageIcon, but you never paint the Icon anywhere so there is nothing to paint and you get an empty screen.
You need to add painting code to your class. See the section from the Swing tutorial on Custom Painting for more information and working examples.
Or maybe you create a JLabel and add the Icon to the label and then add the label to the component. (Don't forget to set the layout manager of your card component if you use this approach).
Or you could just create a JLabel with the Icon. Then you would extend JLabel, instead of JComponent to add your custom methods.
Are you using Absolute layout ?
Absolute Layout is DEPRECATED ..... Have a look
here
From docs: Absolute layouts are less flexible and harder to maintain than other types of layouts without absolute positioning.
However, if it fits your special purpose, just use it.
You can use RelativeLayouts as described here:
Set the absolute position of a view

Visual Custom Grid

I am new to Swing in Java and am trying to make a visual grid. I have some simple questions as to how to do the following. Here are some characteristics of the grid:
For each square of the grid, I should be having an equivalent index(i,j) using which I can identify the square and place a text.
Edit - (i,j) is the row/column value - the index of the square in the grid.
The diagonals of the squares should be drawn and each of the four divisions of the square should be having a different color.
Any suggestions as to how to do so.
Given row and column you will need to know the number of columns per row. With this information you can simply do (row * columns) + column which will return the index of the square.
For example, with 8 columns per row, a request for
row = 0, column = 4, will return 4
row = 1, column = 4, will return 12
row = 0, column = 0, will return 0
Rendering the sections of the square is more complex and can be achieved in at least two ways. You could use a Polygon which generates a triangle for each section or Shape and simply use Graphics2D#fill to fill it.
This will come down to how you physically render each square...
Take a look at 2D Graphics for more details and this for an example of both.
A Shape would be much easier to rotate and position and would only require you to have a single instance (or a single instance for each square based on your needs), where as you would require at least 4 Polygons or do some fun rotation...
Updated with simple example
All done with rotating triangles...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DividedSquare {
public static void main(String[] args) {
new DividedSquare();
}
public DividedSquare() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private TriangleShape baseTriangle;
private Color[] colors;
public TestPane() {
colors = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA};
}
#Override
public void invalidate() {
super.invalidate();
baseTriangle = new TriangleShape(
new Point(0, 0),
new Point(getWidth(), 0),
new Point(getWidth() / 2, getHeight() / 2));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text[] = new String[]{
"123.123",
"456.789",
"012.315",
"678.921"
};
FontMetrics fm = g2d.getFontMetrics();
double angel = 0;
for (int index = 0; index < 4; index++) {
g2d.setColor(colors[index]);
Path2D rotated = rotate(baseTriangle, angel);
g2d.fill(rotated);
Rectangle bounds = rotated.getBounds();
int x = bounds.x + ((bounds.width - fm.stringWidth(text[0])) / 2);
int y = bounds.y + (((bounds.height - fm.getHeight()) / 2) + fm.getAscent());
g2d.setColor(Color.WHITE);
g2d.drawString(text[index], x, y);
angel += 90;
}
g2d.setColor(Color.BLACK);
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.drawLine(getWidth(), 0, 0, getHeight());
g2d.dispose();
}
public Path2D rotate(TriangleShape shape, double angel) {
Rectangle bounds = shape.getBounds();
int x = bounds.width / 2;
int y = bounds.width / 2;
return new Path2D.Float(shape, AffineTransform.getRotateInstance(
Math.toRadians(angel),
x,
y));
}
}
public class TriangleShape extends Path2D.Double {
public TriangleShape(Point2D... points) {
moveTo(points[0].getX(), points[0].getY());
lineTo(points[1].getX(), points[1].getY());
lineTo(points[2].getX(), points[2].getY());
closePath();
}
}
}
Yes, see Making a robust, resizable Chess GUI for a GUI that uses a GridLayout to contain JButton objects. The buttons are held in an 8x8 array (the chessboard), while displayed in a 9 row x 9 column grid layout to accommodate the row (8-1) & column (A-H) identifiers of the board.
Buttons will accept an image that might represent the '4 color diagonal' and text. In the chess board I only use images (the chess pieces).
Edit 1
What is the actual difference between the 4 colored areas (besides the color). E.G. is there supposed to be different functionality depending on which of the diagonal areas the user clicks in?
Each of the 4 colored areas in the square has a value from a table based on some algorithm. The color depends upon the value. Currently, it is just used as an indicator. But the user needs to select an initial square in the grid where I place a mark that it is initial.
And the text. Should it be on top of the '4 color diagonal', beside it, below it..?
I also plan to place a text in each of the region indicating that value. Hence, there is one text field to be placed in each of the four partitions of the square.
Text field or label? A label can show text, but a text field makes it possible to copy the text or change it.
I need a text field because I need to change the text during the course of the algorithm.
By 'I' DYM the program, or the user? The program can change text in a label or text field, but the text field is user editable.
I mean the program
OK - Draw the design and text on an image. Use the image as a button icon. The user can select an initial square by clicking the button. If the text changes, generate a new image and set it to the button.
Edit 2
So do you mean that I have to create an image with 4 colors? Would that not be difficult. I would like to change the colors from the program itself. My algorithm would generate the values and at certain points of the algorithm, I would like to see the visualization.
Not if you generate the image at run-time.
How do I generate an image at run-time?
See the answer to Example images for code and mark-up Q&As The first set of Icons..
...
..As well as the Sprite sheet..
..were generated at run-time in Java code. Each set of images links to the question that includes the code that generated them.
I believe you're describing the SetGridLayout feature in swing. If you want a tutorial on how to set up such a window, you can find it here:
http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html
After reading your question a second time... I think you plan on drawing a grid...
I'd look into the Draw.java library
Maybe you can try to do this adding a jTable object, this object contains methods that can put values in every value i and j respectively like:
jTable1.setValueAt(Value, i, j);
this will allows you to change the value in every cell.

Changing the colour of text in drawstring()

I'm trying to add emphasis to one work in a string im drawing using swing.
I was advised to use HTML with the following code:
Graphics2D g2 = (Graphics2D) g;
g.drawString("this is something I want people to <p color="#00FF00">NOTICE</p>", x, y);
I tried this but had no luck... it just outputs the HTML
Can anyone point me in the right direction?
How does this compile: g.drawString("this is something I want people to <p color="#00FF00">NOTICE</p>", x, y); as ' " ' is a special character we must escape it with \
You cast to Graphics2D but dont use it (not relevant to problem but can cause anomalies).
It should be:
Graphics2D g2 = (Graphics2D) g;
g2.drawString("this is something I want people to <p color=\"#00FF00\">NOTICE</p>", x, y);
to add colour simply call setColor(Color c) on Graphics object:
g2.setColor(Color.GREEN);
However this will set the entire String to be drawn green, if you want only parts to be drawn green use JLabel for HTML support (up to HTML3.2):
JLabel label = new JLabel("<html>this is something I want people to <p color=\"#00FF00\">NOTICE</p></html>");
full example:
NB As you can see notice is on its own line thats because of the paragraph tag rather use font tag to get it on a single line like so:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Test {
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("<html>this is something I want people to <p color=\"#00FF00\">NOTICE</p></html>");
// JLabel label = new JLabel("<html>this is something I want people to <font color=\"#00FF00\">NOTICE</font></html>");//will be shown on single line
frame.add(label);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
Use Graphics.setColor() to change the color of anything you do. Or use a JLabel to set the color on.
Use a JLabel for styled text. See LabelRenderTest for how it can be drawn to an image & used in paint.
Using Graphics/AWT methods
The string implies NOTICE should be green, but the rest default (black). We would need to call drawString(String) twice with the colors of the two parts of the string, offsetting the latter string by the width of the first. To get the width, see things like FontMetrics or a GlyphVector. This answer uses a GlyphVector to get an outline of the letters.
If you're just creating a simple label with emphasis on a word, you can just assign the HTML straight onto the JLabel like this...
JLabel label = new JLabel("<html>this is something I want people to <p color='#00FF00'>NOTICE</p>");
As long as you have the <html> piece at the beginning of the String for a JLabel, it will use the HTML renderer to paint it.
As pointed out by #AndrewThompson, however, the <p> will force the colored text on to a new line, so perhaps <span> would be more appropriate...
JLabel label = new JLabel("<html>this is something I want people to <span style='color:#00FF00;'>NOTICE</span>");
you can use g.setColor(Color.BLUE) before g.drawString(). (For example Color.BLUE)
You could add g.setColor(Color.Chosen Color);and then write the string out with g.drawString()
perhaps

How to draw a two dimensional graphic at Java?

I have 2 different lists. Each of them holds x and y value pairs(they have both positive and negative values). How can I draw them on a 2D axis? I want to put points for every value and they will blue for first list and red for second list.
My lists' type:
List<List<Double>>
List<Double> inside of List<...> has 2 variables, first of it for x value and the second one is for y value.
However just I need to how to draw a two dimensional graphic at Java(desktop application) and put points wherever I want, improving code for my variables is less important.
PS:
I want the more and more simple of that kind of graphic:
Something like:
you could use a library like http://www.jfree.org/jfreechart/ (LGPL-License) there are lots of examples around the web, and it's quite easy to use.
here's an example, that seems to match your requirements:
http://www.java2s.com/Code/Java/Chart/JFreeChartMarkerDemo1.htm
Assuming you are using Swing with a panel, you can use the following:
public class JImagePanelExample extends JPanel {
private BufferedImage image;
private Graphics2D drawingBoard;
private int x, y; // Image position in the panel
// Let's assume image is a chart and you need to draw lines
public JImagePanelExample(BufferedImage image, int x, int y) {
super();
this.image = image;
// Retrieving a mean to draw lines
drawingBoard = image.createGraphics();
// Draw what you need to draw (see other methods too)
drawingBoard.drawLine(0, 10, 35, 55);
}
// Called by Swing to draw the image in the panel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, x, y, null);
}
}
If you don't want to use Swing and you just need to draw in 2D, focus on BufferedImage and Graphics2D only.
There is a Java 2D API: http://java.sun.com/products/java-media/2D/ and many charting libraries easily found with a web search.

Categories