I'm building a PongClone but I encounter a bug. **I think the bug is cause by JPanel.
I tried the Image instead of BufferedImage.
I tried the drawImage outside the paintComponent method.
I create to another panel and then add that panel inside a mainpanel.
Menu Class
package me.pong;
import javax.swing.*;
public class TestMenu {
JFrame frame;
public void createFrame () {
TestMain main = new TestMain ();
frame = new JFrame("TEST");
frame.setSize (800, 450);
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane ().add (main.panel);
frame.setVisible (true);
}
}
MainClass
package me.pong;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class TestMain extends JPanel {
JPanel panel = new JPanel ();
BufferedImage img;
Graphics g;
public static void main (String[] args) {
TestMain testMain = new TestMain ();
TestMenu menu = new TestMenu ();
menu.createFrame ();
testMain.drawGraphics ();
}
public void drawGraphics(){
panel.add (new TestMain ());
img = new BufferedImage(800, 450, BufferedImage.TYPE_INT_RGB);
g = img.createGraphics ();
g.drawString ("TEST STRING 2", 250,250);
}
#Override
protected void paintComponent (Graphics g) {
super.paintComponent (g);
g.clearRect (0,0,800,450);
g.drawImage (img, 0,0,null);
g.setColor (Color.white);
g.drawString ("TEST STRING", 500,250);
g.setColor (Color.black);
g.drawRect (150,100,10,70);
}
}
I expect the Image fill the component but actual output is little tiny box.
Just like that
EDIT: Delete the code and added MCVE/SSCCE Code(I didn't know that). Still same. If I add the image inside the frame it's works but other way doesn't. I know I'm missing something, but I don't know what that is.
**Yes. Problem caused by JPanel but I don't know how to fix it.
The extra panel declared within the custom painted class that is a panel was not only unnecessary, but the source of problems. See further comments in code.
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class TestMain extends JPanel {
JFrame frame;
// Not needed or useful!
//JPanel panel = new JPanel();
BufferedImage img;
Graphics g;
public static void main(String[] args) {
TestMain testMain = new TestMain();
testMain.createFrame();
testMain.drawGraphics();
}
public void createFrame() {
TestMain main = new TestMain();
frame = new JFrame("TEST");
frame.setSize(400, 250);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//frame.getContentPane().add(main.panel);
frame.getContentPane().add(main);
frame.setVisible(true);
}
public void drawGraphics() {
//panel.add(new TestMain());
add(new TestMain());
img = new BufferedImage(800, 450, BufferedImage.TYPE_INT_RGB);
g = img.createGraphics();
g.drawString("TEST STRING 2", 250, 250);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0, 0, 800, 450);
// all JComponent instances are image observers
//g.drawImage(img, 0, 0, null);
g.drawImage(img, 0, 0, this);
g.setColor(Color.WHITE);
// NEW! Otherwise invisible
g.setColor(Color.RED);
g.drawString("TEST STRING", 200, 100);
g.setColor(Color.BLACK);
g.drawRect(150, 100, 10, 70);
}
}
As an aside:
That code still has problems, but I thought it best to stick closely to fixing only the immediate problem.
The easiest way to display a BufferedImage is to show it in a JLabel via an ImageIcon.
Related
So I am new in java graphics and I am creating a program that will show a rectangle. But when I run my program it only show like a small box and not the rectangle. I don't really know why it is happening.
Here is my code:
import javax.swing.*;
public class GraphicsEditor{
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
Rectangle rectangle = new Rectangle();
frame.setSize(1280, 720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(panel);
panel.add(rectangle);
}
}
This is my rectangle class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Rectangle extends JPanel implements Shape {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.fillRect(0, 0, 200, 130);
}
}
This is my shape interface:
import java.awt.*;
public interface Shape {
void paintComponent(Graphics g);
}
Here, try this
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class GraphicsEditor {
public static void main(String[] args) {
JFrame frame = new JFrame();
Rectangle rectangle = new Rectangle();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(rectangle);
frame.pack();
// center frame on screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class Rectangle extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.fillRect(0, 0, 200, 130);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
}
A couple of things.
you don't need the interface.
unlike components, just painting a picture doesn't affect the layout manager, so the panel will be reduced to it's default size with out regard to any painting.
so you need to override getPreferredSize() in your JPanel.
As the comments said, you should set the preferred size of both your panel and rectangle to your desired size, and then pack the frame, like:
panel.setPreferredSize(new Dimension(500,500));
rectangle.setPreferredSize(new Dimension(500,500));
frame.pack();
Otherwise your LayoutManager (when not specified it defaults to FlowLayout) will handle your rectangle the way it wants. So another way would be learning about Layout Managers, and using your desired one.
As a side note, I would like to make some suggestions to your code. Remember, Swing is not thread safe, so place your code inside an invokeLater() call, such as:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
Rectangle rectangle = new Rectangle();
frame.setSize(1280, 720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(500,500));
rectangle.setPreferredSize(new Dimension(500,500));
frame.add(panel);
panel.add(rectangle);
frame.pack();
frame.setVisible(true);
}
});
Also, calling frame.setVisible(true) should be called after adding your components.
I am using a quite basic setup with a class extending JPanel, which I add to a JFrame.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
public class PinTestMCVE extends JPanel implements ActionListener{
BufferedImage loadedImage;
JButton calcButton;
public static void main(String[] args) {
new PinTestMCVE();
}
public PinTestMCVE() {
loadedImage = getTestImage();
JPanel toolbarPanel = new JPanel();
calcButton = new JButton("calcButton...");
toolbarPanel.add(calcButton);
calcButton.addActionListener(this);
JFrame jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(toolbarPanel, BorderLayout.NORTH);
jf.getContentPane().add(this, BorderLayout.CENTER);
jf.setSize(1250, 950);
jf.setVisible(true);
}
public void paintComponent(Graphics g) {
g.drawImage(loadedImage, 0, 0, this);
}
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent " + e.getActionCommand());
if(e.getSource().equals(calcButton)){
this.repaint();
}
}
//Please ignore the inner workings of this
public static BufferedImage getTestImage(){
BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setPaint(Color.GRAY);
g2d.fillRect ( 0, 0, image.getWidth(), image.getHeight() );
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.gray);
int x = 5;
int y = 7;
GradientPaint redtowhite = new GradientPaint(x, y, Color.red, 200, y, Color.blue);
g2d.setPaint(redtowhite);
g2d.fill(new RoundRectangle2D.Double(x, y, 200, 200, 10, 10));
return image;
}
}
What happens is that INITIALLY the window is painted properly, but once paintComponent is called, a strip of the old image (with the same height as the toolbar panel) is visible below the newly painted images - similar to playing card sticking out from a deck. But then, if I manually resize the window by for instance dragging the border, the background is grayed out as it should.
What is going on and how do I fix this?
As outlined here, you need to pack() the frame before calling setVisible(). You can override getPreferredSize() to specify a suitable initial Dimension. Also consider using a Border. See also Initial Threads.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.*;
public class PinTestMCVE extends JPanel implements ActionListener{
private static final int SIZE = 200;
BufferedImage loadedImage;
JButton calcButton;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new PinTestMCVE();
}
});
}
public PinTestMCVE() {
loadedImage = getTestImage();
JPanel toolbarPanel = new JPanel();
calcButton = new JButton("calcButton...");
toolbarPanel.add(calcButton);
calcButton.addActionListener(this);
JFrame jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(toolbarPanel, BorderLayout.NORTH);
jf.add(this, BorderLayout.CENTER);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setVisible(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(loadedImage, 0, 0, this);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent " + e.getActionCommand());
if(e.getSource().equals(calcButton)){
this.repaint();
}
}
//Please ignore the inner workings of this
public static BufferedImage getTestImage(){
BufferedImage image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setPaint(Color.GRAY);
g2d.fillRect ( 0, 0, image.getWidth(), image.getHeight() );
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.gray);
GradientPaint redtowhite = new GradientPaint(5, 5, Color.red, SIZE, 5, Color.blue);
g2d.setPaint(redtowhite);
g2d.fill(new RoundRectangle2D.Double(5, 5, SIZE - 10, SIZE - 10, 10, 10));
return image;
}
}
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);
I tried to implement a simple GUI application,having a class extend JPanel and then adding it to a frame and adding a button,but nothing happens when I click on the button.What is wrong?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class dup extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.green);
g2d.fillRect(0, 0, this.WIDTH, this.HEIGHT);
System.out.println("inside paint component class");
}
}
public class drawing implements ActionListener {
JFrame frame;
dup d1;
public static void main(String args[]) {
drawing d2 = new drawing();
d2.go();
}
public void go() {
frame = new JFrame();
JButton button = new JButton("click me");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d1 = new dup();
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.WEST, button);
frame.getContentPane().add(BorderLayout.CENTER, d1);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
frame.repaint();
}
}
What is wrong with this?
Width and height is wrong. It should be
g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
You were using constants from ImageObserver class instead of width and height properties of the component.
I would like to create 4 JPanels, draw a white rectangular on each
and then put them inside one, big JPanel. Big JPanel is inside the main frame.
However, the following code does not work. Please, tell me, how to fix this problem?
import javax.swing.*;
import java.awt.Graphics;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
public class Main extends JFrame
{
public void GUI () {
setBounds(0, 0, 480, 960);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
setMinimumSize(new Dimension(480, 960));
setResizable(false);
JPanel mainPanel = new JPanel();
GridLayout GL = new GridLayout(4,0);
mainPanel.setLayout(GL);
JPanel panel1 = new MyCanvas();
JPanel panel2 = new MyCanvas();
JPanel panel3 = new MyCanvas();
JPanel panel4 = new MyCanvas();
mainPanel.add(panel1);
mainPanel.add(panel2);
mainPanel.add(panel3);
mainPanel.add(panel4);
add(mainPanel);
setVisible(true);
}
public static void main(String args[]) throws IOException
{
new Main().GUI();
}
class MyCanvas extends JPanel {
public void drawCanvas(Graphics g) {
super.paintComponent( g ); // call superclass's paintComponent
Graphics2D g2 = ( Graphics2D ) g; // cast g to Graphics2D
g2.setColor(Color.WHITE);
double x = 100;
double y = 100;
double width = x + 200;
double height = y + 50;
g2.fillRect(50, 50, 380, 200);
}
}
}
What is this supposed to do?:
public void drawCanvas(Graphics g) {
....
}
This method overrides no JPanel drawing method and so will not routinely get called when the JVM decides to paint your MyCanvas JPanel.
I think that instead you want to override the class's paintComponent(...) method which can easily be done by simply renaming your method to paintComponent(...). If/when you do this, don't forget to use the #Override annotation to be sure that you're overriding the method with the correct signature. You'll also want to change the method's access specifier to protected, not public.
Next you'll want to do something with those double variables that you're creating.