i am making a custom jpanel acting like a canvas for a game.
i was thinking of making the JPanel have a fixed size and use a LayoutManager to make it align to center.
but now i have the following problem:
if i draw something in my custom JPanel like,
#Override
public synchronized void paintComponent(Graphics g) {
g.fillRect(0, 0, 10, 10);
}
will the coordinates i give to the Graphics object be relative to my JPanel top left corner or relative to the inside of the window top left corner? (aka the rectangle within the decoration)
Here's a somewhat simple example I created for a different question.
Change the location of the rectangles and see where they wind up.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShapesExample extends JFrame {
private static final long serialVersionUID = 1L;
private List<Rectangle> rectangles;
public ShapesExample() {
rectangles = new ArrayList<>();
rectangles.add(new Rectangle(10, 10, 20, 20));
rectangles.add(new Rectangle(41, 41, 20, 20));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Shapes Example");
add(new DrawingPanel());
pack();
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShapesExample();
}
});
}
class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(300, 300));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
for (Rectangle rectangle : rectangles) {
g.drawRect(rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
}
}
}
}
Related
If I create a JFrame 800x600 pixels and draw a line from (0,0) to (800,600) it doesn't go from corner to corner, so, where is the (0,0) and where is the (800,600)?
Here is the code
import java.awt.Graphics;
import javax.swing.JFrame;
public class Point0_0test extends JFrame {
public Point0_0test() {
setTitle("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawLine(0, 0, 800, 600);
}
public static void main(String[] args) {
Point0_0test test = new Point0_0test();
test.setVisible(true);
}
}
Here you can see what appears when the program is running
If you want a drawing area that's 800 x 600 pixels, then set a drawing area that's 800 x 600 pixels. Who cares how big the frame is?
Here's a simple drawing GUI that I created. I made it 400 x 300 pixels so it would fit in the answer easier.
Here's the code. It's a minimal, runnable example for setting the size of the drawing area.
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleDrawingArea implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleDrawingArea());
}
#Override
public void run() {
JFrame frame = new JFrame("Simple Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(400, 300));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(4f));
g2d.drawLine(0, 0, 400, 300);
}
}
}
The JFrame size and coordinates count the size of the decorations, such as the top part of the window contains the bar with the close button, the rest contain the extra outline that is added on Windows(Ubuntu, at least, doesn't seem to add an extra outline). In order to get a line like you would want to, you should use JFrame.getInsets(), which returns the size of the GUI that decorates the JFrame, like this:
import java.awt.Insets;
#Override
public void paint(Graphics g) {
super.paint(g);
Insets in = getInsets();
g.drawLine(in.left, in.top, 800-in.right, 600-in.bottom);
}
Edit: this means that you don't have an actual 800x600 space. The Insets class seems to be "created" when setVisible(true) is called, as far as I can tell. So this would be how the code for that looks like:
import javax.swing.JFrame;
import java.awt.Insets;
import java.awt.Graphics;
public class InsetsTest extends JFrame {
public InsetsTest() {
super();
setTitle("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,600);
setVisible(true);
Insets insets= getInsets();
setSize(800+insets.right+insets.left,600+insets.top+insets.bottom);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Insets in = getInsets();
g.drawLine(in.left, in.top, 800+in.left, 600+in.top);
}
public static void main(String[] args) {
InsetsTest test = new InsetsTest();
test.setVisible(true);
}
}```
The window size should be defined without OS specific window decoration.
Try to add
this.setUndecorated(true);
before the
this.setVisible(true);
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
the code:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PaintWindow {
private JFrame frame;
private aJPanel panel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PaintWindow window = new PaintWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public PaintWindow() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new aJPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
panel.stam();
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.NORTH);
frame.setBounds(100, 100, 450, 300);
frame.setVisible(true);
}
public class aJPanel extends JPanel {
private static final long serialVersionUID = 8874943072526915834L;
private Graphics g;
public aJPanel() {
super();
System.out.println("Constructor");
}
public void paint(Graphics g) {
super.paint(g);
System.out.println("paint");
g.fillRect(10, 10, 10, 10);
this.g = g;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paintComponent");
g.fillRect(20, 20, 20, 20);
this.g = g;
}
public void stam() {
System.out.println("stam");
this.g.fillRect(40, 40, 40, 40);
this.repaint();
}
}
}
what I want to do is paint custom shapes (lines, rectangles etc) after the user clicks a button or triggers a mouse event. but calling aJPanel.stam() does not show the rectangle its supposed to. I am fairly new to JPanel. any suggestions?
First of all:
class names should start with a capital letter
class names should be descriptive.
"aJPanel" does not follow either of the above.
but calling aJPanel.stam() does not show the rectangle its supposed to
See Custom Painting Apporoaches for the two common ways to do dynamic painting:
Add objects to a List and iterate the List to paint all the objects
Paint directly to a BufferedImage and then paint the BufferedImage
The examples add the Rectangle by dragging the mouse, but you can easily add Rectangles by just invoking the addRectangle(...) method when you click a button.
When I run this code. The result is a window with the name. Fully blank. I tried editing background color and adding graphics (rectangle) etc but the same result keeps occurring .
Question: This ends up as a white screen on a window. No graphics or background color. Even though I added it to panel and added panel. How do I fix this?
Main.java
package ball.tec.main;
import javax.swing.JFrame;
import ball.tec.frame.Frame;
public class Main {
public static void main(String[] args) {
String Version = "0.1.2";
Frame f = new Frame();
f.setVisible(true);
f.add();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.setSize(1500, 1000);
f.setTitle("RedBall V: " + Version);
}
}
Frame.java
package ball.tec.frame;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame{
private static final long serialVersionUID = 1L;
public boolean debug = false;
//Creating panel object
JPanel panel = new JPanel();
//Graphics displayed
public void paintComponent(Graphics g) {
//Firstly Nothing pops up
g.setColor(Color.RED);
g.drawRect(20, 40, 10, 10);
//And this doesn't work.
this.setBackground(Color.RED);
}
//Add everything to 'panel'
public void add() {
add(panel);
//Even if I put it here it doesn't work ;-;
this.setBackground(Color.RED);
this.pack();
}
}
You don't use paintComponent() in a JFrame. What you probably intended to do was create a third class, extending JPanel. Add your paintComponent() there.
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(20, 40, 10, 10);
this.setBackground(Color.RED);
}
}
f.add(new MyPanel());
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);
}