Here's the class in which I try to draw the lines
package gps;
import java.awt.*;
import java.awt.geom.Line2D;
import java.util.*;
import javax.swing.*;
public class RoadMap extends JPanel {
public void paintComponent(Graphics2D g)
{
super.paintComponent(g);
g.setColor(Color.blue);
for(int i = 0; i < Graph.getEdges().length; i++)
{
Shape s = new Line2D.Double(Graph.vMap.get(Graph.getEdges()[i].i1).x,
Graph.vMap.get(Graph.getEdges()[i].i1).y,
Graph.vMap.get(Graph.getEdges()[i].i2).x,
Graph.vMap.get(Graph.getEdges()[i].i2).y);
g.draw(s);
}
}
}
The Graph.vMap.get(Graph.getEdges()[i].i2).x and Graph.vMap.get(Graph.getEdges()[i].i2).y access the x and y values for the endpoints of the lines and I've tested it and it returned the correct values. However, nothing shows up in my JFrame with this. Trying to draw other lines with set values outside of the for loop actually worked.
x1 = 43.12929, x2 = 43.12976, y1 = -77.626956, y2 = -77.62679
These y values are outside the panel. AWT/Swing component visible coordinate space runs from (0, 0) to (width-1, height-1).
Check where you are computing the values. If you want (0, 0) to be the center, you need to do some arithmetic or a translation via e.g. Graphics2D#translate(int, int).
Furthermore:
public void paintComponent(Graphics2D g)
If you are trying to override paintComponent, you have not done so. paintComponent takes a Graphics, not a Graphics2D:
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Always use the #Override annotation when you attempt to override, because it will cause an error and tell you if it's not an override. See https://docs.oracle.com/javase/tutorial/java/IandI/override.html.
Possibly you mean to use something like this:
public class RoadMap extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(getWidth() / 2, getHeight() / 2);
g2.setColor(Color.blue);
for(int i = 0; i < Graph.getEdges().length; i++) {
Shape s = new Line2D.Double(
Graph.vMap.get(Graph.getEdges()[i].i1).x,
Graph.vMap.get(Graph.getEdges()[i].i1).y,
Graph.vMap.get(Graph.getEdges()[i].i2).x,
Graph.vMap.get(Graph.getEdges()[i].i2).y);
g2.draw(s);
}
g2.dispose();
}
}
Related
i am trying to do a roulette casino game, so for this i made my roulette using the Arc2D package.
My code below
package roulette;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Arc2D;
import java.awt.geom.AffineTransform;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class RouletteInterface extends JPanel{
public int spinValue = 0;
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
paintRoulette(g2d);
}
public void paintRoulette(Graphics2D g2d) {
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(hints);
AffineTransform at = AffineTransform.getTranslateInstance(10, 10);
at.rotate(spinValue, 10, 10);
double angle = 360 / 36.9;
double startAngle = 0;
int color = 0;
for(int i = 0; i < 37; i++) {
if(i == 0) {
g2d.setColor(Color.GREEN);
} else {
if(color == 0) {
g2d.setColor(Color.BLACK);
color = 1;
} else {
g2d.setColor(Color.RED);
color = 0;
}
}
g2d.fill(new Arc2D.Double(100, 100, 300, 300, startAngle, angle, Arc2D.PIE));
startAngle += angle;
}
g2d.transform(at);
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
spinValue += 0.01;
repaint();
}
});
timer.start();
}
}
In short i am not using a generalpath because i want to fill each arc with color red/green or black like the original roulette, and for the rotation i tried using a timer to increase the spinValue (this worked for me but when i use a generalpath) for the AfinneTransformation, but when i run the code, well, nothing happens. It shows me only the roulette without animation. What can i do?
Thanks in advance.
Painting and graphics in general are quite advanced topics, Java/Swing does a good job to "commonalise" the APIs into something which is reasonable easy to use, but still takes time and effort to learn and understand fully.
I would highly recommend having Performing Custom Painting, Painting in AWT and Swing and 2D Graphics and the JavaDocs booked marked, as you will be coming back to them on a regular bases (I still do)
There are lots of issues, which are compounding to make your life difficult.
Starting with...
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D)g;
paintRoulette(g2d);
}
You should favour overriding paintComponent instead of paint, paint is a complicated process and you need to choose your entry point into carefully. Also, you should always call the paint methods super method, unless you are absolutely, positively prepared to take over its core functionality yourself.
In your case, you should also be making a copy of the Graphics context before passing it to paintRoulette, as Graphics is a shared resource and the transformations you are applying will cause issues for anything which is painted after your component.
Transformations...
AffineTransform at = AffineTransform.getTranslateInstance(10, 10);
at.rotate(spinValue, 10, 10);
This is somewhat interesting. You're creating translation of 10x10 which will move the origin point of the Graphics context. You then apply a rotation, which is anchored to 10x10.
The reason I mention it is because you then do...
g2d.fill(new Arc2D.Double(100, 100, 300, 300, startAngle, angle, Arc2D.PIE));
This means that the arc is offset by 110x110 from the corner of the component (add in your translation) and you'll be rotating about a point 20x20 from the component's top/left corner (add in your translation) ... this is weird to me because the centre of the of wheel is actually at 250x250 (from the component's top/left corner) which is going to make for one very weird affect.
Finally, you apply the transformation AFTER the painting is done AND then create a Timer inside the paint method...
Painting is done in serial. So one operation will effect the next, this will mean you will need to apply the transformation BEFORE you paint something (that you want transformed)
You also need to understand that you don't control the paint process, this means that your component may be painted for any number of reason at any time without your interaction. This means you could an infinite number of Timers, over a very small period of time.
Instead, your timer should be controlled externally from the paint process.
One other thing that took me some time to work out is...
public int spinValue = 0;
//...
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
spinValue += 0.01;
repaint();
}
});
You declare spinValue as int, but are adding a floating point value to it, this will have the effect of the decimal component been truncated, so the value will ALWAYS be 0.
Also, AffineTransform#rotate expects angles to be in radians, not degrees. Not sure if it's important, but you should be aware of it.
Runnable example...
Okay, so after applying the above, the code "might" look something like...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new RoulettePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RoulettePane extends JPanel {
private double spinValue = 0;
private Timer timer;
public RoulettePane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
spin();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
paintRoulette(g2d);
g2d.dispose();
}
protected void spin() {
if (timer != null && timer.isRunning()) {
return;
}
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
spinValue += 0.01;
repaint();
}
});
timer.start();
}
protected void paintRoulette(Graphics2D g2d) {
RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(hints);
int width = getWidth();
int height = getHeight();
int dimeter = Math.min(width, height);
AffineTransform at = AffineTransform.getRotateInstance(spinValue, dimeter / 2, dimeter / 2);
g2d.transform(at);
double angle = 360 / 36.9;
double startAngle = 0;
int color = 0;
for (int i = 0; i < 37; i++) {
if (i == 0) {
g2d.setColor(Color.GREEN);
} else {
if (color == 0) {
g2d.setColor(Color.BLACK);
color = 1;
} else {
g2d.setColor(Color.RED);
color = 0;
}
}
g2d.fill(new Arc2D.Double(0, 0, dimeter, dimeter, startAngle, angle, Arc2D.PIE));
startAngle += angle;
}
}
}
}
nb: I took the translation out for the time been as I wanted to focus on making the output more dynamic based on the actual width/height of the component
Like in a topic, I've readed the most of all solutions for repaint() but for my code their are not working. I'm a begginer so forgive me a mess in my code..
class View.java
public class View extends JFrame{
public void make(){
setSize(640,480);
setVisible(true);
setTitle("Parking");
}
double x_ = MyFrame.x;
double y_ = MyFrame.y;
double odchylenie_ = MyFrame.odchylenie;
int szerokosc = 50;
int wysokosc = 30;
public void paint(Graphics g){
Rectangle2D rect = new Rectangle2D.Double(-szerokosc / 2., -wysokosc / 2., szerokosc, wysokosc);
AffineTransform transform = new AffineTransform();
transform.translate(x_, y_);
transform.rotate(Math.toRadians(odchylenie_));
Shape rotatedRect = transform.createTransformedShape(rect);
Graphics2D g2 = (Graphics2D)g;
g2.draw(rotatedRect);
}
All I want to do to re-paint this rotatedRect with new values of x,y and odchylenie (sorry for polish variable names).
I'm calculating new variable values and using Jbutton to redraw it.
Here is my MyFrame.class
public class MyFrame extends javax.swing.JFrame {
static double x,y,odchylenie,kat;
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
View v = new View();
v.make();
Fuzzy f = new Fuzzy();
kat = f.wyjscie(x, odchylenie);
jLabel5.setText("Kąt: " + Double.toString(kat));
odchylenie = Fuzzy.wyliczOdchylenie(odchylenie,kat);
jLabel8.setText("Nowe odchylenie: " + Double.toString(odchylenie));
x = Fuzzy.wyliczX(x, 10, kat,odchylenie);
jLabel6.setText("Nowy x: " + Double.toString(x));
y = Fuzzy.wyliczY(y,x, 10, kat,odchylenie);
jLabel7.setText("Nowy y: " + Double.toString(y));
v.repaint(); //Not works
}
Instead of doing repaint(), the new window appears, and old one stays...
I have tried to declare View v outside the button function body, but it not worked too(nothing is painting).
Whenever you override one of the paint() methods, you need to make a call to the super's method:
public void paint(Graphics g) {
super.paint(g);
// your code goes here
}
Further, you should really be using paintComponent(), not paint().
public void paintComponent(Graphics g) {
super.paintComponent(g);
// your code goes here
}
Instead of using paint, use paintComponent:
public void paintComponent(Graphics g){
super.paintComponent(g);
Rectangle2D rect = new Rectangle2D.Double(-szerokosc / 2., -wysokosc / 2., szerokosc, wysokosc);
AffineTransform transform = new AffineTransform();
transform.translate(x_, y_);
transform.rotate(Math.toRadians(odchylenie_));
Shape rotatedRect = transform.createTransformedShape(rect);
Graphics2D g2 = (Graphics2D)g;
g2.draw(rotatedRect);
}
I have a simple applet that animates a rectangle along the x-axis of the canvas. The problem is that it flickers. I have tried to Google this problem, but I didn't come up with anything useful or anything that I understood.
I am relatively new to Java.
Thanks!
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class simpleAnimation extends JApplet implements ActionListener {
Timer tm = new Timer(10, this);
int x = 0, velX = 2;
public void actionPerformed(ActionEvent event) {
if (x < 0 || x > 550){
velX = -velX;
}
x = x + velX;
repaint();
}
public void paint ( Graphics g ) {
super.paint(g);
g.setColor(Color.RED);
g.fillRect(x, 30, 50, 30);
tm.start();
}
}
**********UPDATED CODE WITHOUT FLICKER**********
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class simpleAnimation extends JApplet implements ActionListener
{
Graphics bufferGraphics;
Image offscreen;
Dimension dim;
int x = 3, velX = 2;
Timer tm = new Timer(10, this);
public void init()
{
dim = getSize();
offscreen = createImage(dim.width,dim.height);
bufferGraphics = offscreen.getGraphics();
}
public void paint(Graphics g)
{
bufferGraphics.clearRect(0,0,dim.width,dim.width);
bufferGraphics.setColor(Color.red);
bufferGraphics.fillRect(x,50,50,20);
g.drawImage(offscreen,0,0,this);
tm.start();
}
public void update(Graphics g)
{
paint(g);
}
public void actionPerformed(ActionEvent evt)
{
if ( x < 0 || x > 550){
velX = -velX;
}
x = x + velX;
repaint();
}
}
I used this applet as a template.
I always struggle with this concept of double buffering.
Here is my example that overrides paint() of the JApplet and a paintComponent() of a JPanel, which uses double buffering by default.
I don't see any difference in the apparent flickering.
//<applet code="SimpleAnimation.class" width="600" height="300"></applet>
import java.awt.*;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class SimpleAnimation extends JApplet implements ActionListener {
Timer tm = new Timer(10, this);
int x = 0, velX = 2;
JPanel panel;
public void init()
{
panel = new JPanel()
{
#Override
public Dimension getPreferredSize()
{
return new Dimension(50, 100);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x, 30, 50, 30);
}
};
add(panel, BorderLayout.SOUTH);
tm.start();
}
public void actionPerformed(ActionEvent event) {
if (x < 0 || x > 550){
velX = -velX;
}
x = x + velX;
repaint();
// panel.repaint();
}
public void paint ( Graphics g ) {
super.paint(g);
g.setColor(Color.RED);
g.fillRect(x, 30, 50, 30);
}
}
I test the code using: appletviewer SimpleAnimation.java
Is my concept of double buffering flawed, or my implementation, or both?
The problem is, top level containers like JApplet aren't double buffered. This means that when it's updated, the screen flickers as each action is done directly onto the screen.
Instead, you should create a custom component, using something like a JPanel, and override its paintComponent method and perform your custom painting actions there.
Because Swing components are double buffered the results of the paint action are buffered before they are painted to the screen, making it a single action
Take a look at Performing Custom Painting for more details
What you're doing now works like this:
public void paint ( Graphics g ) {
// draw the entire area white
super.paint(g);
g.setColor(Color.RED);
// draw a rectangle at the new position
g.fillRect(x, 30, 50, 30);
}
So with every step, you first wipe out your rectangle, and then draw it fresh. Thus the flickering - the pixels under the rectangle keep changing from white to red to white to red to white to red...
Now observe that the smallest amount of painting you need to do is (supposing rectangle moves to the right) this:
draw velx pixels on the left WHITE
draw velx pixes on the right RED
If you do that, your animation will be smooth.
Computing that can be quite challenging though, especially when your shape is more complicated than just a square / your movement is more complex. That's where double buffering comes in.
With double buffering, you create an in-memory image that is the same size as your screen. You paint your entire theme there. Then you paint that image on your screen all at once.
When doing that, there won't be an intermediate step of "entire screen is WHITE"; thus no flickering. But note that you end up re-painting the entire screen rather than just the area that changed, which isn't ideal. Consider using clipping - a technique where you repaint a pre-defined area of the image and not the entire thing.
I am having some trouble while using swing to draw a diamond inside a square.
My code is this,please some one have a look at it and let me know if you can provide a fullfunctional code which is working in creating a diamond inside a square.
The code is:-
import javax.swing.*;
import java.awt.*;
public class MyDrawing extends JPanel
{
static int width=250;
static int height=250;
static int x=0;
static int y=0;
private void doDrawing(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
//for (int i = 0; i <= 1000; i++)
g2d.drawRect(x, y, width,height);
g2d.rotate(Math.toRadians(-45));
System.out.println(Math.toRadians(-45));
x=0;
y=height/2;
System.out.println(y);
width=(int)Math.pow(Math.pow((width/2),2)*2,0.5);
height=width;
System.out.println("width:"+width+"height:"+height);
g2d.drawRect(y, x, width,height);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
To keep the the diamond inside the sqaure, simply
1. Draw a rectangle
2. Rotate the rectangle about its center.
Rectangle2D rectangle = new Rectangle2D.Double(20, 20, 50, 50);
g2.draw(rectangle);
AffineTransform transform = new AffineTransform();
transform.rotate(Math.PI/4, rectangle.getX() + rectangle.width/2, rectangle.getY() + rectangle.height/2);
g2.draw(transform);
I want to use graphics2D but I can't get I get it to display my graphics. Is there a better way to go about this that would allow me to use repaint()? Eventually I want to make have a image set as a background and be able to draw on it then save the contents of the frame as a image.
import java.awt.image.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.swing.JApplet;
import java.awt.*;
// assume that the drawing area is 150 by 150
public class test extends JApplet
{
final int radius = 25;
int width = 200, height = 200;
BufferedImage img = new BufferedImage(
width, height, BufferedImage.TYPE_INT_ARGB);
public void paint ( )
{
Graphics2D g = img.createGraphics();
g.setColor( Color.orange );
g.fillRect( 0, 0, 150, 150 );
g.setColor( Color.black );
g.drawOval( (150/2 - radius), (150/2 - radius), radius*2, radius*2 );
}
}
Ok so,
You have public void paint( ) what the hell is this doing lol? You need a graphics object. public void paint(Graphics g) is like the default method which gets called automatically when your applet is initialised.
You have Graphics2D g = img.createGraphics(); when you need to use your default Graphics g object and cast it into a Graphics2D object like so Graphics2D g2d = (Graphics2D) g;
You should search for a little more information on double buffering too :)
anyway... This code works so take from it what you want :)
P.S Note how I implemented Runnable; You do not need to do this if you only want to use the Graphics2D code. It is just making the class a thread and is used for game frame rates :)
Hope this helped.
import java.applet.*;
import java.awt.*;
public class Test extends Applet implements Runnable{
public boolean isRunning = false;
public int radius = 25;
public void start() {
isRunning = true;
new Thread(this).start();
}
public void stop() {
isRunning = false;
}
public void paint(Graphics g) {
//Create Graphics2D object, cast g as a Graphics2D
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.ORANGE);
g2d.fillRect(0, 0, 150, 150);
g2d.setColor(Color.BLACK);
g2d.drawOval((150/2 - radius), (150/2 - radius), radius * 2, radius * 2);
}
public void run() {
while (isRunning) {
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}