I am trying to get an Image for a little animation but the Panel stays white.
The image is in the same folder than the class.
public class JBallonPanel extends JPanel implements Runnable{
private Image img;
private int x, y;
JBallonPanel(){
setBackground(Color.white);
img=Toolkit.getDefaultToolkit().createImage(".//Ball.jpg");
x=this.getWidth()/2;
y=this.getHeight()/2;
}
public void paintComponent(Graphics g){
g.drawImage(img, x, y,
img.getWidth(this), img.getWidth(this), this);
}
Take a look below, I just did some adjustments, but your code is working.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
//public class JBallonPanel extends JPanel implements Runnable {
//You can remove implements Runnable
public class JBallonPanel extends JPanel {
private Image img;
private int x, y;
JBallonPanel(){
setBackground(Color.white);
// your path should have \\ for example C:\\Ball.jpg or C:\\myImageFolder\\Ball.jpg
// but in your case, it works too.
img=Toolkit.getDefaultToolkit().createImage("C:\\Ball.jpg");
x=this.getWidth()/2;
y=this.getHeight()/2;
}
public void paintComponent(Graphics g){
g.drawImage(img, x, y, img.getWidth(this), img.getWidth(this), this);
}
//And run like this
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new JBallonPanel());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setSize(800, 800);
frame.setVisible(true);
}
}
Related
Here is a little program that should (in theory) draw an image of a ball on screen.
The problem is that paintComponent seems to not get called. The program consists of two classes.
import java.awt.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ScreenSaver extends JPanel {
private static final long serialVersionUID = 001;
public static void main(String[] args) {
new ScreenSaver();
}
public ScreenSaver() {
new Window(1600, 900, "ScreenSaver", this);
}
//----------------------------------------------------------------------------------
private static BufferedImage ball;
public static BufferedImage getBallSprite() {
try {
File pathToBall = new File("ball.png");
ball = ImageIO.read(pathToBall);
} catch (IOException ex) {
ex.printStackTrace();
}
return ball;
}
}
import java.awt.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Window extends Canvas {
private static final long serialVersionUID = 002;
public Window(int width, int height, String title, ScreenSaver ScreenSaver) {
JFrame frame = new JFrame(title);
frame.setPreferredSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
repaint();
}
public void paintComponent(Graphics g) {
System.out.println("Painting...");
BufferedImage ball = ScreenSaver.getBallSprite();
g.drawImage(ball, 0, 0, 100, 100, this);
}
}
As you can see, I tested if paintComponent was called using a console message. Sadly this was not the case. Can someone explain?
java.awt.Canvas does not inherit from JComponent so paintComponent won't be called automatically. You can create a new custom window instead to create a Swing-centric component
public class MyWindow extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
...
}
It's no wonder that paintComponent is not called, because Canvas has no implementation of paintComponent which you can override. With a canvas you have to overwrite paint for your purposes. In your code you use both a JPanel and a Canvas, which is not necessary at all. Use either of the two.
The following is an example with a Canvas:
import java.awt.*;
import javax.swing.*;
public class ScreenSaver extends Canvas{
public static void main(String[] args) {
JFrame window = new JFrame("Screensaver");
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setResizable(false);
ScreenSaver canvas = new ScreenSaver();
canvas.setPreferredSize(new Dimension(1600, 900));
canvas.setBackground(Color.BLACK);
window.add(canvas);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
#Override
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillOval(100, 100, 100, 100);
}
}
The annotation Override above the method to be overwritten ensures that the compiler can issue a warning message if the overwritten method does not exist or there is a typo. I hope this helps you further.
Currently I am having an issue whereby the Robot.png is replacing the image of my gameboard.png . I want to make it so that the robot .png is ontop of the board and be able to move the robot around the board.
Board.Java
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Board extends JPanel {
private Image gameboard;
public Board(){
initBoard();
}
private void initBoard(){
loadImage();
int w = gameboard.getWidth(this);
int h = gameboard.getHeight(this);
setPreferredSize(new Dimension(w,h));
}
private void loadImage(){
ImageIcon i = new ImageIcon("res/gameboard.png");
gameboard = i.getImage();
}
#Override
public void paintComponent(Graphics g){
g.drawImage(gameboard,0,0,null);
}
}
Player.Java
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.ImageIcon;
public class Player extends JPanel {
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
ImageIcon ic = new ImageIcon("res/Robot.png");
Image image1 = ic.getImage();
g2d.drawImage(image1, 100, 100, null);
}
}
GameGUI.Java
import javax.swing.JFrame;
public class GameGui extends JFrame {
public GameGui(){
initGui();
}
public void initGui(){
add(new Board());
add(new Player());
setTitle("11+ Game");
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setSize(1240,620);
}
}
You don't need to reload the robot image every time. You should use ImageIO to load it, and save it in a member variable.
Otherwise, the way to not have the image overwrite the whole background image is to use height and width parameters with your drawImage call
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
ImageIcon ic = new ImageIcon("res/Robot.png");
Image image1 = ic.getImage();
int width = ..., height = ...;
g2d.drawImage(image1, 100, 100, width, height, null);
}
I created a Java gui that displays a circle with a JSlider that can be moved from left to right and changes the size of the circle. Everything runs with no errors. My issue is getting a JTextfield that would display the area, diameter, radius, etc.. of the circle and updates it when the JSlider is moved. I have one main class and two sub-classes. I didn't put the main since it's not important.
Here's what I have"
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
public class SliderFrame extends JFrame
{
private JSlider diameterJSlider;
private OvalPanel myPanel;
public SliderFrame()
{
super("Circle");
myPanel = new OvalPanel();
myPanel.setBackground(Color.WHITE);
diameterJSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
diameterJSlider.setMajorTickSpacing(10);
diameterJSlider.setPaintTicks(true);
diameterJSlider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
myPanel.setDiameter(diameterJSlider.getValue());
}
}
);
add(diameterJSlider, BorderLayout.SOUTH);
add(myPanel, BorderLayout.CENTER);
}
}
import java.awt.Graphics;
import java.awt.Dimension;
import javax.swing.JPanel;
public class OvalPanel extends JPanel
{
private int diameter = 10;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(30, 30, diameter, diameter);
}
public void setDiameter(int newDiameter)
{
diameter = (newDiameter >= 0 ? newDiameter: 10 );
repaint();
}
public Dimension getPreferredSize()
{
return new Dimension(200, 200);
}
public Dimension getMinimumSize()
{
return getPreferredSize();
}
}
Problem: I am trying to update the canvas with new painting objects based on user action. The canvas dosent get updated.
What i have done: The user interacts with the DnD action,The transferrable object reaches the canvas, Calls an update graphics method created by me. And the method simply uses the aldready created graphics 2d object and draws images using it.I have checkd the DnD action,the object is properly recived at canvas class and i was able to print them out using System.out.println.
A sample code,that has a similar function to that of mine,
Paint class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class PaintPanel extends JPanel{
private Graphics2D drawImage;
public PaintPanel()
{
}
#Override
public void paint(Graphics g) {
drawImage = (Graphics2D) g;
drawImage.setColor(Color.WHITE);
drawImage.fillRect(0, 0, getWidth(), getHeight());
}
public void updateGraphics(int length,int width)
{
drawImage.setColor(Color.black);
drawImage.drawRect(100, 150, length, width);
repaint();
}
}
mainframe class:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MainPaint extends JFrame{
public MainPaint()
{
setTitle("test paint");
setSize(400,400);
setLayout(new BorderLayout());
final PaintPanel paintPan = new PaintPanel();
JButton testButon = new JButton("Display shape");
add(paintPan,BorderLayout.CENTER);
add(testButon,BorderLayout.PAGE_END);
testButon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
paintPan.updateGraphics(50,50);
repaint();
}
});
setVisible(true);
}
public static void main(String[] args)
{
new MainPaint();
}
}
Graphics2D drawImage; //source of the problem!
Don't attempt to cache a Graphics (or Graphics2D) instance! Instead:
Add the new objects to a list
Call repaint().
In paintComponent(Graphics) draw the list of objects.
An alternative to that is to use a BufferedImage as the drawing object. See this answer for an example.
Update - SSCCE based on latest code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainPaint extends JFrame {
public MainPaint() {
setTitle("test paint");
setSize(400, 400);
setLayout(new BorderLayout());
final PaintPanel paintPan = new PaintPanel();
JButton testButon = new JButton("Display shape");
add(paintPan, BorderLayout.CENTER);
add(testButon, BorderLayout.PAGE_END);
testButon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
paintPan.updateGraphics(50, 50);
repaint();
}
});
setVisible(true);
}
public static void main(String[] args) {
new MainPaint();
}
}
class PaintPanel extends JPanel {
private int x, y;
private Color color = null;
public PaintPanel() {
setBackground(Color.ORANGE);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D drawImage = (Graphics2D) g;
if (color != null) {
drawImage.setColor(color);
drawImage.drawRect(100, 150, x, y);
}
}
public void updateGraphics(int length, int width) {
color = Color.RED;
x = length;
y = width;
repaint();
}
}
Note
There are still a number of things about that code that need changing. I decided to stop at the earliest variant that worked to display the rectangle on button click.
I think you need to call the validate() method.
I'm trying to build a simple paint tool. The mouseDrag events creates a new ellipse and causes my JPanel to repaint().
This works fine so far.
However, if I press any button (or any other UI component) before firing the mouseDrag event for the first time, the button is painted in the upper left corner of my panel.
I have isolated the code into this test application:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame
{
public Test()
{
final JPanel paintPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setPaintMode();
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(100, 100, 10, 10);
}
};
paintPanel.setPreferredSize(new Dimension(300,300));
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e)
{
paintPanel.repaint();
}
});
this.setLayout(new FlowLayout());
this.add(paintPanel);
this.add(new JButton("Dummy"));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String... args)
{
new Test();
}
}
A Screenshot for "seeing" the problem in my Main application
+1 to #MadProgrammer's answers.
You should have super.paintComponent(..) as the first call in your overriden paintComponent()
Do not extend JFrame unnecessarily
Create and minipulate Swing components via EDT
Dont call setPrefferedSize() rather override getPrefferedSize()
Here is an example which incorporates my advice's and #MadProgrammer's:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
JFrame frame;
public Test() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final PaintPanel paintPanel = new PaintPanel();
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
paintPanel.addRect(e.getX(), e.getY());
}
});
frame.setLayout(new FlowLayout());
frame.add(paintPanel);
frame.add(new JButton("Dummy"));
frame.pack();
frame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class PaintPanel extends JPanel {
public PaintPanel() {
addRect(100, 100);
}
ArrayList<Rectangle> rects = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaintMode();
for (Rectangle r : rects) {
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(r.x, r.y, r.width, r.height);
}
}
public void addRect(int x, int y) {
rects.add(new Rectangle(x, y, 10, 10));
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
You're not calling super.paintComponent.
The graphics context used for a paint cycle is shared between all the components begin painted, this means if you don't take care to clear it before painting onto, you will end up with what ever was painted before you.
One of the jobs of paintComponent is to prepare the graphics for painting