Clear previously drawn string over an image - java

I am wondering how I can clear a previously drawn string before drawing a new one over an image, if I do not clear the strings overlap. I have tried graphics#drawRect and overriding paintComponent(Graphics), still no eval.
Here is my code:
paintComponent(Graphics)
public class SplashScreen extends JLabel
{
private static final long serialVersionUID = 5515310205953670741L;
private static final String ROOT = "./assets/img/";
private static final SplashScreen INSTANCE = new SplashScreen( get( new File( ROOT, "splash.png" ) ), get( new File( ROOT, "splash-bar.png" ) ) );
private final BufferedImage background;
private final BufferedImage foreground;
private final JLabel label;
private SplashScreen( BufferedImage background, BufferedImage foreground )
{
this.background = background;
this.foreground = foreground;
label = new JLabel( new ImageIcon( background ) );
JWindow window = new JWindow();
window.setSize( background.getWidth(), background.getHeight() );
window.getContentPane().add( label );
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
window.setLocation( dimension.width / 2 - window.getSize().width / 2, dimension.height / 2 - window.getSize().height / 2 );
window.setVisible( true );
}
public void updateStatus( String status )
{
Graphics g = background.getGraphics();
g.drawString( status, 304, 301 );
g.dispose();
label.repaint();
}
public void updateBar( int width )
{
Graphics g = background.getGraphics();
g.drawImage( foreground, 73, 309, width, foreground.getHeight(), null );
g.dispose();
label.repaint();
}
private static BufferedImage get( File file )
{
try {
return ImageIO.read( file );
} catch( IOException e ) {
throw new RuntimeException( e.getMessage() );
}
}
public static SplashScreen getInstance()
{
return INSTANCE;
}
}
Any help is greatly appreciated. :-)
Thanks.

