How to draw PNG Image onto JPanel? - java

I'm trying to draw a image onto a JPanel by overriding the paintComponent method. However, I'm having no luck with it at all and I don't know why.
Here's the code I've got at the moment:
DrawPanel
public class DrawPanel extends JPanel{
private Image backgroundImg;
public DrawPanel()
{
backgroundImg = Toolkit.getDefaultToolkit().createImage("C:\\Users\\Administrator\\workspace\\Scrub\\src\\loginBackground.png");
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(backgroundImg, 0, 0, null);
}
}
LoginWindow Class
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LoginWindow extends Window{
private DrawPanel panel;
public LoginWindow(int width, int height)
{
super("", width, height);
panel = new DrawPanel();
this.add(panel);
panel.setVisible(true);
}
}
Main
public class Main
{
public static void main(String[] args)
{
LoginWindow loginWindow = new LoginWindow(500, 300);
}
}

There are lots of reasons this might not work
The image might not be getting loaded. You should use ImageIO.read instead, as it will throw an IOException if something goes wrong
The layout manager is using the preferred size of your panel, which is defaulted to 0x0, making the component effectively invisible
You're not setting the window to be visible...
For example
public class DrawPanel extends JPanel{
//...
public Dimension getPreferredSize() {
return backgroundImg == null ? new Dimesion(100, 100) : new Dimension(backgroundImg.getWidth(this), backgroundImg.gtHeight(this));
}
And then in your Window class...
public LoginWindow(int width, int height)
{
super("", width, height);
panel = new DrawPanel();
this.add(panel);
// Swing components are visible by default
//panel.setVisible(true);
// windows aren't
setVisible(true);
}
A simpler soliton would be to use a JLabel...
setLayout(new BorderLayout());
BufferedImage img = ImageIO.read(new File(...));
JLabel label = new JLabel(new ImageIcon(img));
add(label);
setVisible(true);
Take a look at How to use Labels and Reading/Loading an Image for more details

Related

How can I move a graphics element on my java panel?

I am currently working on a simple pong-like game, but I got stucked with positioning the rectangle.
I want to change it's Y position to be at the half of the actual panel's height.
package com.game;
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("gEngine");
Player playerOne = new Player(frame);
Player playerTwo = new Player(frame);
}
}
package com.game;
import javax.swing.*;
import java.awt.*;
public class Player {
public Player(JFrame frame) {
MyPanel panel = new MyPanel();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.BLACK);
frame.setSize(1280, 720);
frame.setVisible(true);
}
}
class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(50, 60, 20, 120);
}
}
Your code has a lot of "problems". I suggest you to find some kind of tutorials or something. You frame.setVisible(true) and stuff inside Player's class constructor. Do you realize that every time you create a Player object, all these things will be applied to the JFrame? Is this necessary? Maybe you should do them only once. Also in order to paint the compnent according to its position according size, you can do g.fillRect(50, getHeight() / 2, 20, 120);
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("gEngine");
Player playerOne = new Player();
Player playerTwo = new Player();
// Set the proper layout manager
frame.setLayout(new GridLayout());
frame.add(playerOne.getMyPanel());
frame.add(playerTwo.getMyPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.BLACK);
frame.setSize(1280, 720);
frame.setVisible(true);
}
public static class Player {
private JPanel myPanel;
public Player() {
this.myPanel = new MyPanel();
}
public JPanel getMyPanel() {
return myPanel;
}
}
static class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
// let the component be painted "natural"
super.paintComponent(g);
// Do custom painting
g.setColor(Color.WHITE);
g.fillRect(50, getHeight() / 2, 20, 120);
}
}
}
Edit (based on comment):
The background is the default one because GridLayout splits the screen into 2 panels (in the middle of the frame). Even the frame has BLACK background, these 2 panels cover it. So the background you see is from the panels, and not from the frame. In order to change it you will have to change the background of the panels (and make them non-transparent):
static class MyPanel extends JPanel {
public MyPanel() {
super();
setOpaque(true);
setBackground(Color.BLACK);
}
#Override
public void paintComponent(Graphics g) {
// let the component be painted "natural"
super.paintComponent(g);
// Do custom painting
g.setColor(Color.WHITE);
g.fillRect(50, getHeight() / 2, 20, 120);
}
}

Java Drawing to a JPanel (debugging)

