I have the following java programm:
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class Lapex extends JPanel implements MouseListener{
JPanel p = new JPanel();
Lapex(){
JFrame f = new JFrame();
p.addMouseListener(this);
p.setPreferredSize(new Dimension(600, 600));
f.add(p);
f.pack();
f.show(true);
}
public void paint(Graphics g){
paintComponents(g);
g.setColor(Color.RED);
g.drawLine(10, 10, 100, 100);
}
public void mouseClicked(MouseEvent me){
System.out.println("AAAA");
repaint();
}
}
public static void main(String[] args){
new Lapex();
}
}
Clicking the mouse, at the console is displayied "AAAAA", but draws no line.(I deleted the other mouse event)
How to modify ?
You have to call the super method and use paintComponent.
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawLine(10, 10, 100, 100);
}
A few things to note:
Your class extends JPanel, but then you create another JPanel inside the class that you actually add to the frame. Add the instance of your class instead.
Override paintComponent instead of paint.
Use a call to invokeLater to start your program on the EDT. See Event Dispatch Thread for more info.
Override getPreferredSize rather than call setPreferredSize.
Here is a complete example that toggles the line on/off when the mouse button is clicked:
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.event.*;
public class Lapex extends JPanel {
boolean drawLine = false;
Lapex(){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me){
drawLine = !drawLine;
repaint();
}
});
f.add(this);
f.pack();
f.setVisible(true);
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(drawLine) {
g.setColor(Color.RED);
g.drawLine(10, 10, 100, 100);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
new Lapex();
}});
}
}
No!, don't override paint() leave this up to Swing itself. All you should do is override paintComponent().
Related
I'm learning basics of Java Applet and Swings. I'm trying a simple code. I want to change the color of my panel when a button is clicked. Here's the code:
SimpleGui.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui implements ActionListener {
JFrame frame;
JButton button;
public static void main(String[] args) {
SimpleGui gui = new SimpleGui();
gui.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button = new JButton("changes colour");
button.addActionListener(this);
MyPanel drawPanel = new MyPanel();
frame.getContentPane().add(BorderLayout.SOUTH,button);
frame.getContentPane().add(BorderLayout.CENTER,drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
//event handling method
public void actionPerformed(ActionEvent event) {
frame.repaint();
button.setText("color changed");
}
}
class MyPanel extends JPanel {
public void paintCompenent(Graphics g) {
g.setColor(Color.green);
g.fillRect(20, 50, 100, 100);
}
}
I added some println statements to debug and I found out that paintComponent method is not called. Can you please correct me. Where I am making mistake. Is my entire implementation is wrong?
paintComponent must be protected (see here).
change your code to :
class MyPanel extends JPanel {
protected void paintComponent(Graphics g) {
g.setColor(Color.green);
g.fillRect(20, 50, 100, 100);
}
}
Result:
I am starting with Java and want to make a simple pong game to get into the ways of displaying stuff in java. I have created 2 classes that both extend JPanel and call the repaint() function every 16.6 milliseconds. I added both to a JPanel which I added to the frame, but only the component I added first displays.
I've tried to revalidate() after repaint() in both classes and made sure that the Timer actually works and that it's actionPerformed() method is actually called.
This is the main method:
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame("Pong");
//...
JPanel mainPanel = new JPanel();
mainPanel.add(new Player());
mainPanel.add(new Ball(frameWidth/2, frameHeight/2 -40));
frame.add(mainPanel);
}
}
This is the important code for the classes (It's basically the same for both of them):
public class Player extends JPanel {
public Player(){
setPreferredSize(new Dimension(Main.frameWidth, Main.frameHeight));
setBackground(Color.BLACK);
new Timer(1000/60, new ActionListener(){
public void actionPerformed(ActionEvent e){
update();
repaint();
}
}).start();
}
//...
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
}
}
(Of coure I left things like #Override or unneseccary functions out to shorten the code)
This code only paints the Player, altough I want it to display all the components of mainPanel.
This is an example that you can (hopefully) run. I had to split it up into 3 files, since I suck at anonymus classes:
Main.java
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame("Pong");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 800);
JPanel mainPanel = new JPanel();
mainPanel.add(new Player());
mainPanel.add(new Ball());
frame.add(mainPanel);
frame.setVisible(true);
}
}
///////
Player.java
//////
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Player extends JPanel{
private int x = 20, y = 300, width = 20, height = 100;
public Player(){
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000/60, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
}
}
//////
Ball.java
//////
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Ball extends JPanel{
private int x = 20, y = 300, width = 20, height = 100;
public Ball(){
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000/60, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
}
}
In method paintComponent() of class Player, you paint the exact same Rectangle each time. In order to achieve animation, each time you paint the rectangle you need to change either its size or location or both. What do you expect the Player to do? Should it move up and down along the left edge of the window? Have you seen the lesson entitled How to Use Swing Timers which is part of Oracle's Java Tutorial?
EDIT
I see now that Player hides Ball, because of the default layout manager of JPanel. The below code is essentially the code you posted but I set GridLayout as the layout manager for mainPanel. Also, a java source code file may contain more than one class but exactly one class must be public. Hence in the below code only class Main is public.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Pong");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel(new GridLayout(0, 2));
mainPanel.add(new Player());
mainPanel.add(new Ball());
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class Player extends JPanel {
public Player() {
setBorder(BorderFactory.createLineBorder(Color.RED, 2, false));
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000 / 60, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(20, 100, 20, 100);
}
}
class Ball extends JPanel {
public Ball() {
setBorder(BorderFactory.createLineBorder(Color.CYAN, 2, false));
setPreferredSize(new Dimension(800, 800));
setBackground(Color.BLACK);
new Timer(1000 / 60, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(300, 300, 10, 10);
}
}
And here is a screen capture of the GUI...
I just realized that if I extend my window manually, the second JPanel shows up under the one responsible for the Player! This means that I'll need to set the Panels position somehow, right?
#Abra
I am new in java and i wanted to work on a simple paint program using java swing.
my simple paint program should draw a shape like triangle, circle and square whenever i clicked on buttons.
i managed to draw these shapes and print it without buttons but i can not do it using ActionListener?
As you see i have a single button at the moment, i want to draw the oval whenever this button is clicked.
This is the code that i am working on it so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PaintProject extends JComponent implements ActionListener{
public static void main(String[] args) {
JFrame frame=new JFrame("NEW PAINT PROGRAME!");
JButton button1=new JButton("ADD");
PaintProject paint=new PaintProject();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(paint);
frame.add(button1);
frame.pack();
frame.setVisible(true);
}
#Override
public Dimension getPreferredSize(){
return new Dimension(500,500);
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(0,0, 100, 100);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
Could you please take following steps:
Step 1:
Insert button1.addActionListener(paint); just after PaintProject paint=new PaintProject(); in the main method of PaintProject.java
Step 2:
Remove the method named protected void paintComponent(Graphics g). Instead create following method:
private void drawOval(){
Graphics g = this.getGraphics();
g.setColor(Color.red);
g.fillOval(0,0, 100, 100);
}
Step 3:
Call the above method as follows:
#Override
public void actionPerformed(ActionEvent e) {
drawOval();
}
EDIT:
Following example demonstrates how to draw two shapes when respective buttons are clicked:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class PaintProject extends JComponent implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame("NEW PAINT PROGRAME!");
JButton ovalButton = new JButton("Oval");
ovalButton.setActionCommand("Oval");
JButton rectangleButton = new JButton("Rectangle");
rectangleButton.setActionCommand("Rectangle");
PaintProject paint = new PaintProject();
ovalButton.addActionListener(paint);
rectangleButton.addActionListener(paint);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(paint);
frame.add(ovalButton);
frame.add(rectangleButton);
frame.pack();
frame.setVisible(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
private void drawOval() {
Graphics g = this.getGraphics();
g.setColor(Color.red);
g.fillOval(0, 0, 100, 100);
}
private void drawRectangle() {
Graphics g = this.getGraphics();
g.setColor(Color.green);
g.fillRect(150, 150, 100, 100);
}
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Oval")) {
drawOval();
} else if (command.equals("Rectangle")) {
drawRectangle();
}
}
}
hi there i'm trying to improve myself about java2D and first of all i'm dealing with drawing polygons. However, i can not see the polygon on frame. I read some tutorials and examples but as i said i face with problems. here is the sample code of drawing a polygon;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import javax.swing.JFrame;
public class jRisk extends JFrame {
private JFrame mainMap;
private Polygon poly;
public jRisk(){
initComponents();
}
private void initComponents(){
mainMap = new JFrame();
mainMap.setSize(800, 600);
mainMap.setResizable(false);
mainMap.setVisible(true);
mainMap.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int xPoly[] = {150,250,325,375,450,275,100};
int yPoly[] = {150,100,125,225,250,375,300};
poly = new Polygon(xPoly, yPoly, xPoly.length);
}
protected void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
/**
* #param args
*/
public static void main(String[] args) {
new jRisk();
}
}
JFrame does not have a paintComponent(Graphics g) method. Add the #Override annotation and you will get a compile time error.
1) Use JPanel and override paintComponent (you would than add JPanel to the JFrame viad JFrame#add(..))
2) Override getPreferredSize() to return correct Dimensions which fit your drawing on Graphics object or else they wont be seen as JPanel size without components is 0,0
3) dont call setSize on JFrame... rather use a correct LayoutManager and/or override getPrefferedSize() and call pack() on JFrame after adding all components but before setting it visible
4) Have a read on Concurrency in Swing specifically about Event Dispatch Thread
5) watch class naming scheme should begin with a capital letter and every first letter of a new word thereafter should be capitalized
6) Also you extend JFrame and have a variable JFrame? Take away the extend JFrame and keep the JFrame variable as we dont want 2 JFrames and its not good practice to extend JFrame unless adding functionality
Here is your code with above fixes (excuse picture quality but had to resize or it was going to 800x600):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JRisk {
private JFrame mainMap;
private Polygon poly;
public JRisk() {
initComponents();
}
private void initComponents() {
mainMap = new JFrame();
mainMap.setResizable(false);
mainMap.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
int xPoly[] = {150, 250, 325, 375, 450, 275, 100};
int yPoly[] = {150, 100, 125, 225, 250, 375, 300};
poly = new Polygon(xPoly, yPoly, xPoly.length);
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
};
mainMap.add(p);
mainMap.pack();
mainMap.setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JRisk();
}
});
}
}
As per your comment:
i am preparing a map which includes lots of polygons and yesterday i
used a JPanel over a JFrame and i tried to check if mouse was inside
of the polygon with MouseListener. later i saw that mouseListener gave
false responds (like mouse is not inside of the polygon but it acts
like it was inside the polygon). so i deleted the JPanel and then it
worked
Here is updated code with MouseAdapter and overridden mouseClicked to check if click was within polygon.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JRisk {
private JFrame mainMap;
private Polygon poly;
public JRisk() {
initComponents();
}
private void initComponents() {
mainMap = new JFrame();
mainMap.setResizable(false);
mainMap.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
int xPoly[] = {150, 250, 325, 375, 450, 275, 100};
int yPoly[] = {150, 100, 125, 225, 250, 375, 300};
poly = new Polygon(xPoly, yPoly, xPoly.length);
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
};
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
if (poly.contains(me.getPoint())) {
System.out.println("Clicked polygon");
}
}
};
p.addMouseListener(ma);//add listener to panel
mainMap.add(p);
mainMap.pack();
mainMap.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JRisk();
}
});
}
}
JFrame does not extend JComponent so does not override paintComponent. You can check this by adding the #Override annotation.
To get this functionality extract paintComponent to a new class which extends JComponent. Don't forget to call super.paintComponent(g) rather than super.paintComponents(g).
Replace
protected void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
With
protected void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
First coord in this case should be 0,0 and not 8,30. What am i doing wrong(i am using NetBeans)
import java.awt.Color;
import java.awt.Graphics;
public class TEST extends javax.swing.JFrame {
#Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.blue);
g.drawRect(8, 30, 200, 200);
repaint();
}}
Add a JPanel to the frame and paint in that. The frame's coordinates include the decorations (title bar, borders, etc.). It would look something like this:
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
private Test() {
add(new MyPanel());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 600);
setVisible(true);
}
private class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.drawRect(8, 30, 200, 200);
}
}
}
Also, don't call repaint(); in paint();. That will cause an infinite loop and will freeze the entire program.
The problem is your paint(..) method is not taking into account the JFrame Insets by calling getInsets which as docs state:
If a border has been set on this component, returns the border's
insets.
this code works fine:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void createAndShowGui() {
JFrame frame = new JFrame() {
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.blue);
g.drawRect(0 + getInsets().left, 0 + getInsets().top, 200, 200);
}
};
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
however this is not best practice.
Rather add JPanel to JFrame and override paintComponent(Graphics g) of JPanel dont forget call to super.paintComponent(g) as first call in the overridden method and than draw there (dont forget to override getPreferredSize() and return correct Dimensions so the JPanel will fit its drawing/graphic content) this problem will no longer persist as JPanel is added at correct co-ordinates on contentPane like so:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void createAndShowGui() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.setColor(Color.blue);
g2d.drawRect(0, 0, 200, 200);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
The above includes Graphics2D and RenderingHints i.e anti-aliasing. Just for some better looking drawings :)