You don't need to do custom painting.
Here are a couple of different ways to paint text on a label with an Icon:
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class LabelImageText extends JPanel
{
public LabelImageText()
{
JLabel label1 = new JLabel( new ColorIcon(Color.ORANGE, 100, 100) );
label1.setText( "Easy Way" );
label1.setHorizontalTextPosition(JLabel.CENTER);
label1.setVerticalTextPosition(JLabel.CENTER);
add( label1 );
//
JLabel label2 = new JLabel( new ColorIcon(Color.YELLOW, 200, 150) );
label2.setLayout( new BoxLayout(label2, BoxLayout.Y_AXIS) );
add( label2 );
JLabel text = new JLabel( "More Control" );
text.setAlignmentX(JLabel.CENTER_ALIGNMENT);
label2.add( Box.createVerticalGlue() );
label2.add( text );
label2.add( Box.createVerticalStrut(10) );
//
JLabel label3 = new JLabel( new ColorIcon(Color.GREEN, 200, 150) );
add( label3 );
JLabel text3 = new JLabel();
text3.setText("<html><center>Text<br>over<br>Image<center></html>");
text3.setLocation(20, 20);
text3.setSize(text3.getPreferredSize());
label3.add( text3 );
//
JLabel label4 = new JLabel( new ColorIcon(Color.CYAN, 200, 150) );
add( label4 );
JTextPane textPane = new JTextPane();
textPane.setText("Add some text that will wrap at your preferred width");
textPane.setEditable( false );
textPane.setOpaque(false);
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
StyledDocument doc = textPane.getStyledDocument();
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPane.setBounds(20, 20, 75, 100);
label4.add( textPane );
}
public static class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("LabelImageText");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new LabelImageText() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Then to change the text you just change the text in the component you are using to display the text.
If none of these help then the way to do custom painting is to override the paintCompnent() method of the JLabel. You should not be painting the text directly on the BufferedImage.

Basically, you can't.
What you should try doing is keep a reference to the original background image and when you need to change the text, copy it to a temp image and draw the String there, replacing it (the temp copy) as the label's icon...
A better solution might be to paint the text directly as part of the labels paint process by overriding the paintComponent method

Related

Layered Java JPanels

I have overlayed JPanels, background has an image that prevents foreground from painting on applet's load.
setOpaque(false) works fine (repaints both panels twenty times thou[?]), but I need it opaque to have BG color, opaque background causes repainting itself 3 times, and that wipes out the top panel:
public class LayeredPanelsTest extends JApplet
{
private Image _image;
#Override
public void init()
{
_image = getImage( getDocumentBase(), "./images/flag.GIF" );
setSize( 450, 450 );
setLayout( new OverlayLayout( getContentPane() ) );
final BottomPanel background = new BottomPanel();
background.setBounds( 10, 10, 400, 400 );
final TopPanel foreGround = new TopPanel();
foreGround.setBounds( 10, 10, 400, 400 );
add( foreGround );
add( background );
}
public class BottomPanel extends JPanel
{
public BottomPanel()
{
setBackground(Color.CYAN);
setLayout( new FlowLayout() );
setOpaque( true );//with false foreground is painted just fine, but they get repainted like 20 times.
}
#Override
public void paintComponent( final Graphics g )
{
super.paintComponent( g );
g.drawImage( _image, 10, 10, this );
System.out.println( "Bottom" );
}
}
public class TopPanel extends JPanel
{
int _mouseX = 10;
public TopPanel()
{
setLayout( new FlowLayout() );
setOpaque( false );
addMouseListener( new MouseAdapter()
{
#Override
public void mousePressed( final MouseEvent evt ) {
_mouseX = evt.getX();
repaint();
}
});
}
#Override
public void paintComponent( final Graphics g )
{
super.paintComponent( g );
g.drawLine( _mouseX, 0, _mouseX, 80);
System.out.println( "Top" );
}
}
}

JButton settext specific position

I have a JButton with an image icon and I need to position the text.
Is there a way to position the text of a JButton in a specific position instead of using CENTER,LEADING, TOP and so on?
I've never tried it on a JButton before, but maybe you can add a JLabel as a component on the button. Then you can use layout managers or Borders to position the label more appropriately.
Here are some example of adding a component to a JLabel with an Icon:
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class LabelImageText extends JPanel
{
public LabelImageText()
{
JLabel label1 = new JLabel( new ColorIcon(Color.ORANGE, 100, 100) );
label1.setText( "Easy Way" );
label1.setHorizontalTextPosition(JLabel.CENTER);
label1.setVerticalTextPosition(JLabel.CENTER);
add( label1 );
//
JLabel label2 = new JLabel( new ColorIcon(Color.YELLOW, 200, 150) );
label2.setLayout( new BoxLayout(label2, BoxLayout.Y_AXIS) );
add( label2 );
JLabel text = new JLabel( "More Control" );
text.setAlignmentX(JLabel.CENTER_ALIGNMENT);
label2.add( Box.createVerticalGlue() );
label2.add( text );
label2.add( Box.createVerticalStrut(10) );
//
JLabel label3 = new JLabel( new ColorIcon(Color.GREEN, 200, 150) );
label3.setLayout( new GridBagLayout() );
add( label3 );
JLabel text3 = new JLabel();
text3.setText("<html><center>Text<br>over<br>Image<center></html>");
text3.setLocation(20, 20);
text3.setSize(text3.getPreferredSize());
label3.add( text3 );
//
JLabel label4 = new JLabel( new ColorIcon(Color.CYAN, 200, 150) );
add( label4 );
JTextPane textPane = new JTextPane();
textPane.setText("Add some text that will wrap at your preferred width");
textPane.setEditable( false );
textPane.setOpaque(false);
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
StyledDocument doc = textPane.getStyledDocument();
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPane.setBounds(20, 20, 75, 100);
label4.add( textPane );
}
public static class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("LabelImageText");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new LabelImageText() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
I doubt the JTExtPane example will work with a button because the text pane will intercept the mouse events and so you will not be able to click the button when you click on the text. So I would stick with the examples that add a label to the button.
Spanish:
Puedes sobreescribir el método setText(String str).
Google Traductor English: You can overwrite the method setText (String str).
private static final String HTML_1 = "<html><body style='margin:0px 0px 0px 0px'>";
private static final String HTML_2 = "</html>";
#Override
public void setText(String txt) {
if (txt.isEmpty()) {
txt = "Dispositivo";
}
String txt2 = HTML_1 + txt + HTML_2;
super.setText(txt2);
}
you can use set bounds method to set the postion of the text on the button
JLabel positiongLabel = new JLabel();
positiongLabel.setBounds(100,50,300,30);
for more detail click here

Adding elements to JPanel

Why does "drawing" not appear here? I am adding it to a different JPanel then adding everything to another JPanel and returning that. However, all i see is the TrackBall
public class Draw extends JFrame
{
private JSplitPane itemPane;
private Point position = null;
public Draw()
{
// Set the layout to a grid
setLayout ( new BorderLayout (5,5));
// Set the properties of the window
setTitle ("Emulator");
setSize ( 900, 700);
setDefaultCloseOperation (EXIT_ON_CLOSE);
setBackground ( new Color (15, 255, 10));
// Add the components
addComponents ();
}
public static void startWindowsGui()
{
// We are in the static main, set the form to invoke later
SwingUtilities.invokeLater ( new Runnable()
{
public void run()
{
// Create a new instance of server and set it to visible
Draw gui = new Draw();
gui.setVisible (true);
}
} );
}
private void addComponents()
{
// Create the main and an itemPane
JSplitPane mainPane = new JSplitPane ( JSplitPane.HORIZONTAL_SPLIT );
setItemPane(new JSplitPane ( JSplitPane.VERTICAL_SPLIT ));
mainPane.add ( createPane ( ), JSplitPane.LEFT );
mainPane.add ( getItemPane(), JSplitPane.RIGHT );
mainPane.setOneTouchExpandable ( true );
getItemPane().setOpaque(true);
getItemPane().setBackground(new Color(0xffffffc0));
JPanel p = new JPanel();
this.getItemPane().add(p);
add ( mainPane, BorderLayout.CENTER );
}
public static void main(final String[] args)
{
Runnable gui = new Runnable()
{
#Override
public void run()
{
new Draw().setVisible(true);
}
};
SwingUtilities.invokeLater(gui);
}
private class Drawing extends JPanel {
private static final long serialVersionUID = 1L;
private final Point position;
public Drawing(Point position) {
this.position = position;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
g2.fillOval(160 + position.x, 160 - position.y, 15, 15);
}
}
private JPanel createPane()
{
// Create the feedPanel
JPanel panel = new JPanel ( );
JPanel panel2 = new JPanel ( );
JPanel panel3 = new JPanel ( );
this.position = new Point();
TrackBall myJoystick = new TrackBall(150, position, 100);
panel.add(myJoystick, BorderLayout.PAGE_END);
Drawing drawing = new Drawing(position);
panel2.add(drawing, BorderLayout.PAGE_START);
panel3.add(panel2);
panel3.add(panel);
return panel3;
}
public JSplitPane getItemPane() {return itemPane;}
public void setItemPane(JSplitPane itemPane) {this.itemPane = itemPane;}
}
3 issues
panel2 requires BorderLayout rather than the default FlowLayout for the BorderLayout.PAGE_START constraint to be used
The class Drawing is required to override getPreferredSize
The Dimension specified by getPreferredSize should be large enough to accommodate the position specified in the constructor of Drawing
Read: Changing preferred size of a Swing component

How to dynamically add a new customized button?

I am trying to have my interface dynamically generate a customized button when I click a button. I searched several answers like this, but somehow it does not work. Is there any mistake with my current code below?
public class MainWindow {
private JFrame frame;
private JPanel panel;
private JPanel panel_1;
private JPanel panel_2;
private JSplitPane splitPane;
private JButton btnSearch;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainWindow window = new MainWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MainWindow() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 645, 438);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
splitPane = new JSplitPane();
panel.add(splitPane);
panel_1 = new JPanel();
splitPane.setLeftComponent(panel_1);
btnSearch = new JButton("Search");
GridBagConstraints gbc_btnSearch = new GridBagConstraints();
gbc_btnSearch.gridx = 0;
gbc_btnSearch.gridy = 10;
panel_1.add(btnSearch, gbc_btnSearch);
panel_2 = new JPanel();
splitPane.setRightComponent(panel_2);
btnSearch.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
addButton();
}
});
}
protected void addButton() {
MyButton hahaButton = new MyButton("haha");
panel_2.add(hahaButton);
panel_2.add(new JButton());
panel_2.revalidate();
panel_2.repaint();
}
And this is the definition of the MyButton:
public class MyButton extends JButton {
private static final long serialVersionUID = 1L;
private Color circleColor = Color.BLACK;
public MyButton(String label) {
super(label);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension originalSize = super.getPreferredSize();
int gap = (int) (originalSize.height * 0.2);
int x = originalSize.width + gap;
int y = gap;
int diameter = originalSize.height - (gap * 2);
g.setColor(circleColor);
g.fillOval(x, y, diameter, diameter);
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
size.width += size.height;
return size;
}
}
I just tried your sourcecode and it works as expected: everytime I klick the search button on the left side of the split-pane, 2 buttons are added to the panel on the right side of the panel (one with the black filled circle and a button without a label).
What doesn't work for you? I'm using java 1.6 on Mac OSX, but this should work with earlier versions on other platforms as well......
As Dieter Rehbein pointed out, the code you have does compile and run.
However, it was rather sloppy and convoluted, as if you copied and pasted different sources together.
I took a few minutes and cleaned it up some, hope it helps.
public class MainWindow
{
public static void main( String[] args )
{
new MainWindow();
}
public MainWindow()
{
// Create the split pane
JSplitPane jSplitPane = new JSplitPane();
final JPanel leftPanel = new JPanel();
final JPanel rightPanel = new JPanel();
jSplitPane.setLeftComponent( leftPanel );
jSplitPane.setRightComponent( rightPanel );
// Create the button
JButton jButton = new JButton( "Generate" );
leftPanel.add( jButton );
jButton.addMouseListener( new MouseAdapter()
{
#Override
public void mouseClicked( MouseEvent e )
{
addButtons( rightPanel );
}
} );
// Create the panel
JPanel jPanel = new JPanel();
jPanel.setLayout( new BoxLayout( jPanel , BoxLayout.X_AXIS ) );
jPanel.add( jSplitPane );
// Create the frame
JFrame jFrame = new JFrame();
jFrame.setBounds( 100 , 100 , 645 , 438 );
jFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
jFrame.getContentPane().add( jPanel , BorderLayout.CENTER );
// Show the frame
jFrame.setVisible( true );
}
private void addButtons( JPanel jPanel )
{
addButton( jPanel , "Default" , null );
addButton( jPanel , "Red" , Color.RED );
addButton( jPanel , "Yellow" , Color.YELLOW );
addButton( jPanel , "Blue" , Color.BLUE );
addButton( jPanel , "Green" , Color.GREEN );
}
protected void addButton( JPanel jPanel , String label , Color color )
{
jPanel.add( new MyButton( label , color ) );
jPanel.revalidate();
jPanel.repaint();
}
public class MyButton extends JButton
{
private static final long serialVersionUID = 1L;
private Color color = null;
public MyButton( String label , Color color )
{
super( label );
this.color = color;
}
#Override
protected void paintComponent( Graphics graphics )
{
super.paintComponent( graphics );
if ( color != null )
{
Dimension dimension = super.getPreferredSize();
int gap = ( int ) ( dimension.height * 0.2 );
int diameter = dimension.height - ( gap * 2 );
graphics.setColor( color );
graphics.fillOval( dimension.width + gap , gap , diameter , diameter );
}
}
#Override
public Dimension getPreferredSize()
{
Dimension size = super.getPreferredSize();
size.width += size.height;
return size;
}
}
}