I'm trying to draw a basic object to a JPanel
although it doesn't seem to be working.
I'm certain I am doing something wrong with where the paint method
is being called
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
public class testGui {
static colors gc_colors;
static gui gc_gui;
public static void main(String[] args) {
gc_colors = new colors();
gc_gui = new gui();
gc_gui.cv_frame.setVisible(true);
}
public static class colors {
Color cv_ltGrey;
Color cv_mdGrey;
Color cv_dkGrey;
public colors() {
cv_ltGrey = Color.decode("#DDDDDD");
cv_mdGrey = Color.decode("#CCCCCC");
cv_dkGrey = Color.decode("#111111");
}
}
public static class gui {
JFrame cv_frame;
JPanel cv_panel;
JPanel cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_panel = new JPanel();
cv_panel.setBackground(gc_colors.cv_ltGrey);
cv_panel.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_panel);
cv_content = new content();
cv_panel.add(cv_content);
}
}
public static class content extends JPanel {
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(gc_colors.cv_ltGrey);
graphic2D.fillRect(10, 10, 100, 100);
}
}
}
I have a class for my gui which I am adding a JPanel to (a light grey one).
Which I am then trying to add my drawing to using a JPanel extended class
called content.
When I run it though it seems to create the grey JPanel which I want but
the drawing is just a tiny white square and I'm not sure why.
So, you content panel has a default preferred size of 0x0, FlowLayout honours the preferredSize of its components (with a little margin), hence the reason why you have a nice little small white rectangle.
What you need to do is override the getPreferredSize method of the content panel and return a suitable size, for example
public static class content extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 120);
}
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(gc_colors.cv_ltGrey);
graphic2D.fillRect(10, 10, 100, 100);
}
}
I've decided to just leave out the second JPanel altogether.
It was too much of a hassle to put the JPanel inside of another JPanel
so instead I am only going to use a single JPanel
public static class gui {
JFrame cv_frame;
JPanel cv_panel;
JPanel cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_content = new content();
cv_content.setBackground(gc_colors.cv_ltGrey);
cv_content.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_content);
}
}

Dynamically add a JPanel to a groupLayout

I try to build a webcam app for a university project in java. Until now i never needed GUI so i have no experience with this and for that i used the gui builder inside of netbeans.
For now the GUI looks like that:
It's only a jPanel and a jButton added inside the gui builder.
The image i want to display is taken by using openCV. This works just fine and i get a bufferedImage. To display this image i created a subclass of jPanel and changed the paintComponent method.
package WebcamImageCapture;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class ImagePanel extends JPanel
{
/**
* Creates a new empty ImagePanel.
*/
public ImagePanel()
{
this.image = null;
}
/**
* Creates a new ImagePanel from BufferedImage img.
* #param img The BufferedImage to display on the ImagePanel
*/
public ImagePanel(BufferedImage img)
{
this.image = img;
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(this.image, 0, 0, this.image.getWidth(), this.image.getHeight(), null);
g.setColor(new Color(240, 160, 40));
g.fillRect(10, 10, 25, 25);
this.repaint();
}
/**
* Sets the BufferedImage img to display on ImagePanel.
* #param img The BufferedImage to display on the ImagePanel
*/
public void setImage(BufferedImage img)
{
this.image = img;
}
private BufferedImage image;
}
The GUI class has the member openCameraButton and outputPanel, which are the elements you can see on the screenshot. I tryed the following to add my imagePanel to the outputPanel inside of the method which handles the ActionPerformed event of the button.
// create the custom jPanel
ImagePanel webcamFrame = new ImagePanel(img);
webcamFrame.setPreferredSize(new Dimension(640, 480));
this.outputPanel.getLayout().addLayoutComponent("webcamFrame", webcamFrame);
this.outputPanel.revalidate();
this.outputPanel.repaint();
this.revalidate();
this.repaint();
This doesn't work =(. I googled around and tested for 2 days (also reading the oracle documentation on layouts : documentation) not finding a solution.
So the main questions are:
How do i add the ImagePanel?
Should i manually implement the GUI with an other layout?
Thanks in advance for your help.
2.Should i manually implement the GUI with an other layout?
Yes, code generated by an IDE is hard to maintain and change.
The JFrame is uses a BorderLayout by default so you could do something like:
ImagePanel = new ImagePanel();
frame.add(imagePanel, BorderLayout.CENTER);
JPanel south = new JPanel();
JButton load = new JButton("Load Image");
south.add(load);
frame.add(south, BorderLayout.PAGE_END);
So the idea is you add the panel to the frame at design time. Then whenever you capture an image you invoke the setImage() method. The code in your setImage() method would be:
this.image = img;
repaint();
Your paintComponent() code would change to:
if (image != null);
g.drawImage(this.image, 0, 0, this.image.getWidth(), this.image.getHeight(), null);
Also get rid of the repaint(). This will cause an infinite loop.
i changed my code as you recommended ...
package WebcamImageCapture;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class ImagePanel extends JPanel
{
/**
* Creates a new empty ImagePanel.
*/
public ImagePanel()
{
this.image = null;
}
/**
* Creates a new ImagePanel from BufferedImage img.
* #param img The BufferedImage to display on the ImagePanel
*/
public ImagePanel(BufferedImage img)
{
this.image = img;
}
#Override
public void paintComponent(Graphics g)
{
if(this.image != null)
{
super.paintComponent(g);
g.drawImage(this.image, 0, 0, this.image.getWidth(), this.image.getHeight(), null);
g.setColor(new Color(240, 160, 40));
g.fillRect(10, 10, 25, 25);
System.out.println("image drawn ...");
}
else
{
System.out.println("image not drawn ...");
}
}
/**
* Sets the BufferedImage img to display on ImagePanel.
* #param img The BufferedImage to display on the ImagePanel
*/
public void setImage(BufferedImage img)
{
this.image = img;
this.repaint();
}
private BufferedImage image;
}
... and created the GUI by hand.
private void init()
{
this.imageOutput = new ImagePanel();
this.add(imageOutput, BorderLayout.CENTER);
this.openCameraButton = new JButton("open camera");
this.openCameraButton.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
openCameraButtonActionPerformed(evt);
}
});
JPanel navigation = new JPanel();
navigation.add(this.openCameraButton, BorderLayout.PAGE_END);
this.add(navigation);
this.setTitle("Webcam");
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.pack();
}
Inside the openCameraButtonActionPerformed method i took the image and used the setImage method of the ImagePanel to set it.
this.imageOutput.setImage(img);
But unfortunately nothing happens. If i do the following, i get a new window with the image inside.
JFrame myFrame = new JFrame("myFrame");
ImagePanel out = new ImagePanel(img);
myFrame.add(out);
myFrame.pack();
myFrame.setVisible(true);
What i am doing wrong?

