I'm a beginner trying to print a basic window with a line 0,0,500,500.
I've tried validate, doLayout, printAll. I am unsure about the g in the printAll. I can't find anywhere that says what it is. ??
package helloprogram;
import java.awt.Graphics.*;
/**
*
* #author jglvn
*/
class Component{
void setSize(int width, int height){ }
void setBounds(int x, int y){ }
void drawLine(int x1, int y1, int x2, int y2){ }
void setBackground(int r, int g, int b){ }
void validate(){ }
void doLayout(){ }
void printAll(Graphics g){ }
}
public class HelloProgram {
public static void main(String[] args) {
Component canvas = new Component();
canvas.setSize(500, 500);
canvas.setBounds(300, 300);
canvas.setBackground(153,153,153);
canvas.drawLine(0, 0, 500, 500);
canvas.doLayout();
canvas.validate();
canvas.printAll(g);
}
}
It seams you want to draw a line in a frame. If this is the case, you should go for some container like a JPanel. You want to paint something on the panel, you should override the paint method:
Here is a sample code:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawLinePanel extends JPanel{
private static final int FRAME_HEIGHT = 600;
private static final int FRAME_WIDTH = 600;
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(FRAME_WIDTH, FRAME_HEIGHT);
f.add(new DrawLinePanel(new Point(100, 100), new Point(500, 500)));
f.setVisible(true);
}
private Point pointA;
private Point pointB;
public DrawLinePanel(Point pointA, Point pointB) {
this.pointA = pointA;
this.pointB = pointB;
}
#Override
public void paint(Graphics g) {
super.paintComponents(g);
//
Graphics2D g2 = (Graphics2D) g;
g2.drawLine(pointA.x, pointA.y, pointB.x, pointB.y);
}
}
Some advice:
Don't make the frame visible before you do all your graphics.
Don't mix the Component sub classes like Frame or Panel with JComponent sub classes like JFrame or JPanel.
Hope this would be helpful.
Related
I am working on a simple app Java/Swing, which involves having the user click on a box and drag it around. I am having troubles with understanding how the repaint method can be used. I created this example of the problem, in which a square is drawn and then on mousePressed it gets the x cordinates of the click, and displaces the original drawing by however much the pointer is moved.
I have read the commonly referred guides on drawing in Swing, but I haven't seen any answers to the question on how to write a program that incorporates both mouseMotion and mouseListener (which as far as I can tell means that the mouseListener must be implemented as its own class, as opposed to the common solution of incorporating it into the custom JPanel class) and also calls repaint() based on mouse actions.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.MouseInputAdapter;
class drawTest extends JPanel {
static int xpos_square = 200;
static int ypos_square = 200;
int width = 100;
int height = 100;
static int x_init;
static int y_init;
public drawTest(){
addMouseListener(new mouseListener());
addMouseMotionListener(new mouseListener());
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawSquare(g);
}
public void drawSquare(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(xpos_square, ypos_square, height, width);
}
public static void moveShape(int x, int y){
xpos_square += x-x_init;
ypos_square += y-y_init;
repaint();
}
public static void getChord(int x, int y){
x_init = x;
y_init = y;
}
}
class mouseListener extends MouseInputAdapter{
public void mousePressed(MouseEvent e){
drawTest.getChord(e.getX(),e.getY());
}
public void mouseDragged(MouseEvent e){
drawTest.moveShape(e.getX(),e.getY());
}
}
public class myTest {
JFrame myFrame = new JFrame();
JPanel myDrawing = new drawTest();
public myTest () {
myFrame.add(myDrawing);
myFrame.setSize(500,500);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String []args){
new myTest();
}
}
The issue is of course that repaint() cannot be called in a static context. However, I don't see how I can avoid this, since if I want the position to smoothly update, it has to be called via the mouseDragged method.
How else could I use the repaint() method to redraw based on mouse movements?
So I figured out a way around it, using anonymous methods in addMouseListener. This bypasses the need for static methods in the call to repaint. If anyone else has a similar question, maybe they will find it helpful.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.MouseInputAdapter;
class DrawTest extends JPanel {
static int xpos_square = 200;
static int ypos_square = 200;
int width = 100;
int height = 100;
static int x_init;
static int y_init;
public DrawTest(){
addMouseListener(new mouseListener(){ public void mousePressed(MouseEvent e){
getClick(e.getX(),e.getY());
}});
addMouseMotionListener(new mouseListener(){ public void mouseDragged(MouseEvent e){
moveShape(e.getX(),e.getY());
}});
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawSquare(g);
}
public void drawSquare(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(xpos_square, ypos_square, height, width);
}
public void moveShape(int x, int y){
if((x >= xpos_square)&&(x <= xpos_square + width)&&(y >= ypos_square)&&(y <= ypos_square + height)){
xpos_square += x-x_init;
ypos_square += y-y_init;
x_init = x;
y_init = y;
repaint();
}
}
public void getClick(int x, int y){
x_init = x;
y_init = y;
}
}
public class MyTest {
JFrame myFrame = new JFrame();
JPanel myDrawing = new DrawTest();
public MyTest () {
myFrame.add(myDrawing);
myFrame.setSize(500,500);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String []args){
new MyTest();
}
}
I want to know How could I draw a String or Rectangle (the JFrame is in a full screen completely)
Heres what in my Main.java class:
public static int WIDTH, HEIGHT;
private Window window;
...
public Main() {
window = new Window("2D Shooter", this);
...
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);//this calls the render method to render objects
g.dispose();
bs.show();
}
Later in a different class I have:
public void render(Graphics g){
...
g.setColor(Color.WHITE);
g.drawString("2D Shooter", ((Main.WIDTH)/2), (Main.HEIGHT/5));
...
}
This Code Works and runs BUT the text is not completely centered I want it to be Centered on top not in the middle. Thank You!
Use the graphics context's FontMetrics.
String s = "2D Shooter";
int w2 = g.getFontMetrics().stringWidth(s) / 2;
int h2 = g.getFontMetrics().getHeight();
g.drawString(s, getWidth() / 2 - w2, h2);
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see http://stackoverflow.com/a/37150783/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(getFont().deriveFont(Font.BOLD, 24f));
String s = "2D Shooter";
int w2 = g.getFontMetrics().stringWidth(s) / 2;
int h2 = g.getFontMetrics().getHeight();
g.drawString(s, getWidth() / 2 - w2, h2);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}
I am trying to learn the paint method and get a ball to move across the frame. here is my code so far. w=.
I currently have two classes One is the main and one for the ball.
this is the main class
import java.awt.;
import javax.swing.;
public class PaintTest extends JPanel {
int x = 0;
int y = 0;
public void moveBall(){
x = x + 1;
y = y + 1;
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Ball ball = new Ball(x,y);
while(true){
ball.moveBall();
repaint();
}
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.magenta);
g.drawLine(0,100,500,100);
g.drawLine(0,101,500,101);
g.drawLine(0,102,500,102);
g.drawLine(0,103,500,103);
g2.fillOval(x,y,35,35);
}
}
and here is the ball class
public class Ball {
int x,y;
public Ball(int x, int y){
this.x = x;
this.y = y;
}
}
now when i compile I get an error saying cannot find symbol ball in class PaintTest even though I am calling it from the class Ball. I am aware of the repaint error as i do not know what to put in front of it.
Draw in a JPanel
In its paintComponent method not in its paint method -- this gives you double buffering.
Call the super's paintComponent method in your override. This allows the JPanel to do housekeeping drawing including erasing the oval image at its old position.
Don't use a while (true) loop as this can cause serious Swing threading issues. Use a Swing Timer instead.
In the Swing Timer, increment your animation variables and then call repaint(). This will tell Swing to repaint the component which will re-draw the oval in the new location.
Don't guess at this stuff as that leads to frustration since Swing graphics coding is a different beast. Instead check the tutorials. You can find links to the Swing tutorials and to other Swing resources here: Swing Info. Also check out Performing Custom Painting with Swing.
Graphics2D goodies: RenderingHints can be used to smooth out your image jaggies.
More Graphics2D goodies: Stroke can be used to draw thicker lines when needed.
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class PaintTest extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private static final Stroke STROKE = new BasicStroke(5f);
private int x;
private int y;
public PaintTest() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// to smooth graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.magenta);
Stroke initialStroke = g2.getStroke();
g2.setStroke(STROKE);
g.drawLine(0, 100, 500, 100);
g2.setStroke(initialStroke);
g2.fillOval(x, y, 35, 35);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
repaint();
}
}
private static void createAndShowGui() {
PaintTest mainPanel = new PaintTest();
JFrame frame = new JFrame("PaintTest");
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(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You have to put the paintComponent method in a JPanel. You can do it by using something like this.
JPanel panel = new JPanel(){
#Overide
public void paintComponent(Graphics g){
super.paint();
// Draw Stuff Here
}
};
The reason you are not getting the ball to move across the frame is that you are not calling the repaint method. You should do so on a thread.
Thread th = new Thread(new Runnable(){
#Overide
public void run(){
while(frame.isVisible()){
ball.moveBall();
panel.repaint();
try{Thread.sleep(5);}catch(Exception e){e.printStackTrace();}
}
}
});
Also, why are you making ball a instance of the PaintTest class? To get only one frame and ball you would want to add a class named Ball and use that to make an instance:
public class Ball{
int x, y;
public Ball(int x, int y){
this.x = x;
this.y = y;
}
}
That is why you were getting 2 frames.
Then you would want to get rid of the x and y variables in the main class. To make an instance using this class you would do:
Ball ball = new Ball(x, y);
Then to paint the ball in the paintComponent method you would do:
g.fillOval(ball.x, ball.y, 35, 35);
You didn't call the repaint(); method.
You don't need the y + 1 part.
Instead of using the while(true) loop, you should use a for loop.
You didn't call the super.paint() method.
You didn't use any Thread.sleep(), which made the ball move across instantaneously.
Here is the code:
import java.awt.*;
import javax.swing.*;
public class PaintTest extends JFrame {
int x = 8;
int y = 30;
public void moveBall(){
x = x + 1;
//y = y + 1;
try{
Thread.sleep(500);
} catch(InterruptedException e){
}
repaint();
}
public static void main(String[] args){
PaintTest frame1 = new PaintTest();
PaintTest ball = new PaintTest();
for(int i = 0; i<100; i++){
//while(true){
ball.moveBall();
}
}
public PaintTest() {
super("Paint Test");
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
super.paint(g);
super.paint(g2);
g.setColor(Color.magenta);
g.drawLine(0,100,500,100);
g.drawLine(0,101,500,101);
g.drawLine(0,102,500,102);
g.drawLine(0,103,500,103);
g.fillOval(x,y,35,35);
}
}
This code will make the ball move across the screen VERY slowly. If you want to speed it up, change the number of miliseconds in the Thread.sleep(miliseconds) part to a smaller number of miliseconds.
I'm making a Java game. I have a Board class which extends JPanel, and have painted a node jim, which is an object instance of Ball class, to the screen using the paintComponent(Graphics g) {. I can move the Ball object around on the JPanel using arrow keys.
Instead of representing the Ball object as a red square, I would like to have an image loaded.
Board class extends JPanel:
jim = new Ball(0, 0, 50, 50, "jim");
Ball class:
public class Ball extends Component {
int x, y, w, h;
BufferedImage jimImg;
public Ball(int xLoc, int yLoc, int width, int height, String imgtype) throws IOException {
x = xLoc;
y = yLoc;
w = width;
h = height;
jimImg = ImageIO.read(new File("resources/Jim.png"));
loadImages(imgtype);
}
public void paint(Graphics g) {
g.drawImage(jimImg, 200, 0, null);
}
It's not drawing on top of the red square though, or even appearing at all.
I have also tried appending the image as a JLabel... here's code within the Ball class:
public void loadImages(String imgType) throws IOException {
if (imgType == "jim") {
JLabel utc = new JLabel("test");
ImageIcon utcImg = new ImageIcon("resources/Miller.png");
utc.setIcon(utcImg);
}
}
But since Ball class is not a JPanel, I can't add the label to the object.
Don't compare Strings with ==, use equals
if (imgType == "jim") ==>> if ("jim".eqauls(imgType))
You should be reading from a URL and not a File object. A URL can be obtained by using getClass().getResource(). e.g.
jimImg = ImageIO.read(
Ball.class.getResource("/resources/Jim.png"));
You should use a try/catch in the constructor, so you won't have to later when you instantiate the Ball
It's preffered to paint on JPanel and override its paintCompoent, or JComponet
You never actually use the variable taken from your constructor to use to paint`
g.drawImage(jimImg, x, y, w, h, this);
When working with painting, you should override the getPreferredSize of the JPanel so the frame will size it accordingly.
Here's a running example that works. Keep in mind my file structure look like
ProjectRoot/src/resources/image.png
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Ball extends JPanel {
int x, y, w, h;
BufferedImage jimImg;
public Ball(int xLoc, int yLoc, int width, int height) {
x = xLoc;
y = yLoc;
w = width;
h = height;
try {
jimImg = ImageIO.read(
Ball.class.getResource("/resources/stackoverflow5.png"));
System.out.println(jimImg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(jimImg, x, y, w, h, this);
}
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new Ball(50, 50, 100, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
EDIT in response to OP commment
"the way my classes are structured: Main class adds JFrame, where I add a new Board class object to the JFrame (Board class extends JPanel). Then I have Board class extends JPanel, which adds a new Ball object and has keyboard methods, etc... so I can move the Ball around. Then Ball Class is just a node with get/set methods getX(), setX() etc. So I can't add an image to the Ball class without extending JPanel?"
It doesn't look like you need ball to be a Component at all. Instead of making the ball a compoent, just make it a regular class. And in the paintComponent of your Board JPanel, just call ball.paint() for each ball you have.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Board extends JPanel {
Ball ball = new Ball(50, 50, 200, 200);
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
ball.drawBall(g);
}
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new Board());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
class Ball {
int x, y, w, h;
BufferedImage jimImg;
public Ball(int xLoc, int yLoc, int width, int height) {
x = xLoc;
y = yLoc;
w = width;
h = height;
try {
jimImg = ImageIO.read(
Board.class.getResource("/resources/stackoverflow5.png"));
System.out.println(jimImg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void drawBall(Graphics g) {
g.drawImage(jimImg, x, y, w, h, null);
}
}
How can I draw an equilateral triangle using the graphics method especially the draw polygon method. My issue is that to make an equilateral triangle I need the square root 3/2 and the drawPolygon method I can only use int[],int[],int, the compiler will not let me double because it differ in lengh.
Any help is appreciated.
import java.awt.*;
public class Triangle extends Shape {
// Instance variables
private int leng;
// Constructor
public Triangle(int x, int y, Color color,
int leng) {
super(x, y, color);
this.leng=leng;
}
// Instance methods
public void draw(Graphics g) {
double[] Xcoord = { getX(), getX() + leng, getX() + leng / 2};
double[] Ycoord = { getY(), getY(), getY()*(1.0+ Math.sqrt(3) / (2.0))};
g.drawPolygon(Xcoord,Ycoord,3);
}
public int getHeight() {
return leng;
}
public int getWidth() {
return leng;
}
}
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();
}
});
}
}
This was found from about drawing a Polygon in java after searching in google.