Wrong Output with the following code - java

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.

Related

Java graphics window doesn't draw when opened from another window through an event

I have three classes, the first one is the main window smthn like
public class Starter extends JFrame{
JButton b=new JButton("Game");
Starter(){
setSize(200,200);
add(b);
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
TryGraph gg=new TryGraph();
}
});
setVisible(true);
}
public static void main(String [] args){
Starter g= new Starter();
}
}
Then the second class is a window that has a panel where the graphics is going to be drawn on
public class TryGraph {
static int w=640,h=480;
TryGraph(){
JFrame mF=new JFrame();
GPan pan=new GPan();
mF.setLocationRelativeTo(null);
mF.setResizable(false);
mF.setSize(w,h);
mF.add(pan);
mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mF.setVisible(true);
pan.playGame();
}
public static void main(String []args){
TryGraph t=new TryGraph();
}
}
Then lastly the panel class which does the drawing
public class GPan extends JPanel{
private boolean running;
private BufferedImage image;
private Graphics2D g;
int x,y;
public GPan(){
x=TryGraph.w;
y=TryGraph.h;
init();
}
public void init(){
running=true;
image=new BufferedImage(x,y,BufferedImage.TYPE_INT_RGB);
g=(Graphics2D)image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
public void playGame(){
while(running){
g.setColor(new Color(102,102,102));
g.fillRect(0,0,x,y);
g.setColor(new Color(255,0,0));
g.fillOval(0, 0, 100,100);
repaint();
}
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(image,0,0,x,y,null);
g2.dispose();
}
}
The problem is if I'm using an event from the Starter class window to the TryGraph class window the GPan panel won't draw the graphics when it loops through play game() method. But when the TryGraph class is executed directly it works fine
A couple of problems I noticed.
When you call main in TryGraph, you create a new instance. But you already have an instance of TryGraph when the button was pressed.
Don't extend JFrame. It's bad practice. Just create an instance of it.
Only use one static main entry point.
The big problem is that you put repaint() in a tight loop. Don't do that. Just call repaint(). Remember that repaint is run on the Event Dispatch Thread. So if that thread is tied up, nothing else will work.
Don't dispose of your graphics context. You can do that if you create a new one but otherwise don't get rid of it.
Finally, put super.paintComponent() as the first statement in your JPanel paintComponent method.
I suggest you read about painting and the EDT in the Java Tutorials.
Here is the modified code, all in one file.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Starter {
JButton b = new JButton("Game");
JFrame frame = new JFrame();
Starter() {
frame.setSize(200, 200);
frame.add(b);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
TryGraph gg = new TryGraph();
}
});
frame.setVisible(true);
}
public static void main(String[] args) {
Starter g = new Starter();
}
}
class TryGraph {
static int w = 640, h = 480;
TryGraph() {
JFrame mF = new JFrame();
GPan pan = new GPan();
mF.setLocationRelativeTo(null);
mF.setResizable(false);
mF.setSize(w, h);
mF.add(pan);
mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mF.setVisible(true);
pan.playGame();
}
}
class GPan extends JPanel {
private boolean running;
private BufferedImage image;
private Graphics2D g;
int x, y;
public GPan() {
x = TryGraph.w;
y = TryGraph.h;
init();
}
public void init() {
running = true;
image = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
public void playGame() {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(new Color(102, 102, 102));
g2.fillRect(0, 0, x, y);
g2.setColor(new Color(255, 0, 0));
g2.fillOval(0, 0, 100, 100);
// g2.drawImage(image,0,0,x,y,null);
g2.dispose();
}
}
One additional suggestion. In your original code I believe you implemented a listener by implementing the interface in a private class. Good idea except you should extend the adapter class for the given interface. For example, for mouseListener, extend MouseAdapter. It provides dummy methods so you don't have to create them yourself. It helps make your code more readable. Of course, single method interfaces don't have ( or need) adapters.

How to see BufferedImage in JPanel?

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.

What will be the Main of this program in java |How do i call the line method in main?

package drawinglinebymethods;
import java.awt.*;
import javax.swing.JFrame;
public class DrawingLineByMethods extends Frame {
public JFrame f=new JFrame();
void fra_size()
{
f.setSize(450, 300);
}
void fra_visible()
{
f.setVisible(true);
}
void fra_title()
{
f.setTitle(" java frame");
}
void exit()
{
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void line(Graphics g) {
g.drawLine(10, 10, 20, 300);
}
public static void main(String[] args) {
DrawingLineByMethods obj = new DrawingLineByMethods();
obj.fra_size();
obj.fra_title();
obj.fra_visible();
obj.fra_exit();
obj.line(g); // <-- error here
}
}
Your question suggests that you are not yet clear on how graphics and drawing works in Swing GUI's. Some suggestions for you:
Don't have your class extend java.awt.Frame as this makes no sense. You're not creating an AWT Frame window and have no need of this.
Create a class that extends JPanel and draw in its paintComponent method as the Swing painting tutorials (link now added) show you.
You never call drawing code directly but rather it is indirectly called by the JVM.
If you want to draw from outside of the GUI itself, then draw to a BufferedImage, one that is then displayed within the GUI.
Don't use a Graphics object obtained by calling getGraphics() on a GUI component as the object thus obtained will not persist, and this risks you creating unstable graphics or worse -- throwing a NullPointerException.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
public LineDraw() {
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
If you want to add lines as the program runs, again, use a BufferedImage that is drawn within the JPanel's paintComponent method. When you need to add a new line to the GUI, extract the Graphics or Graphics2D object from the BufferedImage using getGraphics() or createGraphics() respectively (it's OK to do this), draw with this Graphics object, dispose of the Graphics object, and repaint the GUI. For example in the code below, I draw a new line when the button is pressed by adding code within the JButton's ActionListener (actually its AbstractAction which is similar to an ActionListener but more powerful):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
private BufferedImage img;
private int yDistance = 20;
private int deltaY = 10;
public LineDraw() {
img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
add(new JButton(new DrawLineAction("Draw Line", KeyEvent.VK_D)));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw the buffered image here
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
public void drawNewLines() {
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
yDistance += deltaY;
g2.drawLine(10, 10, yDistance, PREF_H);
g2.dispose();
repaint();
}
private class DrawLineAction extends AbstractAction {
public DrawLineAction(String name, int mnemonic) {
super(name); // give button its text
putValue(MNEMONIC_KEY, mnemonic); // alt-hot key for button
}
#Override
public void actionPerformed(ActionEvent e) {
drawNewLines();
}
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
Line is a non-static method, the only way to call it from a static method (main here) is to have an instance of the class.

Set Transparent Color for the Whole JPanel

I have a JPanel with a JLabel which owns an Icon picture.
how do I set a transparent red color at the top of the whole JPanel (including JLabel Icon)?
I have the transparent backgriound color on for the panel but I want the whole panel including the picture and everything get this transparent color. something like a transparent colorful glass at the top of the JPanel
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TransparentJLabel {
private static final String IMAGE_PATH = "http://duke.kenai.com/Oracle/OracleStratSmall.png";
private static void createAndShowUI() {
JPanel panel = new JPanel();
panel.setBackground(Color.pink);
URL imageUrl;
try {
imageUrl = new URL(IMAGE_PATH);
BufferedImage image = ImageIO.read(imageUrl);
ImageIcon icon = new ImageIcon(image);
JLabel label = new JLabel(icon);
panel.add(label);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
JFrame frame = new JFrame("TransparentJLabel");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
If you just need a layered panel over the whole contentPane, a simple glassPane will do fine (override it's paintComponent(...) method). For example:
JPanel glassPane = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(new Color(0, 100, 0, 100));
g2.fillRect(0, 0, getWidth(), getHeight());
g2.dispose();
}
};
glassPane.setOpaque(false);
frame.setGlassPane(glassPane);
frame.getGlassPane().setVisible(true);
However, if you want a layered panel over only one JPanel, I would use JLayer combined with LayerUI, as MadProgrammer already mentioned. You will need a custom LayerUI in which you override the paint(Graphics g, JComponent c) method. I know that sounds dangerous, but I honestly don't know of another way of doing it...
I've provided an example below, this is the output:
As you can see, panel1 (or more accurately, the JLayer) is slighty transparent (RGBA = "0, 100, 0, 100") and panel2 is normal.
Code:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
public class Example {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
public Example() {
JFrame frame = new JFrame("Example");
JPanel panel1 = new JPanel();
panel1.add(new JButton("Panel 1"));
MyLayerUI layerUI = new MyLayerUI();
JLayer<JPanel> panel1Layer = new JLayer<JPanel>(panel1, layerUI);
panel1.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (layerUI.hasOverlay()) {
layerUI.setOverlay(false);
} else {
layerUI.setOverlay(true);
}
panel1Layer.repaint();
}
});
JPanel panel2 = new JPanel();
panel2.add(new JButton("Panel 2"));
JPanel contentPane = new JPanel(new GridLayout(2, 1));
contentPane.add(panel1Layer);
contentPane.add(panel2);
frame.setContentPane(contentPane);
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyLayerUI extends LayerUI<JPanel> {
private boolean overlay = true;
#Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (hasOverlay()) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(new Color(0, 100, 0, 100));
g2.fillRect(0, 0, c.getWidth(), c.getHeight());
g2.dispose();
}
}
public boolean hasOverlay() {
return overlay;
}
public void setOverlay(boolean overlay) {
this.overlay = overlay;
}
}

Graphics not working in Java

I am trying to mess around with some graphics in java, however i can't get it to work. The JFrame comes up with the button i created, but the JFrame is just gray with no red line that i want it to draw.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Shapes extends JFrame implements ActionListener{
JButton button = new JButton("click");
public Shapes() {
setVisible(true);
setSize(500, 500);
button.addActionListener(this);
button.setSize(20, 20);
setLayout(new FlowLayout());
add(button);
repaint();
}
public static void main(String[] args){
Shapes s = new Shapes();
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.drawLine(5, 10, 10, 20);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button){
repaint();
}
}
}
Two things:
1). You don't really want to do custom painting on a top-level container such as a JFrame. Instead you want to use a JPanel
class Panel extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.drawLine(5, 10, 10, 20);
}
}
And add it to your JFrame: add(new Panel()); (Or create an object if you want).
2). setVisible(true); should be the very last thing that you do while setting up your window. So change your constructor:
public Shapes() {
setSize(500, 500);
button.addActionListener(this);
button.setSize(20, 20);
setLayout(new FlowLayout());
add(button);
add(new Panel()) // added from part 1
repaint();
setVisible(true);
}
For more information go through the "performing custom painting tutorials."

Categories