Unable to add other components to window after creating background using JLabel in Java

I want to create a java Application like a widget. Here is my code below
package newpackage;
public class MainFrame extends JFrame {
JLabel imageLabel = new JLabel();
public MainFrame() {
try {
this.setUndecorated(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(new Dimension(360, 360));
ImageIcon ii = new ImageIcon(this.getClass().getResource("imageexcel.gif"));
imageLabel.setIcon(ii);
add(imageLabel, java.awt.BorderLayout.CENTER);
this.setVisible(true);
Shape shape=new Ellipse2D.Float(0,0,360,360);
AWTUtilities.setWindowShape(this, shape);
AWTUtilities.setWindowOpaque(this, false);
imageLabel.add(new JButton("START"));
} catch (Exception exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
new MainFrame();
}
}
In the above code, I have done the following:
Created a Frame
Removed the Title Bar
Added the Background using JLabel
Changed the shape of window as circle according to the shape of image
Now I would like to add some components in to it and perform some action with them but no component is visible after adding.
I have tried adding to Frame as well as JLabel and no use from either.
This is the image i used for background
Please help me to proceed further....
Thanking you
JLabels use null layouts by default, and so your button will default to size 0,0. Try giving it a decent layout manager, even FlowLayout would likely work. Another solution is to keep the null layout and set the sizes and positions of added components, but this route is a dangerous route and one I don't recommend.
Actually a GridBagLayout works nice to center the components. Also add all components before calling setVisible(true):
imageLabel.setLayout(new GridBagLayout());
this.setUndecorated(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(new Dimension(360, 360));
ImageIcon ii = new ImageIcon(this.getClass().getResource("imageexcel.gif"));
imageLabel.setIcon(ii);
add(imageLabel, java.awt.BorderLayout.CENTER);
imageLabel.add(new JButton("START"));
this.setVisible(true);
or better?
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Shape;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.net.URL;
import javax.swing.*;
import com.sun.awt.AWTUtilities;
#SuppressWarnings("serial")
public class MainPanelOvalFrame extends JPanel {
private static final String RESOURCE_PATH = "imageexcel.gif";
private Window window;
private Image img;
public MainPanelOvalFrame(Window window, Image image) {
this.window = window;
this.img = image;
setLayout(new GridBagLayout());
add(new JButton(new StartAction("Start", KeyEvent.VK_S)));
int w = image.getWidth(this);
int h = image.getHeight(this);
Shape shape = new Ellipse2D.Float(0, 0, w, h);
AWTUtilities.setWindowShape(window, shape);
AWTUtilities.setWindowOpaque(window, false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
int w = img.getWidth(this);
int h = img.getHeight(this);
return new Dimension(w, h);
}
private class StartAction extends AbstractAction {
public StartAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
window.dispose();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame();
frame.setUndecorated(true);
URL imgUrl = MainPanelOvalFrame.class.getResource(RESOURCE_PATH);
Image image = new ImageIcon(imgUrl).getImage();
MainPanelOvalFrame mainPanel = new MainPanelOvalFrame(frame, image);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You just need to set a Layout manager for imageLabel ,or use null as the Layout manager, then set the size and location of the JButton manually.
to use Layout Manager
imageLabel.setIcon(ii);
imageLabel.setLayout(new FlowLayout());
imageLabel.add(new JButton("START"));
//need to setLayout and add JButton before setVisible(true)
add(imageLabel, java.awt.BorderLayout.CENTER);
this.setVisible(true);
to use null layout
JButton j=new JButton("START");
j.setSize(100,50);
j.setLocation(imageLabel.getWidth()/2-j.getWidth()/2, imageLabel.getHeight()/2-j.getHeight()/2);
//then add Button into imageLabel
imageLabel.add(j);
Layout manager is usually recommended because it can fit different environment.

Nothing is getting displayed on JFrame

This what I am doing but is nothing is getting displayed on Jframe window. I have not extended class JFrame to do my, is it necessary to do so for displaying objects on window.
public class testGraphics {
static JFrame workingFrame = null;
public static void main(String args[])
{
JFrame workingManager = new JFrame("Hello");
workingManager.setSize(500, 500);
workingManager.setVisible(true);
Graphics g = workingManager.getGraphics();
JPanel jp = (JPanel) workingManager.getContentPane();
workingManager.paintComponents(g);
g.fillOval(0, 0, 30, 30);
g.drawOval(0, 50, 30, 30);
g.setColor(Color.CYAN);
}
}
Do not ever call getGraphics() or explicitly call paintXxx() to do custom painting. The correct way to do custom painting is to override the paintComponent method of the panel to paint on. The overriden method will be implicitly called for you. Then add that panel to the frame. Also you should override the getPreferredSize() of the panel, so it has a preferred size, so you can just pack the frame
class PaintPanel extends JPanel {
#Override
protected paintComponent(Grapchics g) {
super.paintComponent(g);
g.drawString(....);
}
#Override
public Dimension getPreferredSize() {'
return new Dimension(300, 300);
}
}
Then add it to the frame (or if you want to set it as the content pane of the frame, do that instead)
PaintPanel panel = new PaintPaint();
frame.add(panel);
...
frame.pack();
See more at Performing Custom Painting
I made several changes to your code to get it to work properly.
I changed your main method to call the SwingUtilities invokeLater method to make sure that the Swing components were defined and used on the Event Dispatch thread.
I created a drawing JPanel. I set the color first, then drew the ovals.
I added a JFrame default close operation. You must specify a default close operation, or else your Java application will continue running after you close the JFrame.
I moved the size to the drawing panel. The frame size will be calculated when you call the JFrame pack method.
And here's the modified code:
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestGraphics implements Runnable{
private JFrame workingManager;
private JPanel drawingPanel;
#Override
public void run() {
workingManager = new JFrame("Hello");
workingManager.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel();
workingManager.add(drawingPanel, BorderLayout.CENTER);
workingManager.pack();
workingManager.setLocationByPlatform(true);
workingManager.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new TestGraphics());
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID =
-3701718376300985046L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(500, 500));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.CYAN);
g.fillOval(0, 0, 30, 30);
g.drawOval(0, 50, 30, 30);
}
}
}
The setSize() and setVisible() must be at the bottom of the method:
JFrame workingManager = new JFrame("Hello");
Graphics g = workingManager.getGraphics();
JPanel jp = (JPanel) workingManager.getContentPane();
workingManager.paintComponents(g);
g.fillOval(0, 0, 30, 30);
g.drawOval(0, 50, 30, 30);
g.setColor(Color.CYAN);
workingManager.setSize(500, 500);
workingManager.setVisible(true);

Categories