Swing drawString: Text bounds and line wrapping - java

I need to draw text with Graphics#drawString
I'm drawing on top of a JPanel that changes both in width and height (by dragging).
I'm looking for a solution to generate bounds, so that I can warp the lines automatically and adapt the text accordingly, without overflows.
I figured I could just hardcode it myself by getting the length in pixels with fontMetrics, however, I would rather have a component that does this automatically (drawString also doesn't support '\n').
In the docs as well as in this other answer I found this:
Graphics2D g = ...;
Point2D loc = ...;
Font font = Font.getFont("Helvetica-bold-italic");
FontRenderContext frc = g.getFontRenderContext();
TextLayout layout = new TextLayout("This is a string", font, frc);
layout.draw(g, (float)loc.getX(), (float)loc.getY());
Rectangle2D bounds = layout.getBounds();
bounds.setRect(bounds.getX()+loc.getX(),
bounds.getY()+loc.getY(),
bounds.getWidth(),
bounds.getHeight());
g.draw(bounds);
Which does draw the string and the bounds, but they have no effect, so no luck here.
Any class I could use?

Any class I could use?
Another option is to use a LineBreakMeasurer:
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.text.*;
import java.util.Objects;
import javax.swing.*;
import javax.swing.border.Border;
public final class LineBreakMeasurerTest {
private static final String TEXT = "1234567890 ABCDEFG HIJKLMN OPQRSTU VWXYZ";
private final JLabel lbl1 = new JLabel(TEXT);
private final JTextArea lbl2 = new JTextArea(TEXT);
private final JLabel lbl3 = new WrappingLabel(TEXT);
public JComponent makeUI() {
Border b = BorderFactory.createLineBorder(Color.GREEN, 5);
lbl1.setBorder(
BorderFactory.createTitledBorder(b, "JLabel"));
lbl2.setBorder(
BorderFactory.createTitledBorder(b, "JTextArea"));
lbl3.setBorder(
BorderFactory.createTitledBorder(b, "LineBreakMeasurer"));
lbl2.setFont(lbl1.getFont());
lbl2.setEditable(false);
lbl2.setLineWrap(true);
lbl2.setWrapStyleWord(true);
lbl2.setBackground(lbl1.getBackground());
JPanel p = new JPanel(new GridLayout(3, 1));
p.add(lbl1);
p.add(lbl2);
p.add(lbl3);
return p;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
UIManager.put("swing.boldMetal", Boolean.FALSE);
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new LineBreakMeasurerTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class WrappingLabel extends JLabel {
//TEST: private AffineTransform at = AffineTransform.getScaleInstance(.8, 1d);
protected WrappingLabel(String text) {
super(text);
}
#Override protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(getForeground());
Insets i = getInsets();
float x = i.left;
float y = i.top;
int w = getWidth() - i.left - i.right;
AttributedString as = new AttributedString(getText());
//TEST: as.addAttribute(TextAttribute.FONT, g2.getFont());
//TEST: as.addAttribute(TextAttribute.TRANSFORM, at);
AttributedCharacterIterator aci = as.getIterator();
FontRenderContext frc = g2.getFontRenderContext();
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
while (lbm.getPosition() < aci.getEndIndex()) {
TextLayout tl = lbm.nextLayout(w);
tl.draw(g2, x, y + tl.getAscent());
y += tl.getDescent() + tl.getLeading() + tl.getAscent();
}
g2.dispose();
}
}

Simplest solution: use a JTextArea.
You can rig it up so that it doesn't even look like a JTextArea by setting background to null, by making it nonfocusable, and it will automatically wrap words if you call setLineWrap(true) and setWrapStyleWord(true) on it. To have it fill the JPanel, give the panel a BorderLayout, and add the JTextArea BorderLayout.CENTER. You can even set a margin if desired.

Related

How can i draw circle in JFrame without overriding paint(...) or paintComponent(...)

I want to draw circle using a method that I create but I get a nullPointerException
public class GenealogyTreeGUI extends JFrame {
JFrame frame;
Graphics2D g2;
public GenealogyTreeGUI(){
frame = new JFrame("Genealoy Tree");
JPanel panel = new JPanel();
frame.add(panel);
frame.setVisible(true);
panel.setVisible(true);
}
this is my method
public void drawPerson(int x, int y, Person p1){
System.out.println("----------------------DrawPerson---------------------------------");
this.g2.drawOval(x, y, frame.getWidth()/12 , frame.getHeight()/12 );
}
You can:
Create a BufferedImage of the size desired
Get its Graphics object via createGraphics() (for a Graphics2D object) or getGraphics() (for a Graphics object)
Draw with the above graphics object, and then .dispose() it
Create an ImageIcon using the above image via new ImageIcon(myImage)
Display the icon in a JLabel via .setIcon(myIcon)
done
e.g.,
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SomeDrawingFoo extends JPanel {
private static final int IMG_W = 400;
private static final int IMG_H = IMG_W;
private static final Color COLOR_1 = Color.RED;
private static final Color COLOR_2 = Color.BLUE;
private static final float DELTA = 40f;
private JLabel label = new JLabel();
public SomeDrawingFoo() {
// create image and draw with it
BufferedImage myImage = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = myImage.createGraphics();
Paint gradPaint = new GradientPaint(0, 0, COLOR_1, DELTA, DELTA, COLOR_2, true);
g2.setPaint(gradPaint);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillOval(10, 10, IMG_W - 20, IMG_H - 20);
g2.dispose();
// put image into Icon and then into JLabel
Icon myIcon = new ImageIcon(myImage);
label.setIcon(myIcon);
add(label);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SomeDrawingFoo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Notes:
You could also call .getGraphics() on your JPanel or JFrame, but the object obtained would not be stable or long-lasting, and this will lead to images that disappear or that cause a NullPointerException. I most definitely do NOT recommend this
Usually the easiest way to do your graphics is the way that you stated you wished not doing -- draw within a JPanel's protected void paintComponent(Graphics g) method.

Swing Java Rotate JLabel but text be erased

I'm using swing Java to try to do something with java. Now I want to rotate JLabel and I did that. But unfortunelately, a part of my text in JLabel is erased (as in the image below). I have tried search but seem no one has problems as same as mine. I guess it's occured caused JLabels they overlaped.
and this is my code
serviceName[j] = new JLabel(name){
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
AffineTransform aT = g2.getTransform();
Shape oldshape = g2.getClip();
aT.rotate(Math.toRadians(300));
g2.setTransform(aT);
g2.setClip(oldshape);
super.paintComponent(g);
}
};
Can you give me the way to solved it
You should restore original transform and clip after your painting. Like this
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
AffineTransform aT = g2.getTransform();
Shape oldshape = g2.getClip();
g2.rotate(Math.toRadians(300));
super.paintComponent(g);
g2.setTransform(aT);
g2.setClip(oldshape);
}
Your JLabel subclass should also override getPreferredSize() to report the size it will be when it is rotated; otherwise the any layout manager that uses asks your component for its preferred size will use JLabel's version, which assumes the text is drawn horizontally.
Instead of attempting to rotate the component, another approach would be to create a Text Icon and add the Icon to a JLabel.
Once you have created the TextIcon you can then create a Rotated Icon to add to the label. The RotatedIcon will calculate the proper size of the Icon so therefore the size of the label will also be correct and no custom painting is required.
So the basic code would be something like:
JLabel label = new JLabel();
TextIcon textlIcon = new TextIcon(label, "Rotated Text");
label.setIcon( new RotatedIcon(textIcon, 300) );
Edit:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.io.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
OverlapLayout layout = new OverlapLayout(new Point(20, 0));
setLayout( layout );
addLabel("one");
addLabel("two");
addLabel("three or more");
addLabel("four");
}
private void addLabel(String text)
{
JLabel label = new JLabel();
TextIcon textIcon = new TextIcon(label, text);
label.setIcon( new RotatedIcon(textIcon, 300) );
label.setVerticalAlignment(JLabel.BOTTOM);
add(label);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
This example also uses the Overlap Layout so the labels can be painted over top of one another.
You may find some hints from this small program. Experiment on the values of setPrefferedSize to have more ideas. If you still can't solve the problem, please edit and add more codes in your question above.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.*;
public class InclinedLabels extends JFrame{
/** Creates a new instance of InclinedLabels */
public InclinedLabels() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
JPanel jPanel1 = new JPanel();
jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
add(jPanel1);
JPanel jPanel2 = new JPanel();
jPanel2.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jPanel2.setPreferredSize(new Dimension(10, 100));
add(jPanel2, BorderLayout.NORTH);
jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jPanel1.setPreferredSize(new java.awt.Dimension(200, 200));
java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setBounds((screenSize.width-400)/2, (screenSize.height-352)/2, 300, 352);
String str = "The quick brown fox jumps over the lazy dog";
String[] word = str.split(" ");
JLabel[] serviceName = new JLabel[str.length()];
String name;
for (int j=0; j<word.length; j++) {
name = word[j];
serviceName[j] = new JLabel(name){
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
AffineTransform aT = g2.getTransform();
Shape oldshape = g2.getClip();
aT.rotate(Math.toRadians(300));
g2.setTransform(aT);
g2.setClip(oldshape);
super.paintComponent(g);
}
};
serviceName[j].setPreferredSize(new Dimension(50,20));
serviceName[j].setBorder(BorderFactory.createLineBorder(Color.RED));
jPanel1.add(serviceName[j]);
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new InclinedLabels().setVisible(true);
}
});
}
}
Update:
I found a much closer hint that may solve this problem. The big factor here is the component layout. The null layout allows overlapping of JLabel components so it is the most appropriate layout to be used here. Then you have to customize the location and size of the labels through the setBounds method. In the code below there is serviceName[j].setBounds(xOffset + j*20,180, 170, 15); So in every loop iteration, the x location of the label is increased by 20. The size of all labels is 170 by 15. I also placed temporary borders to the components to help in understanding the output.
import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
public class InclinedLabels extends JFrame{
/** Creates a new instance of InclinedLabels */
public InclinedLabels() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setBounds((screenSize.width-360)/2, (screenSize.height-352)/2, 360, 352);
JPanel jPanel1 = new JPanel();
jPanel1.setBorder(BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jPanel1.setLayout(null); // null layout allows overlapping of components
add(jPanel1);
JPanel jPanel2 = new JPanel();
jPanel2.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jPanel2.setPreferredSize(new Dimension(10, 100));
add(jPanel2, BorderLayout.NORTH);
String str = "The quick brown fox jumpsssssssssssss123456 over the lazy dogssssssssssssss123456";
String[] word = str.split(" ");
JLabel[] serviceName = new JLabel[str.length()];
String name;
int xOffset = 30;
for (int j=0; j<word.length; j++) {
name = word[j];
serviceName[j] = new JLabel(name){
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
AffineTransform aT = g2.getTransform();
Shape oldshape = g2.getClip();
aT.rotate(Math.toRadians(300));
g2.setTransform(aT);
g2.setClip(oldshape);
super.paintComponent(g2);
}
};
serviceName[j].setBounds(xOffset + j*20,180, 170, 15); // experiment here
serviceName[j].setBorder(BorderFactory.createLineBorder(Color.RED));
jPanel1.add(serviceName[j]);
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new InclinedLabels().setVisible(true);
}
});
}
}
The limitation that I found in the code above is the width of the parent panel. In the example, the label having the text dogssssssssssssss123456 was not printed in whole. This can be overcome by increasing the width of the frame which in turn increases the width of jPanel1.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
public class Test {
public static void main(String[] args) {
// Create the first label, which will be rotated later.
Test.RotateLabel one = new Test.RotateLabel( "Rotated", 100, 100 );
one.setRotation( 270 );
JLayeredPane pane = new JLayeredPane();
pane.setLayer( one, JLayeredPane.DEFAULT_LAYER );
pane.add( one );
pane.setBorder(new javax.swing.border.LineBorder(Color.BLACK,1));
// Put the container pane in a frame and show the frame.
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( pane );
frame.setSize( 500, 500 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
static class RotateLabel extends JLabel {
private static final long serialVersionUID = 1L;
private int angle = 0;
public RotateLabel( String text, int x, int y ) {
super( text );
setBorder( new javax.swing.border.CompoundBorder(
new javax.swing.border.LineBorder( Color.red, 1), getBorder() ) );
int width = getPreferredSize().width;
int height = getPreferredSize().height;
setBounds(x, y, width, height);
}
#Override
public void paintComponent( Graphics g ) {
Graphics2D gx = (Graphics2D) g;
Shape old = gx.getClip();
gx.rotate(-Math.toRadians(45), getWidth() / 2, getHeight() / 2);
gx.setClip(old);
super.paintComponent(gx);
}
public void setRotation( int angle ) { this.angle = angle; }
}

How can I add images as a JPanel background?

I would like to make four panels using different backgrounds, and merge them together using a BorderLayout. I used JLabel, but I can't add any component to a JLabel, therefore I need to make it as a background.
I've search some code but it only tell how to add a background in JFrame.
import javax.swing.*;
import java.awt.*;
public class LoginPanel extends JFrame{
private ImageIcon top = new ImageIcon("C:/Users/user/Desktop/top.png");
private ImageIcon mid = new ImageIcon("C:/Users/user/Desktop/mid.png");
private ImageIcon center = new ImageIcon("C:/Users/user/Desktop/center.png");
private ImageIcon bottom = new ImageIcon("C:/Users/user/Desktop/bottom.png");
public LoginPanel(){
JPanel topp = new JPanel();
topp.setLayout(new BorderLayout(0,0));
topp.add(new JLabel(top),BorderLayout.NORTH);
JPanel centerp = new JPanel();
centerp.setLayout(new BorderLayout(0,0));
centerp.add(new JLabel(mid),BorderLayout.NORTH);
centerp.add(new JLabel(center),BorderLayout.SOUTH);
topp.add(new JLabel(bottom),BorderLayout.SOUTH);
topp.add(centerp,BorderLayout.CENTER);
add(topp);
}
public static void main(String[] args) {
LoginPanel frame = new LoginPanel();
frame.setTitle("Test");
frame.setSize(812, 640);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I would make a new class called JImagePanel, and then use that:
class JImagePanel extends JComponent {
private static final long serialVersionUID = 1L;
public BufferedImage image;
public JImagePanel(BufferedImage image)
{
this.image = image;
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// scale image
BufferedImage before = image;
int w = before.getWidth();
int h = before.getHeight();
BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale(2.0, 2.0);
AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
after = scaleOp.filter(before, after);
// center image and draw
Graphics2D g2d = (Graphics2D) g;
int x = (getWidth() - 1 - image.getWidth(this)) / 2;
int y = (getHeight() - 1 - image.getHeight(this)) / 2;
g2d.drawImage(image, x, y, this);
g2d.dispose();
}
}
Check out Custom Painting and 2D Graphics
Check out
Add image to panel not using swings
Java: maintaining aspect ratio of JPanel background image
Java background JFrame with a Jpanel arranging images in a grid

Internal padding for JTextArea with background Image

My ultimate goal is to have a JTextArea with a background image. I found code online that showed me how to do this, but now I'm having an issue with the text being on top of the image.
This Is what I mean:
Is there any way I can add a sort of inward indent so that the text is not overlapping the edges of the image?
Here is the raw comment bubble image.
Here is the code:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.GrayFilter;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class myBackgroundSample {
String file;
public myBackgroundSample(String i) {
file = i;
setItUp();
}
public void setItUp() {
final ImageIcon imageIcon = new ImageIcon(file);
JTextArea textArea = new JTextArea() {
Image image = imageIcon.getImage();
public void paint(Graphics g) {
setOpaque(false);
g.drawImage(image, 0, 0, this);
super.paint(g);
}
};
JFrame frame = new JFrame("Background Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane(textArea);
Container content = frame.getContentPane();
content.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String right = "chat1.jpg";
myBackgroundSample temp = new myBackgroundSample(right);
}
}
Use a custom border that extends AbstractBorder. Something like this:
Getting the exact shape & color is left as an exercise for the reader. :)
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
class TextBubbleBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
RenderingHints hints;
TextBubbleBorder(
Color color) {
new TextBubbleBorder(color, 4, 8, 7);
}
TextBubbleBorder(
Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness/2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + pointerSize + strokePad;
insets = new Insets(pad,pad,bottomPad,pad);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
#Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D)g;
int bottomLineY = height-thickness-pointerSize;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0+strokePad,
0+strokePad,
width-thickness,
bottomLineY,
radii,
radii
);
Polygon pointer = new Polygon();
// left point
pointer.addPoint(
strokePad+radii+pointerPad,
bottomLineY);
// right point
pointer.addPoint(
strokePad+radii+pointerPad+pointerSize,
bottomLineY);
// bottom point
pointer.addPoint(
strokePad+radii+pointerPad+(pointerSize/2),
height-strokePad);
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
Area spareSpace = new Area(new Rectangle(0,0,width,height));
spareSpace.subtract(area);
g2.setClip(spareSpace);
g2.clearRect(0,0,width,height);
g2.setClip(null);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JLabel l = new JLabel(
"The quick brown fox jumped over the lazy dog!");
l.setBorder(new TextBubbleBorder(Color.MAGENTA.darker(),2,4,0));
l.setOpaque(true);
l.setBackground(Color.BLACK);
JOptionPane.showMessageDialog(null, l);
}
});
}
}
You should use an Border for that, more specifictly you should use BorderFactory.createEmptyBorder(int top, int left, int bottom, int right):
textArea.setBorder(BorderFactory.createEmptyBorder(10,10,15,10));
You should also override paintComponent instead of paint. Also, use setRows() and setColumns() to set the size of the textArea, then you can use pack() instead of setSize(400,400) which is not recommended. See this example:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class Test extends JFrame {
class MyTextArea extends JTextArea {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.PINK);
g2.setStroke(new BasicStroke(4));
g2.drawRoundRect(3, 3, getWidth()-7, getHeight()-7, 5, 5);
}
}
public Test() {
JPanel panel = new JPanel(new BorderLayout());
JTextArea textArea = new MyTextArea();
textArea.setRows(3);
textArea.setColumns(25);
textArea.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(textArea, BorderLayout.NORTH);
add(panel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}
To post code, indent every line by four spaces.
I assume you are overriding paintComponent()* for your JTextArea. If you are, make sure that it is transparent by adding
setOpaque(false);
*This also works if you override paint(), but as trashgod correctly states, that would interfere with paintBorder().
A better version of TextBubbleBorder.
https://gist.github.com/wenerme/6940534
pointer padding control
pointer side control
dynamic change

Java - setting Fonts/Color in setBorder

Is there a way I can define my own font and color schemes for Text1 AND Text2 text
within the setBorder method. New to java and cannot find it in the SUN tutorials.
My code
//Create Positions Table
JPanel SpreadPanel = new JPanel();
SpreadPanel.setBorder(BorderFactory.createTitledBorder(" Text 1 Text 2"));
Regards
Simon
setBorder(BorderFactory.createTitledBorder(null, "text", TitledBorder.CENTER, TitledBorder.BOTTOM, new Font("times new roman",Font.PLAIN,12), Color.yellow));
the first parameter null or another border (for compound borders)
2nd param text that you're displaying
3rd and 4th param justification and location of the text from param 2
4th param
and 5th param are the two to set font and color
If you want a different font and color for each of the strings (e.g. Text1 and Text2) in the same TitledBorder, you may be need to extend AbstractBorder and override paintBorder(). The existing implementation only has one font and one color for a single title.
Text Font:
((javax.swing.border.TitledBorder) panel_1.getBorder()).setTitleFont(new Font("Tahoma", Font.PLAIN, 20));
Text Color:
((javax.swing.border.TitledBorder)panel_1.getBorder()).setTitleColor(Color.WHITE);
The JavaDocs for doing this are somewhat overwhelming if you are new to Java and Swing. The JavaDocs for BorderFactory are here: http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/BorderFactory.html
Here's an example of making the text red in a sans serif font:
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.io.IOException;
public class ScratchSpace {
public static void main(String[] args) throws IOException {
Font myFont = new Font("SansSerif", Font.PLAIN, 10);
Color myColor = Color.RED;
TitledBorder titledBorder = BorderFactory.createTitledBorder(null, " Text 1 Text 2", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, myFont, myColor);
JFrame frame = new JFrame();
final JLabel label = new JLabel("Hello gruel world");
label.setBorder(titledBorder);
frame.getContentPane().add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I know it is an old question.
Thought I would like to resurrect it as maybe someone knows how to solve this problem. I have only 'a partial solution'.
I have very quickly implemented the border which does what you want. I have reused what Java gives, i.e. interpretation of HTML in swing components.
All works sweet, the border is painted fine for a plain or HTML text, with exception for a situation where you are trying to have different font sizes for the texts.
I do not have idea how to solve this issue. But I am very much interested in a solution.
I know the procedure would be to sum up width of each string in its own font size when calculating the textLengthInPixels variable.
The problem is that I do not know how to get it, maybe from the View, but no idea how?
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.View;
public class MultiColorTitleBorder extends AbstractBorder
{
private static final long serialVersionUID = 1L;
private JLabel label;
private int thicknessTop = 10;
private Border border;
private int thicknessLeft = 0;
private int thicknessRight = 0;
private int thicknessBottom = 0;
public MultiColorTitleBorder(String title)
{
this.label = new JLabel(title);
thicknessTop = label.getPreferredSize().height;
}
public MultiColorTitleBorder(String title, Border border)
{
this(title);
this.border = border;
thicknessLeft = border.getBorderInsets(null).left;
thicknessRight = border.getBorderInsets(null).right;
thicknessBottom = border.getBorderInsets(null).bottom;
}
#Override
public synchronized void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
Graphics2D g2 = (Graphics2D) g;
View view = (View) label.getClientProperty("html");
String text = label.getText();
FontMetrics fm = g2.getFontMetrics(label.getFont());
int bY = y + fm.getAscent() - ((fm.getAscent() + fm.getDescent())) / 2;
if(border != null)
{
Insets in = border.getBorderInsets(c);
g2.setClip(x, y, thicknessLeft * 2, height);
border.paintBorder(c, g, x, bY, width, height - bY);
try
{
if(view != null)
text = view.getDocument().getText(0, view.getDocument().getLength());
}catch(BadLocationException ex)
{
Logger.getLogger(MultiColorTitleBorder.class.getName()).log(Level.SEVERE, null, ex);
}
int textLengthInPixels = fm.stringWidth(text);
System.out.println("textLengthInPixels=" + textLengthInPixels);
g2.setClip(x +thicknessLeft * 2+ textLengthInPixels, y, width - thicknessLeft * 2 -textLengthInPixels, height);
border.paintBorder(c, g, x, bY, width, height - bY);
int bottomIn = in.bottom;
g2.setClip(x, height - bottomIn, width, bottomIn);
border.paintBorder(c, g, x, bY, width, height - bY);
g2.setClip(x, y, width, height);
}
if(view != null)
view.paint(g2, new Rectangle(x + thicknessLeft * 2, y, width - thicknessLeft * 2, height));
else
{
Font prevFont = g2.getFont();
g2.setFont(label.getFont());
g2.drawString(text, x + thicknessLeft * 2, fm.getAscent());
g2.setFont(prevFont);
}
}
#Override
public Insets getBorderInsets(Component c)
{
return new Insets(thicknessTop, thicknessLeft, thicknessBottom, thicknessRight);
}
#Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.top = thicknessTop;
insets.left = thicknessLeft;
insets.right = thicknessRight;
insets.bottom = thicknessBottom;
return insets;
}
#Override
public boolean isBorderOpaque()
{
return false;
}
public static void main(String[] args)
{
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(200, 200));
String title = "<html><color=red> Text 1</font><font color=blue> Text 2</font&gt";
//title = "<html><font color=red font size=5> Text 1</font><font color=blue> Text 2</font>";
//title = "Text 1 Text 2";
p.setBorder(new MultiColorTitleBorder(title, new LineBorder(Color.CYAN, 6)));
p.setBackground(Color.YELLOW);
p.add(new JTextField(5));
JPanel contentPane = new JPanel();
contentPane.add(p);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Try this:
.setBorder(UIManager.getBorder("TextField.border"));

Categories