The Situation
I am currently trying to build a 2D game with Java's Swing. For this, I have my main class Puzzle which is subclassing JFrame. To my frame I add my main JPanel which consists of several JPanels added together (each of them being a new piece).
EDIT 2: PlayingField is my model which will store the current location of each piece.
One can select a piece with the mouse (the plan is to highlight it) and move it with the arrow keys as long as the next step (a full cell, so approx. 100 pixel) isn't the location of one of the other pieces. As of right now, PlayingFielddoes not store any data since the pieces are missing.
private void createAndShowGui() {
// The playing-field with a 4x6 grid.
PlayingField field = new PlayingField(4, 6);
JPanel mainPanel = new ComputerView(field);
setTitle("Puzzle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 600);
add(mainPanel);
setVisible(true);
}
The method above will create my frame and adds the main panel. The following method is my main panel which adds several JPanels to itself.
public ComputerView(PlayingField field) {
this.field = field;
this.setLayout(null);
JPanel topLeft = new GamingPiece(PlayingField.TOP_LEFT);
add(topLeft);
JPanel topRight = new GamingPiece(PlayingField.TOP_RIGHT);
add(topRight);
JPanel bottomLeft = new GamingPiece(PlayingField.BOTTOM_LEFT);
add(bottomLeft);
}
Each GamingPiece or rather my sub-JPanels are drawing a basic piece (I only drawing one and rotating the others, since all consists of the same arbitrary shape). The GamingPiece class also subclasses JPanel and invokes the JPanel#paintComponent() method to draw the piece.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillPolygon(pieceX, pieceY, pieceX.length);
}
The Problem And My Questions
Since I am pretty new to Java I really do not know how to do it properly. If I add my pieces by creating a new object and adding it to the main panel, it won't show all of them, only the last one added. Some don't even seem to work, even if they're the only ones added (to explain my situation: I have for pieces which are the same arbitrary shape just rotated differently but using Graphics2D#rotate() doesn't seem to work fine).
I hope I explained my situation and my problem well enough fo you guys to help me. Thanks in advance!
EDIT:
My Codes
Puzzle.java
package programming.schimmler;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import programming.schimmler.model.PlayingField;
import programming.schimmler.view.ComputerView;
public class Puzzle extends JFrame {
...
Invoking the createAndShowGui()
...
private void createAndShowGui() {
// The playing-field with a 4x6 grid.
PlayingField field = new PlayingField(4, 6);
JPanel mainPanel = new ComputerView(field);
setTitle("Puzzle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 600);
add(mainPanel);
setVisible(true);
}
}
ComputerView.java
package programming.schimmler.view;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JPanel;
import programming.schimmler.model.PlayingField;
public class ComputerView extends JPanel {
...
Instance variables
....
public ComputerView(PlayingField field) {
this.field = field;
this.setLayout(null);
JPanel topLeft = new GamingPiece(PlayingField.TOP_LEFT);
add(topLeft);
JPanel topRight = new GamingPiece(PlayingField.TOP_RIGHT);
add(topRight);
JPanel bottomLeft = new GamingPiece(PlayingField.BOTTOM_LEFT);
add(bottomLeft);
}
}
GamingPiece.java
package programming.schimmler.view;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import programming.schimmler.model.PlayingField;
/**
*
*/
public class GamingPiece extends JPanel {
...
public GamingPiece(int type) {
switch (type) {
// Need to draw each polygon from different coordinates since rotating did not work yet.
case PlayingField.TOP_LEFT:
pieceX = new int[] { 100, 100, 300, 300, 200, 200, 100 };
pieceY = new int[] { 100, 100, 100, 200, 200, 300, 300 };
break;
case PlayingField.TOP_RIGHT:
pieceX = new int[] { 400, 400, 300, 300, 200, 200 };
pieceY = new int[] { 0, 200, 200, 100, 100, 0 };
break;
case PlayingField.BOTTOM_LEFT:
pieceX = new int[] { 0, 200, 200, 100, 100, 0 };
pieceY = new int[] { 400, 400, 300, 300, 200, 200 };
break;
case PlayingField.BOTTOM_RIGHT:
pieceX = new int[] { 400, 400, 300, 300, 200, 200 };
pieceY = new int[] { 400, 200, 200, 300, 300, 400 };
break;
case PlayingField.SQUARE:
pieceX = new int[] { 100, 300, 300, 100 };
pieceY = new int[] { 100, 100, 300, 300 };
break;
}
setLayout(null);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillPolygon(pieceX, pieceY, pieceX.length);
}
}
These classes above are the only classes interacting with my GUI, no other classes take part.
You are overcomplicating things by trying to add JPanel puzzle pieces to your JPanel puzzle board. Problems will rapidly become apparent with your non-rectangular puzzle pieces, like the TOP_LEFT shape, which has a cut-out from the lower right side of the piece. When it comes time to overlap the puzzle pieces, to fit the cut-away portions together, the piece added later will occlude pieces drawn earlier.
For instance, if you try to nest a TOP_LEFT piece (A) and a BOTTOM_RIGHT piece (B) together.
AAAAAA BBB
AAAAAA BBB
AAA BBBBBB
AAA BBBBBB
You will only see:
+---+------+
|AAA| BBB|
|AAA| BBB|
|AAA|BBBBBB|
|AAA|BBBBBB|
+---+------+
The overlapping area will be drawn by only one of the panels. The entire area of the B piece, including the blank space, will be drawn in the area of the second piece, on top of whatever the A piece hoped to display.
You might be able to get around this by setting the JPanel to be transparent, and not calling super.paintComponent() which paints the entire component the background colour. But then you still have to draw the shape on the JPanel, and position the JPanel properly on the parent JPanel.
Forget panels within panels! Just draw the pieces on the parent JPanel.
Example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Puzzle {
public static void main(String[] args) {
SwingUtilities.invokeLater(Puzzle::new);
}
private final static int shape_x[] = { -100, 100, 100, 0, 0, -100 };
private final static int shape_y[] = { -100, -100, 0, 0, 100, 100 };
public Puzzle() {
JFrame frame = new JFrame("Puzzle");
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
View view = new View();
frame.setContentPane(view);
Shape l_shape = new Polygon(shape_x, shape_y, shape_x.length);
view.pieces.add(new Piece(Color.YELLOW, l_shape, 0, 100, 100));
view.pieces.add(new Piece(Color.GREEN, l_shape, 180, 300, 300));
view.pieces.add(new Piece(Color.RED, l_shape, 65, 450, 145));
frame.setVisible(true);
}
}
#SuppressWarnings("serial")
class View extends JPanel {
final List<Piece> pieces = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gc = (Graphics2D) g;
for (Piece piece : pieces)
piece.draw(gc);
}
}
class Piece {
final Color color;
final Shape shape;
final int angle;
int x, y; // Move pieces by by changing these
Piece(Color color, Shape shape, int angle, int x, int y) {
this.color = color;
this.shape = shape;
this.angle = angle;
this.x = x;
this.y = y;
}
void draw(Graphics2D gc) {
AffineTransform tf = gc.getTransform();
gc.translate(x, y);
gc.rotate(Math.toRadians(angle));
gc.setColor(color);
gc.fill(shape);
gc.setTransform(tf);
}
}
Note that this is also a Minimal, Complete and Verifiable example. Minimal: No package statement; No extra HashSet and Set imports which aren't used; doesn't try to do anything except show 3 game pieces. It is complete: a single file you can compile, and run. It is verifiable: you can run it and see it shows 3 game pieces.
As a bonus, it shows Graphics2D.rotate() working, with one piece rotated 180°, and another rotated at an angle that is not appropriate for your puzzle but useful in demonstrating the that rotate works just fine.
Related
Im currently working on a 3-body-simulation (gravity) and I managed to calculate every new x and y value by randomly guessing dt (the time steps) and putting them into an iterative equation. I then saved each x and y value in an ArrayList after every iteration which covers the time dt that I put into a variable. Im very very new at Java and I'd appreciate every answer although I'd be more thankful for a, in consideration of my noobie knowledge, easier answer. (Im a 16y.o. non english speaker, I apologize for any mistakes)
I already imported ArrayList, List and LinkedList and an example of my x and y List would be
List<Double> xlistobject1 = new ArrayList<Double>();
List<Double> ylistobject1 = new ArrayList<Double>();
And in the while-loop-iteration-process:
xlistobject1.add(xobject1); // where xobject1 and yobject1 are the x and y
ylistobject1.add(yobject1); // coordinates
I've already researched the best ways to animate this but nothing worked for me. I really cant wrap my head around Canvas, JFrame and so on because they require so much prior knowledge to this topic. As the time-span would already be defined by the n-count of iterations*dt, I imagine that you can't just draw a dot on every position in the lists and press play because to create a relatively smooth animation, you'd have to take a timer into this to setup a fixed animation length like 30 seconds would imply that you rescale the time onto this fixed length and end up with an information loss of the exact coordinates as my monitor can only display 1920x1080 pixels?
What I've got already:
I've copied the only Frame that worked on my Eclipse-Installation (at the bottom of the text) and removed the moving-part that was there already in an attempt of moving to the value of x and y that was in the in the lists looped until my lists are clear. After that I would rescale the time of the simulation (n-counter * dt) so that it would fit into 20 seconds with 30 frames per second so that the simulation had 600 timesteps and so if I didnt get something wrong, you'd have to divide (n-counter *dt)/600 to get the x- and y-scaling factors. My main problem is the implementation of my idea into Java. I hope I didn't confuse you or talked total bs. Thanks for any help! :)
Here's my "animation"-code:
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;
import java.util.Vector;
import java.util.Stack;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
final public class Test
{
JFrame frame;
DrawPanel drawPanel;
private int oneX = 7;
private int oneY = 7;
public static void main(String... args)
{
new Test().go();
}
private void go()
{
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setResizable(false);
frame.setSize(1920, 1000);
frame.setLocationByPlatform(true);
frame.setVisible(true);
moveIt();
}
class DrawPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g)
{
g.setColor(Color.BLUE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.RED);
g.fillRect(3, 3, this.getWidth() - 6, this.getHeight() - 6);
g.setColor(Color.WHITE);
g.fillRect(6, 6, this.getWidth() - 12, this.getHeight() - 12);
g.setColor(Color.BLACK);
g.fillRect(oneX, oneY, 6, 6);
// Object 1
! for i = 0 to xlistobject1.count - 1
! //move circle to x=xlistobject1.item(i)
! //move circle to y=ylistobject1.item(i)
next
try
{
Thread.sleep(10);
}
catch (Exception e)
{
e.printStackTrace();
}
frame.repaint();
}
}
}
##########################################################
I've made changes:
-instead of a List of coordinates, I now have a List of Point2d that stores coordinates
Code for the animation part:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
final public class altanim {
JFrame frame;DrawPanel drawPanel; public static int ni=1; public static Boolean returnt=false; public static Double plus1x, plus2x, plus3x, plus1y, plus2y, plus3y;
public static Double zugriff1x=0.0, zugriff2x=0.0, zugriff3x=0.0, zugriff1y=0.0,zugriff2y=0.0, zugriff3y=0.0, nialtx3=0.0,nialtx2=0.0, nialtx1=0.0, nialty1=0.0, nialty2=0.0, nialty3=0.0;
public static void main(String... args) {
new altanim().go();
}
public void go() {
if (returnt==false) {
frame=new JFrame("3-Körper-Problem: Simulation:");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setResizable(true);frame.setSize(3000,1600);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setGlassPane(drawPanel);
frame.setLocationRelativeTo(null);
returnt=true;}
Timer timer = new Timer(10, new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
if (!(leololwjkr2.listepunkteobjekt1.size()==0) && ni<leololwjkr2.listepunkteobjekt1.size()-1) {
System.out.println(ni+2+"..."); zugriff1x=leololwjkr2.listepunkteobjekt1.get(ni).getX();
zugriff2x=leololwjkr2.listepunkteobjekt2.get(ni).getX();
zugriff3x=leololwjkr2.listepunkteobjekt3.get(ni).getX(); zugriff1y=leololwjkr2.listepunkteobjekt1.get(ni).getY();
zugriff2y=leololwjkr2.listepunkteobjekt2.get(ni).getY();
zugriff3y=leololwjkr2.listepunkteobjekt3.get(ni).getY();
ni++ ;
plus1x=zugriff1x;
plus2x=zugriff2x;
plus3x=zugriff3x;
plus1y=zugriff1y;
plus2y=zugriff2y;
plus3y=zugriff3y;
}
else {System.out.println("Fertig");
try {Thread.sleep(3000);} catch (Exception e4) {System.out.println(e);} drawPanel.repaint(); } } }); timer.start(); }
class DrawPanel extends JPanel { private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
System.out.println("nächstes...");
g.setColor(Color.BLUE); g.fillRect(0, 0, this.getWidth(), this.getHeight());g.setColor(Color.RED); g.fillRect(3, 3, this.getWidth() - 6, this.getHeight() - 6);g.setColor(Color.WHITE); g.fillRect(6, 6, this.getWidth() - 12, this.getHeight() - 12); // Rahmen
g.setColor(Color.BLUE);g.drawLine(zugriff1x.intValue(), zugriff1y.intValue(), plus1x.intValue(), plus1y.intValue());
g.setColor(Color.RED);g.drawLine(zugriff2x.intValue(), zugriff2y.intValue(), plus2x.intValue(), plus2y.intValue());
g.setColor(Color.GREEN);g.drawLine(zugriff3x.intValue(), zugriff3y.intValue(), plus3x.intValue(), plus3y.intValue()); }
}
}
###############
My problem is that the paintComponent at the bottom doesn't do anything and I can't think of a solution. Please take a look at it. :)
The important thing to understand is the paintComponent method just draws the component as it appears at that moment in time -- it is not a place to do animation.
I have made two minor changes to your code to give you this idea:
Removed the loop and the sleep from paintComponent.
Added a timer which modifies oneX and oneY and triggers a repaint of your DrawPanel.
You will want to do more complicated updating of x and y coordinates, and you'll want to draw more things in paintComponent, but I hope this will get you started.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
final public class SwingTest
{
JFrame frame;
DrawPanel drawPanel;
private int oneX = 7;
private int oneY = 7;
public static void main(String... args)
{
new SwingTest().go();
}
private void go()
{
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setResizable(false);
frame.setSize(1920, 1000);
frame.setLocationByPlatform(true);
frame.setVisible(true);
// added this timer, which updates every 100ms
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// move the box
oneX += 1;
oneY += 1;
drawPanel.repaint();
}
});
timer.start();
}
class DrawPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g)
{
g.setColor(Color.BLUE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.RED);
g.fillRect(3, 3, this.getWidth() - 6, this.getHeight() - 6);
g.setColor(Color.WHITE);
g.fillRect(6, 6, this.getWidth() - 12, this.getHeight() - 12);
g.setColor(Color.BLACK);
g.fillRect(oneX, oneY, 6, 6);
// removed your loop
}
}
}
Another tip to think about in the future: Create a class for each object you want to display, and have a list of instances of this class, instead of a separate list for each attribute of the object. That way there's just one insert operation when you create a new objects, and a single get from the list gives you all the attributes you need to draw or update it.
When using AffineTransform in Java, it gets applied to everything drawn onto the Graphics object. It affects for example the width of lines or flips around the text and makes it much larger.
This is an example:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class Test extends JFrame {
public Test() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
add(new DrawPanel());
pack();
}
private class DrawPanel extends JComponent {
public DrawPanel() {
setPreferredSize(new Dimension(1200, 600));
}
#Override
protected void paintComponent(Graphics g) {
AffineTransform scale = AffineTransform.getScaleInstance(1200 / 360.0, 600 / 180.0);
AffineTransform mirrorY = new AffineTransform(1, 0, 0, -1, 0, 600);
AffineTransform worldToPixel = new AffineTransform(mirrorY);
worldToPixel.concatenate(scale);
Graphics2D g2 = (Graphics2D) g;
g2.setTransform(worldToPixel);
g2.setColor(Color.RED);
g2.drawString("50x50", 50, 50);
g2.drawString("100x100", 100, 100);
}
}
public static void main(String[] args) {
Test test = new Test();
test.setVisible(true);
}
}
The translation of the coordinates works perfectly: On a 1200x600 pixel component, the above transformation puts 0,0 in the lower left corner and 360,180 in the upper right corner. But the text is mirrored and stretched, too. Also, lines get thicker because of the "scale" transformation.
Text flipped and stretched
Is there a way to prevent AffineTransform to get applied on text and line styles? So that it works only on coordinates and not on styles?
I am trying to add a border to a Rectangle element and for some reason it will not work, is it not compatible with JFrame? I can set my entire JFrame to having a border, but it can't find setBorder with my rectangles. Here is my code:
package trivia;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class Main extends JFrame{
boolean mainMenu = true;
static Color tan = Color.decode("#F4EBC3");
static Color darkGreen = Color.decode("#668284");
static Color buttonColor = Color.decode("#A2896B");
Rectangle header = new Rectangle(0, 0, 500, 100);
Rectangle body = new Rectangle(0, 100, 500, 400);
Rectangle start = new Rectangle(150, 150, 200, 40);
public Main() {
setTitle("Trivia Game!");
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
Dimension d = this.getSize();
Border blackline;
blackline = BorderFactory.createLineBorder(Color.black);
if(mainMenu = true){
g.setColor(darkGreen);
g.fillRect(header.x, header.y, header.width, header.height);
g.setFont(new Font("Courier", Font.BOLD, 24));
g.setColor(Color.BLACK);
drawCenteredString("Trivia Game!", d.width, 125, g);
g.setColor(tan);
g.fillRect(body.x, body.y, body.width, body.height);
g.setColor(buttonColor);
g.fillRect(start.x, start.y, start.width, start.height);
}
}
public void drawCenteredString(String s, int w, int h, Graphics g) {
FontMetrics fm = g.getFontMetrics();
int x = (w - fm.stringWidth(s)) / 2;
int y = (fm.getAscent() + (h- (fm.getAscent() + fm.getDescent())) / 2);
g.drawString(s, x, y);
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Main m = new Main();
}
}
And when I add this in my paint function:
start.setBorder(blackline);
It gives me the error:
The method setBorder(Border) is undefined for the type Rectangle
I am not sure how I can make it recognize the setBorder function, can anyone help? All help is much appreciated!
Rectangle does not have a setBorder method, instead, set the color of the Graphics context using Graphics#setColor(Color) and either use Graphics#drawRect(int, int, int, int) or Graphics2D#draw(Shape)
You're breaking the paint chain. Painting is made up of a series of chained method calls, which when called correctly, paint the current component and its child components. By not calling super.paint you're preventing from doing this and could cause any number of nasty side effects, none of which you really want...
You should avoid overriding paint of top level containers, like JFrame, for a number of reasons; they're not double buffered; there a bunch of other components sitting on top of the frame which may paint over it; etc. Instead, create a custom component, extending from something like JPanel and override it's paintComponent method instead (ensuring that you call super.paintComponent first)...
See Painting in AWT and Swing,
Performing Custom Painting and 2D Graphics for more details
Sounds like you're trying to draw the rectangle referenced by start. In that case, you want to be invoking a method on a Graphics, not on a Rectangle. So:
g.drawRect(start.x, start.y, start.width, start.height);
I am desperately trying to implement some things which I don't think I fully understand. I am attempting to set it up so the commented out actions can be taken (I will need to change syntax but I want to make sure I am on the right track first).
Am I going about this the right way? Where will my drawing actions go if not in the draw method? I get lots of errors when I move it there. Thanks
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics2D;
import java.awt.Graphics;
public class Test extends JPanel{
abstract class graphic {
public Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private int[] location = new int[] {screenSize.width/2,screenSize.height/2};
}
public class gladiator extends graphic {
void draw() {
//g2d.setColor(Color.green);
//g2d.fillArc(location[0], location[1], 100, 100, 45, 90);
//g2d.setColor(Color.black);
//g2d.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
new Timer(200, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// setLocation((location[0]+1),location[1]);
repaint();
System.out.println("repainting");
}
}).start();
}
public void setLocation(int x, int y){
//this.location[0] = x;
//this.location[1] = y;
}
public static void main(String[] args){
JFrame jf=new JFrame();
jf.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize());
jf.add(new Test());
jf.pack();
jf.setVisible(true);
}
}
My original code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test extends JPanel{
private int[] location = new int[2];
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillArc(location[0], location[1], 100, 100, 45, 90);
g.setColor(Color.black);
g.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);
new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setLocation((location[0]+50),50);
repaint();
System.out.println("repainting");
}
}).start();
}
public void setLocation(int x, int y){
this.location[0] = x;
this.location[1] = y;
}
public static void main(String[] args){
JFrame jf=new JFrame();
jf.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(new Dimension(300,500));
jf.setLocation(100,100);
jf.add(new Test());
jf.pack();
jf.setVisible(true);
}
}
Edit: Should have included this bit, first commenter was right.
The error is cannot find symbol, referring to g2d or g, whichever. I take it to mean that drawing can only happen inside of paint components and that I will have to find a way to include all the instructions for drawing there. I want to make sure I'm just doing something fundamentally wrong, though as this is my first brush with both abstract classes and 2d drawing in java. Also, I know the location[0] etc will not work as is. Lets ignore that.
The bottom code is what I am trying to accomplish (at least at first), but I am trying to use something similar to the top code to create multiple instances of it which can operate independently.
Move the timer out of paintcomponent.
You have declared an abstract class that has a draw method that needs a Graphics2D object to be able to draw, it has no access to it. It also makes little sense to declare a class just to hold two values (screensize and location) if that class also does stuff like drawing.
To fix the issues with 2, you can either let your gladiator extend JComponent, override its paintcomponent and place your draw() code in there and add gladiator to the panel as a component.
You can alternatively do active rendering, which means that you get the Graphic2D object of your canvas (the panel in this case) and take control of the rendering yourself instead of relying on swing.
Since you are working with swing I will give you a working example of what you probably intend to do. If you have more specific questions please do leave a comment.
public class Test extends JPanel {
public static abstract class graphic extends JComponent {
public Dimension dim = new Dimension(500, 500);
private int[] loc = new int[] { 250, 250 };
#Override
#Transient
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public int[] getLoc() {
return loc;
}
public Dimension getDim() {
return dim;
}
}
public static class gladiator extends graphic {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.green);
g2d.fillArc(getLoc()[0], getLoc()[1], 100, 100, 45, 90);
g2d.setColor(Color.black);
g2d.fillArc((getLoc()[0] + 50 - 10), (getLoc()[1] + 50 - 10), 20,
20, 0, 360);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
Test canvas = new Test();
gladiator gladiator = new gladiator();
canvas.add(gladiator);
frame.getContentPane().add(canvas);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
This renders
import javax.swing.*; // For JPanel, etc.
import java.awt.*; // For Graphics, etc.
import java.awt.geom.*; // For Ellipse2D, etc.
import java.awt.event.*;
public class ShapeExample extends JPanel {
private Rectangle2D.Double square =
new Rectangle2D.Double(50, 50, 100, 100);
private Rectangle2D.Double square1 =
new Rectangle2D.Double(10, 10, 200, 200);
private Ellipse2D.Double circle =
new Ellipse2D.Double(50, 50, 100, 100);
public void paintComponent(Graphics g) {
clear(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(Color.red);
//g2d.fill(square);
g2d.draw(square);
g2d.draw(square1);
g2d.fill(square1);
}
}
// super.paintComponent clears offscreen pixmap,
// since we're using double buffering by default.
protected void clear(Graphics g) {
super.paintComponent(g);
}
protected Rectangle2D.Double getsquare() {
return(square);
}
public static void main(String[] args) {
WindowUtilities.openInJFrame(new ShapeExample(), 100, 100);
}
}
Get rid of the WindowUtilites class and build your frame manually so you understand what is going on. Then you add a panel containing your sliders to the top/bottome of the frame. Add your painting panel to the center. Start by reading the Swing tutorial on How to Use Sliders for working examples of creating a basic GUI with sliders. You can then post your SSCCE if you have problems.