I have a method that creates a buffered image and I want to be able to create a progress bar and then paint that onto the buffered image. Any idea how I can achieve this please?
public void paint() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
JProgressBar pb = new JProgressBar();
//Draw the progress bar on Graphics g ???
}
Yours appears to be an xy problem in that you really don't want to add or remove components inside of any painting method. I'm going to assume that you want to place a JProgressBar onto a component that shows an image, and to do this best, create a class that extends JPanel, override its paintComponent method, draw your image in that method override, and add your JProgressBar to that JPanel (but not within its paint or paintComponent method).
e.g.
public class MyPanel extends JPanel {
private BufferedImage image;
private JProgressBar progressBar = new JProgressBar();
public MyPanel() {
// get your image here
add(progressBar);
}
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();;
if (image == null) {
return size;
} else {
int w = Math.max(image.getWidth(), size.width);
int h = Math.max(image.getHeight(), size.height);
return new Dimension(w, h);
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
}
Related
I have multiple images drawn with Graphics. How can I make them appear and disappear using a JCheckBox ?
private void drawImages(int index) {
Graphics g = mNew.getGraphics();
int x = index % this.width;
int y = index / this.width;
g.drawImage(imageLabelPixel.get(idImage-1), x, y, 100, 100, null);
}
You wouldn't use graphics to draw something on the screen you want to remove. Graphics just renders it on the screen along with all the other graphics you have drawn, It doesn't keep track of components
Your options are to add an action event to your checkbox and repaint the screen from scratch not drawing the image, or to just use a Label to draw the image and set it to invisible when the box is checked
I would do it like that:
JCheckBox cb = new JCheckBox();
ImgPanel p = new ImgPanel();
cb.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
if(cb.isSelected){
p.set(0);
} else {
p.set(-1);
}
}
});
.
public class ImgPanel extends JPanel {
private int i = 0;
private List<BufferedImage> imgs;
public ImgPanel(){
//init imgs
}
public void set(){
i = 0;
repaint();
}
#Override
public void paintComponent (Graphics g){
super.paintComponent(g);
if(i >= 0){
Image img = imgs.get(i-1);
Image img1 = img.getScaledInstance(100, 100, null);
}
g.drawImage(img1, 0, 0, null);
}
}
You can't simply draw on a graphic and then hand it to a compoennt or so (I don't really understand what your given code should have done). Instead you have to overwrite the paintComponent method of a Component and put your custom drawing code in there.
I have problem with program in kind of slideshow. I add two arguments for this program: path to folder which include images, time after images will be repainting.
Images should draw in original size and the window adjust to that size. If some files won't be image, program should draw "ERROR" statement. Anyway, that program haven't work at all and it haven't draw any image. Anyone could tell me why it doesn't draw anything and whether Timer is good way to repaint images?
public class ImagePanel extends JPanel
{
Image img;
private int period;
private int n = 0;
private File[] files;
Timer timer;
Dimension d;
public ImagePanel(File dir, int period)
{
this.period = period;
files = dir.listFiles();
loadImage(files[n++].getPath());
timer = new Timer(period, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Component component = (Component) e.getSource();
//JFrame f = (JFrame)
//SwingUtilities.windowForComponent(component);
//f.pack();
if (n < files.length)
{
loadImage(files[n].getPath());
}
else
{
repaint();
((Timer)e.getSource()).stop();
}
n++;
}
});
timer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (img != null)
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
private void loadImage(String imgFileName)
{
img = new ImageIcon(imgFileName).getImage();
int w = img.getWidth(this);
int h = img.getHeight(this);
if (w != -1 && w != 0 && h != -1 && h != 0)
{
d = new Dimension(img.getWidth(this), img.getHeight(this));
}
revalidate();
repaint();
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(img.getWidth(this), img.getHeight(this));
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(0, 1, 0, 0));
ImagePanel panel = new ImagePanel(new File(args[0]), Integer.parseInt(args[1]) * 1000);
frame.add(panel);
//frame.getContentPane().add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
whether Timer is good way to repaint images?
Yes, you should use a Swing Timer to schedule the animation.
Anyone could tell me why it doesn't draw anything
In your ImagePanel class you should create a method like setImage(...). This method will be invoked by the Timer code whenever you want to change the image.
Then in the setImage(...) method you need to invoke repaint() to tell the panel to repaint itself.
Since Java only supports single inheritance, I desire to paint directly on an instance of a JPanel that is a member of the class Panel. I grab an instance of Graphics from the member and then paint whatever I desire onto it.
How can I not inherit from JComponent or JPanel and still utilize getGraphics() for painting on this without overriding public void paintComponent(Graphics g)?
private class Panel {
private JPanel panel;
private Graphics g;
public Panel() {
panel = new JPanel();
}
public void draw() {
g = panel.getGraphics();
g.setColor(Color.CYAN);
g.draw(Some Component);
panel.repaint();
}
}
The panel is added to a JFrame that is made visible prior to calling panel.draw(). This approach is not working for me and, although I already know how to paint custom components by inheriting from JPanel and overriding public void paintComponent(Graphics g), I did not want to inherit from JPanel.
Here are some very simple examples which show how to paint outside paintComponent.
The drawing actually happens on a java.awt.image.BufferedImage, and we can do that anywhere, as long as we're on the Event Dispatch Thread. (For discussion of multithreading with Swing, see here and here.)
Then, I'm overriding paintComponent, but only to paint the image on to the panel. (I also paint a little swatch in the corner.)
This way the drawing is actually permanent, and Swing is able to repaint the panel if it needs to without causing a problem for us. We could also do something like save the image to a file easily, if we wanted to.
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
/**
* Holding left-click draws, and
* right-clicking cycles the color.
*/
class PaintAnyTime {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new PaintAnyTime();
}
});
}
Color[] colors = {Color.red, Color.blue, Color.black};
int currentColor = 0;
BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
Graphics2D imgG2 = img.createGraphics();
JFrame frame = new JFrame("Paint Any Time");
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Creating a copy of the Graphics
// so any reconfiguration we do on
// it doesn't interfere with what
// Swing is doing.
Graphics2D g2 = (Graphics2D) g.create();
// Drawing the image.
int w = img.getWidth();
int h = img.getHeight();
g2.drawImage(img, 0, 0, w, h, null);
// Drawing a swatch.
Color color = colors[currentColor];
g2.setColor(color);
g2.fillRect(0, 0, 16, 16);
g2.setColor(Color.black);
g2.drawRect(-1, -1, 17, 17);
// At the end, we dispose the
// Graphics copy we've created
g2.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
};
MouseAdapter drawer = new MouseAdapter() {
boolean rButtonDown;
Point prev;
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = e.getPoint();
}
if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {
// (This just behaves a little better
// than using the mouseClicked event.)
rButtonDown = true;
currentColor = (currentColor + 1) % colors.length;
panel.repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (prev != null) {
Point next = e.getPoint();
Color color = colors[currentColor];
// We can safely paint to the
// image any time we want to.
imgG2.setColor(color);
imgG2.drawLine(prev.x, prev.y, next.x, next.y);
// We just need to repaint the
// panel to make sure the
// changes are visible
// immediately.
panel.repaint();
prev = next;
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = null;
}
if (SwingUtilities.isRightMouseButton(e)) {
rButtonDown = false;
}
}
};
PaintAnyTime() {
// RenderingHints let you specify
// options such as antialiasing.
imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
imgG2.setStroke(new BasicStroke(3));
//
panel.setBackground(Color.white);
panel.addMouseListener(drawer);
panel.addMouseMotionListener(drawer);
Cursor cursor =
Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
panel.setCursor(cursor);
frame.setContentPane(panel);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
It's also possible to set up a JLabel with an ImageIcon, although personally I don't like this method. I don't think JLabel and ImageIcon are required by their specifications to see changes we make to the image after we've passed it to the constructors.
This way also doesn't let us do stuff like painting the swatch. (For a slightly more complicated paint program, on the level of e.g. MSPaint, we'd want to have a way to select an area and draw a bounding box around it. That's another place we'd want to be able to paint directly on the panel, in addition to drawing to the image.)
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
/**
* Holding left-click draws, and
* right-clicking cycles the color.
*/
class PaintAnyTime {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new PaintAnyTime();
}
});
}
Color[] colors = {Color.red, Color.blue, Color.black};
int currentColor = 0;
BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
Graphics2D imgG2 = img.createGraphics();
JFrame frame = new JFrame("Paint Any Time");
JLabel label = new JLabel(new ImageIcon(img));
MouseAdapter drawer = new MouseAdapter() {
boolean rButtonDown;
Point prev;
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = e.getPoint();
}
if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {
// (This just behaves a little better
// than using the mouseClicked event.)
rButtonDown = true;
currentColor = (currentColor + 1) % colors.length;
label.repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (prev != null) {
Point next = e.getPoint();
Color color = colors[currentColor];
// We can safely paint to the
// image any time we want to.
imgG2.setColor(color);
imgG2.drawLine(prev.x, prev.y, next.x, next.y);
// We just need to repaint the
// label to make sure the
// changes are visible
// immediately.
label.repaint();
prev = next;
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
prev = null;
}
if (SwingUtilities.isRightMouseButton(e)) {
rButtonDown = false;
}
}
};
PaintAnyTime() {
// RenderingHints let you specify
// options such as antialiasing.
imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
imgG2.setStroke(new BasicStroke(3));
//
label.setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
label.setBackground(Color.white);
label.setOpaque(true);
label.addMouseListener(drawer);
label.addMouseMotionListener(drawer);
Cursor cursor =
Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
label.setCursor(cursor);
frame.add(label, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class SomeComponent extends JComponent {
private Graphics2D g2d;
public void paintComponent(Graphics g) {
g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLACK);
g2d.scale(scale, scale);
g2d.drawOval(0, 0, importance, importance);
}
public Graphics2D getG2d() {
return g2d;
}
public void setG2d(Graphics2D g2d) {
this.g2d = g2d;
}
}
then you can do the following
get the SomeComponent instance in the panel and modify it
Graphics2D x= v.getPanel().get(i).getG2d;
x.setColor(Color.BLUE);
v.getPanel().get(i).setG2d(x);
v.getPanel().repaint();
v.getPanel().revalidate();
V is a class that extends JFrame and contains the panel in it AND
i is instance of SomeComponent
I have a panel with GridLayout(1, 3) but i want centralize the content of cells in this layout(without addition Panels):
public MainMenu() {
setLayout(new GridLayout(1, 3));
setBorder(BorderFactory.createLineBorder(Color.BLUE));
setOpaque(false);
ImageComponent img = new ImageComponent("resources/music.png", true, this);
add(img);
ImageComponent img1 = new ImageComponent("resources/video.png", true, this);
add(img1);
ImageComponent img2 = new ImageComponent("resources/audio", true, this);
add(img2);
}
Because if i just add this 3 ImageComponents to MainMenu they appears upwards.
GridLayout will size all components to fill the available space. So, if the dimensions of your 3 ImageComponents are 50x50, 50x50, and 75x75, they will all be sized to 75x75. From there it is up to ImageComponent how it paints itself.
Most likely ImageComponent implements paintComponent something like this:
protected void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, this);
}
That will paint the image in the upper-left corner, not centered.
This will paint a centered image:
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
int iw = image.getWidth(this);
int ih = image.getHeight(this);
if (iw != -1 && ih != -1)
{
int w = getWidth();
int h = getHeight();
g.drawImage(image, (w -iw)/2, (h-ih)/2, this);
}
}
I believe what you're wanting requires you to call setLayoutData on your image components - check the examples here.
Well, I have an image that I would like to put as a background to a button (or something clicable). The problem is that this image is round, so I need to show this image, without any borders, etc.
The JComponent that holds this button has a custom background, so the button really needs to only show the image.
After searching Google, I couldn't manage to do so. I have tried all the following, but with no luck:
button.setBorderPainted(false);
button.setContentAreaFilled(false);
button.setOpaque(true);
And after I paint the icon at the background, the button paints it, but holds an ugly gray background with borders, etc. I have also tried to use a JLabel and a JButton. And to paint an ImageIcon at it, but if the user resizes or minimizes the window, the icons disappear!
How can I fix this?
I just need to paint and round an image to a JComponent and listen for clicks at it...
Create a new Jbutton:
JButton addBtn = new JButton("+");
addBtn.setBounds(x_pos, y_pos, 30, 25);
addBtn.setBorder(new RoundedBorder(10)); //10 is the radius
addBtn.setForeground(Color.BLUE);
while setting the border for a JButton, call the overridden javax.swing.border.Border class.
addBtn.setBorder(new RoundedBorder(10));
Here is the class
private static class RoundedBorder implements Border {
private int radius;
RoundedBorder(int radius) {
this.radius = radius;
}
public Insets getBorderInsets(Component c) {
return new Insets(this.radius+1, this.radius+1, this.radius+2, this.radius);
}
public boolean isBorderOpaque() {
return true;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.drawRoundRect(x, y, width-1, height-1, radius, radius);
}
}
Did you try the following?
button.setOpaque(false);
button.setFocusPainted(false);
button.setBorderPainted(false);
button.setContentAreaFilled(false);
setBorder(BorderFactory.createEmptyBorder(0,0,0,0)); // Especially important
setBorder(null) might work, but there is a bug described at Sun explaining it is by design that the UI sets a border on a component unless the client sets a non-null border which does not implement the UIResource interface.
Rather than the JDK itself setting the border to an EmptyBorder when null is passed in, the clients should set an EmptyBorder themselves (a very easy workaround). That way there is no confusion about who's doing what in the code.
I wrote an OvalButton class that can handle oval, circular and capsule-like shaped JButtons.
In your case, extend the OvalButton class and override getBackgroundImage() method to return the image you want to set as the background.
Then add listeners and text as usually. Only a click on the oval/circular area triggers the action.
Example of your button class:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageButton extends OvalButton {
private BufferedImage image;
public ImageButton() {
super(); // Default is oval/circle shape.
setBorderThickness(0); // Oval buttons have some border by default.
try {
image = ImageIO.read(new File("your_image.jpg")); // Replace with the path to your image.
}
catch (IOException e) {
e.printStackTrace();
image = null;
}
}
#Override
protected BufferedImage getBackgroundImage() {
return image;
}
}
I would recommend overriding paint(Graphics g) method as so:
class JImageButton extends JComponent implements MouseListener {
private BufferedImage img = null;
public JImageButton(BufferedImage img) {
this.img = img;
setMinimumSize(new Dimension(img.getWidth(), img.getHeight()));
setOpaque(false);
addMouseListener(this);
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
}
You can try the following. It works fine for me, and I also faced the same issue with the button.
// Jbutton
JButton imageButton = new JButton();
// Buffered Icon
BufferedImage buttonIcon = null;
try {
// Get the image and set it to the imageicon
buttonIcon = ImageIO.read(getClass().getClassLoader().getResource("images/login.png"));
}
catch(Exception ex) {
}
// Set the image icon here
imageButton = new JButton(new ImageIcon(buttonIcon));
imageButton.setBorderPainted(false);
imageButton.setContentAreaFilled(false);
imageButton.setFocusPainted(false);
imageButton.setOpaque(false);
Drag a normal button to your panel
Right click your button and go to properties:
border = no border
border painted = false
contentAreaFilled = false
focusPainted = false
opaque = false
Set an (icon) and a (rolloverIcon) by importing to project.
Opacity should be set to false, so
button.setOpaque(false);
could already be what you want.
I just had the same problem and answer of #Lalchand inspired me. I created custom class for rounded borders, that is actually a modified version of LineBorder class. It draws two rectangles: inner and outer. For my case it is ok if border is colored like a background, but if you need something else, you should tinker with detentions of inner and outer. And as creative liberty I used subpixel rendering for smoother borders.
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
class RoundedBorder extends LineBorder {
private int radius;
RoundedBorder(Color c, int thickness, int radius) {
super(c, thickness, true);
this.radius = radius;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
// adapted code of LineBorder class
if ((this.thickness > 0) && (g instanceof Graphics2D)) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
Color oldColor = g2d.getColor();
g2d.setColor(this.lineColor);
Shape outer;
Shape inner;
int offs = this.thickness;
int size = offs + offs;
outer = new RoundRectangle2D.Float(x, y, width, height, 0, 0);
inner = new RoundRectangle2D.Float(x + offs, y + offs, width - size, height - size, radius, radius);
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(outer, false);
path.append(inner, false);
g2d.fill(path);
g2d.setColor(oldColor);
}
}
}
You can create an empty border to the button like this:
button.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));