Java - Draw text in the center of an image

I need to write text in the center of an image. The text to write is not always the same.
The code I'm using is here:
// Here I first draw the image
g.drawImage(img, 22, 15, 280, 225, null);
// I get the text
String text = photoText.getText();
// Set the text color to black
g.setColor(Color.black);
// I draw the string
g.drawString(text, 79.5F, 220.0F);
The problem is that the text isn't at the center of the image, what can I do?
I only need to draw the text at the horizontal center.
Using a JLabel is less work, but FontMetrics, shown here, will let you manage the geometry directly.
One possible solution: draw the image in a JPanel, being sure to set the panel's preferredsize as the size of the image, have the JPanel use a GridBagLayout, and place the text in a JLabel that is added to the JPanel, without GridBagConstraints. This is one way to center the JLabel in the JPanel.
The easy way is to use a JLabel with an Icon and Text. Then set the horizontal/vertical text position to CENTER and the text is painted in the center of the image.
From your code it looks like you are trying to paint the text near the bottom of the image. In this case you can use the JLabel with an Icon as a container. Then you can set the layout to something like a BoxLayout and add another label with the text.
No custom painting is required for either approach.
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class LabelImageText extends JPanel
{
public LabelImageText()
{
JLabel label1 = new JLabel( new ColorIcon(Color.ORANGE, 100, 100) );
label1.setText( "Easy Way" );
label1.setHorizontalTextPosition(JLabel.CENTER);
label1.setVerticalTextPosition(JLabel.CENTER);
add( label1 );
//
JLabel label2 = new JLabel( new ColorIcon(Color.YELLOW, 200, 150) );
label2.setLayout( new BoxLayout(label2, BoxLayout.Y_AXIS) );
add( label2 );
JLabel text = new JLabel( "More Control" );
text.setAlignmentX(JLabel.CENTER_ALIGNMENT);
label2.add( Box.createVerticalGlue() );
label2.add( text );
label2.add( Box.createVerticalStrut(10) );
//
JLabel label3 = new JLabel( new ColorIcon(Color.GREEN, 200, 150) );
add( label3 );
JLabel text3 = new JLabel();
text3.setText("<html><center>Text<br>over<br>Image<center></html>");
text3.setLocation(20, 20);
text3.setSize(text3.getPreferredSize());
label3.add( text3 );
//
JLabel label4 = new JLabel( new ColorIcon(Color.CYAN, 200, 150) );
add( label4 );
JTextPane textPane = new JTextPane();
textPane.setText("Add some text that will wrap at your preferred width");
textPane.setEditable( false );
textPane.setOpaque(false);
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
StyledDocument doc = textPane.getStyledDocument();
doc.setParagraphAttributes(0, doc.getLength(), center, false);
textPane.setBounds(20, 20, 75, 100);
label4.add( textPane );
}
public static class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("LabelImageText");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new LabelImageText() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
I mean I have to write a text in the center of the image and then save the image
You can use Screen Image to create an image of any component. This assumes you are displaying the image and text on a GUI.
Or, if you are talking about just reading in an image adding text to the image and then saving the image, then you will need to create a BufferedImage and draw the image on it and then draw the text on it. You will need to use the FontMetrics class as mentioned by Trashgod. My suggestion won't help.
I used TextLayout to get the text properly centered:
Here's how to create the image and save it as a file:
int imgWidth = 250;
int imgHeight = 250;
var img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
var backgroundColor = new Color(0, 150, 100);
g.setPaint(backgroundColor);
g.fillRect(0, 0, imgWidth, imgHeight);
var font = new Font("Arial", Font.PLAIN, 80);
g.setFont(font);
g.setPaint(Color.WHITE);
String text = "0";
var textLayout = new TextLayout(text, g.getFont(), g.getFontRenderContext());
double textHeight = textLayout.getBounds().getHeight();
double textWidth = textLayout.getBounds().getWidth();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Draw the text in the center of the image
g.drawString(text, imgWidth / 2 - (int) textWidth / 2,
imgHeight / 2 + (int) textHeight / 2);
String imgFormat = "png";
ImageIO.write(img, imgFormat, new File("/home/me/new_image." + imgFormat));

Categories

Resources