I just came across example - tutorial in book which I don't quite understand.
So here is the code
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.util.GregorianCalendar;
import javax.swing.JApplet;
public class Watch extends JApplet {
private final Color butterscotch = new Color(255, 204, 102);
Rectangle2D.Float background;
// Whats is purpose of following line, here on this place? Applet works well even without it?
Graphics2D screen2D;
#Override
public void init() {
setBackground(Color.black);
}
#Override
public void paint(Graphics screen) {
super.paint(screen);
Graphics2D screen2D = (Graphics2D) screen;
Font type = new Font("Monospaced", Font.BOLD, 20);
screen2D.setFont(type);
screen2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (background == null) {
// set up the background rectangle
// Whats is purpose of following line? Applet works well even without parameters?
background = new Rectangle2D.Float(0F, 0F, getSize().width, getSize().height);
// But if previous line is omit then background color is not set - why?
// background = new Rectangle2D.Float(0F, 0F, 0F, 0F);
// background = new Rectangle2D.Float();
}
screen2D.fill(background);
GregorianCalendar day = new GregorianCalendar();
String time = day.getTime().toString();
screen2D.setColor(butterscotch);
screen2D.drawString(time, 5, 25);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// do nothing
}
repaint();
}
}
My questions are:
What is purpose of this declaration (line 16) here on this place in code:
Graphics2D screen2D;
code works even without it? To be more precise Graphics2D object is of course declared later with same object name (screen2D) later on in paint() (line 26).
What is purpose of
getSize().width, getSize().height in this line (33):
background = new Rectangle2D.Float(0F, 0F, getSize().width, getSize().height);
I mean, how can it even get size of newly created object when size is not defined (prior to) that object creation? OK, I recon that since Eclipse gives initial value of 200 x 200 this might makes sense, so that getSize().width, getSize().height gets those values? Am I right about that one?
Moreover any of following (substitution) lines of code works well, instead of that one:
background = new Rectangle2D.Float(0F, 0F, 0F, 0F);
or
background = new Rectangle2D.Float();
BUT, here comes another question
If background = new Rectangle2D.Float(0F, 0F, getSize().width, getSize().height);
is substituted with
background = new Rectangle2D.Float(0F, 0F, 0F, 0F);
or
background = new Rectangle2D.Float();
Then background color is NOT black as defined in init() line 20
setBackground(Color.black);
but it is some shade of gray. Why? What do I miss here?
One more note: I am using Eclipse IDE Kepler if it matters in this case anyhow (I know that default applet size is 200 x 200, which could be modified in Run configuration -> parameters )
In this example there are two objects called screen2D. The first which is declared on line 16 is a member variable that is package private (can be accessed by all classes in the given package). As you have pointed out this variable doesn't seem to be used at all.
The second screen2D is a local variable declared on line 26 and used only in the paint function.
Likely this is a typo and only one of these variables is needed for the example.
the function getSize() is inherited from the superclass JApplet so getSize.width() is getting the applets width not the width of a newly created object.
So when you change the background to have dimensions of 0 then set its color you are setting the color of an object that doesn't have any size. Since this object doesn't have any size it doesn't matter what color you set it to since you wont actually be seeing it.
Related
I'm in a beginner's class that is teaching java and in our reading they gave an example about using graphics to draw items. So, I posted the code into my IDE and tried it out.
The code they posted was supposed to create an alien face and
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
/*
A component that draws an alien face
*/
public class FaceComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
// Draw the head
Ellipse2D.Double head = new Ellipse2D.Double(5, 10, 100, 150);
g2.draw(head);
// Draw the eyes
g2.setColor(Color.GREEN);
Rectangle eye = new Rectangle(25, 70, 15, 15);
g2.fill(eye);
eye.translate(50, 0);
g2.fill(eye);
// Draw the mouth
Line2D.Double mouth = new Line2D.Double(30, 110, 80, 110);
g2.setColor(Color.RED);
g2.draw(mouth);
// Draw the greeting
g2.setColor(Color.BLUE);
g2.drawString("Hello, World!", 5, 175);
}
}
However I am unsure how it is you create the Graphics to which you call the function. I had assumed that you would use
Graphics g = new Graphics();
Like how you call a new class, but this turned out to be an error. I tried looking into the documentation but it seems to gloss over what you use for 'g'.
Please help me understand.
Or is this a situation where this is a class I need to call from another class since I'm extending it?
paintComponent(Graphics g) is a method inherited from JComponent (Note that paintComponent should have #Override anotation), it is part of the draw system of the GUI. It's invoked from Java Swing Framework to ask for a Component to draw itself on the screen. The object past to the method is already instantiated and valid for usage.
You have to add your component to the screen with like JFrame/JPanel and make it visible to see it working.
Also that since you don't implement a measurable screen you need to add some space to it inside layout to see the result (setMinimumSize() after instiating, before frame.pack()).
Don't create a Graphics g with a new operator. It is passed in through the public void paintComponent(Graphics g) method.
Note that Java actually passes a Graphics2D object though this interface (which makes the cast possible) but for legacy reasons kept the Graphics interface by making the Graphics2D object inherit from Graphics.
The reason you don't create a new Graphics object is because the passed Graphics object is the one that is used by the rest of your widgets, and the AWT/Swing interface in general.
As far as "using" it, it is a standard Java object. Use it like a Java object, by calling methods on it.
g.setColor(...);
ect.
I am having trouble with creating a stroked shape in BasicStroke Outline = new BasicStroke(10f, 50, 50);. The error I am currently getting is error:
can't find symbol canvas.setStroke(Outline) pointing to the dot.
I am new to constructors so any help would be great and the only thing I did similar to this was creating an instance of Scanner.
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Color; //sets color
import java.awt.BasicStroke;
import java.awt.Graphics2D;
public class ColoredOlypmicRings extends JFrame
{
//varriables go here
public void paint(Graphics canvas)
{
super.paint (canvas);
canvas.setColor(Color.green);
canvas.drawOval(100,100,100,100); //color green
canvas.setColor(Color.red);
canvas.drawOval(200,200,100,100); //color red
final BasicStroke Outline = new BasicStroke(10f, 50, 50);
canvas.setStroke(Outline);
canvas.drawOval(300,300,200,200);
}
public ColoredOlypmicRings()
{
setSize(600,400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
ColoredOlypmicRings guiWindow = new ColoredOlypmicRings();
guiWindow.setVisible(true);
}
}
The Graphics class can't handle Strokes and doesn't have methods for setting it as its API will tell you.
The Graphics2D class on the other hand can handle this class and should be used to handle it. So cast your Graphics object to a Graphics2D object.
e.g.,
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(....); // do it here after casting
}
Also check out the BasicStroke API as you're not using the constructor correctly, passing in incorrect parameters.
Other issues:
Don't draw directly in a JFrame or other top-level window.
Instead draw in the paintComnponent method of a JPanel that is displayed in the JFrame.
The three int BasicStroke constructor is being mis-used as the 2nd and 3rd parameters should be constants that represent the cap and join state of the Stroke object.
This code repaints a random oval, rectangle, and line with different colors on the screen. The problem is that I'm trying to change the background color each time it repaints, but the backgrounds doesn't repaint. Please help.
package events;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class Paint extends JPanel {
static Paint g;
boolean change = true;
int x = 0;
int y = 0;
public void paintComponent(Graphics g) {
g.fillOval(x, y, 50, 50);
}
void circles() {
Color color = new Color(0, 0, 0);
repaint();
}
}
Get rid of the static Paint variable. Your class doesn't need any static variables.
how would i change the background then?
The painting method should NOT change the properties of the class. It should only paint the component based on the current properties.
So you need to do something like:
Create a method like setRandomBackground(). This method will create a Color object that you can use in the paintComponent() method. At the end of this method you should invoke repaint(), which will tell Swing to paint the component.
Get rid of new Paint()
get rid of Thread.sleep() // never tell a painting method to sleep.
get rid of repaint() // never tell a painting method to repaint itself, this will create an infinite loop.
Finally, read the Swing tutorial on Custom Painting for more information and working examples to learn the basics.
Also, variable names (R, G, B) should NOT be upper cased.
I've just finished a 2D vector/transformation library that I want to use on a simple example. I have a main loop that runs efficiently and update/render methods. I've always tried to understand what people are talking about when they use Java2D or jPanels or jFrames, but none of it makes sense to me.
I've made some 2D examples before, but it is using a jFrame with a Threaded canvas that I made when following a youtube tutorial. Its problem is that it is basically an integer array that allows for individual pixel setting and you can only use integers as positions, not floats like my library uses.
so my question is: how would I go about making a simple opening/closing window, that I can draw a sprite (should sprites just be some sort of slickUtil loaded thing, or will I have to load in individual pixels as I did before?) to, and that accepts float values for Cartesian coordinates with the origin at the centre.
Derive a class from JComponent and override the paintComponent method. It gets passed a Graphics object that can be cast into a Graphics2D object. The latter one has support for changing the coordinate system.
For drawing sprites: Loading individual pixels in a loop is very slow. There is a drawImage method in Graphics2D that supports everything you need for blitting sprites.
Here's an example to setup the Graphics2D object with a centered origin in a self-contained example:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Draw2D extends JFrame {
public Draw2D() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new DrawPane(), BorderLayout.CENTER);
pack();
}
public static void main(String[] args) {
Draw2D drawing = new Draw2D();
drawing.setVisible(true);
}
}
class DrawPane extends JComponent {
public DrawPane() {
setPreferredSize(new Dimension(640, 640));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// use anti-aliasing for smooth lines
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// move origin to center
g2.translate(getWidth() / 2, getHeight() / 2);
// scale as you need. Using negative y so that y points upward
// note that non-square window sizes will cause a different aspect ratio,
// you probably want to use Math.min(width, height) or something
g2.scale(getWidth() / 2, -getHeight() / 2);
// set color and thickness
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(0.001f));
// draw coordinate lines
g2.draw(new Line2D.Float(-1f, 0f, 1.0f, 0f));
g2.draw(new Line2D.Float(0, -1.0f, 0.0f, 1.0f));
// draw a vector
g2.draw(new Line2D.Float(0f, 0f, 0.25f, 0.25f));
}
}
Edit:
I submitted a bug for the below (it may take a a few days to become approved though):
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7043319
Some more details:
It works with Windows Sun JDK 1.6 versions 13 and 17
It fails on Ubuntu 11.04 x64 with both OpenJDK 1.6.0_22 and Sun JDK 1.6.0_24
What I want is to make a background image panel with additional panels on top of it (with additional components - e.g. JButtons, custom shapes, etc. - in them) and draw all that correctly. I'm using JLayeredPane for that purpose in my app, but for the sake of an example the below code should suffice. I'm open to suggestions about how to do what I want regardless of the below problem.
I'm running into the issue that the painting is behaving really weird. It doesn't repaint fully (e.g. only the top part above the image), it repaints in - from what I've noticed increasingly spaced - steps (e.g. 1st paint, 3rd paint, 9th paint, 21st paint, 64th paint, etc.). My guess is that I'm going too much into implementation here - is there anything obviously wrong with the below?
On a separate note, there are three commented lines below. Interestingly enough, uncommenting any of them and commenting the following line solves the problem. The images are with the following attributes (and it seems it doesn't matter which image - just the size):
cat.jpg JPEG 640x533 640x533+0+0 8-bit DirectClass 110KB 0.000u 0:00.000
cat-small.jpg JPEG 200x167 200x167+0+0 8-bit DirectClass 7.99KB 0.000u 0:00.000
Here's the Java code I'm having issues with:
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class SwingDrawingPrb {
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
final JFrame frame = new JFrame("SwingDrawingPrb");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Container contentPane = frame.getContentPane();
frame.setLocation(550, 50);
frame.setSize(1000, 800);
frame.setVisible(true);
// ImageIcon image = new ImageIcon(SwingDrawingPrb.class.getResource("/cat-small.jpg"));
ImageIcon image = new ImageIcon(SwingDrawingPrb.class.getResource("/cat.jpg"));
final JPanel imagePanel = new JPanel() {
// Color trans = new Color(255, 0, 0, 255);
Color trans = new Color(255, 0, 0, 64);
protected void paintComponent(Graphics g) {
System.out.println("painting");
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(trans);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.blue);
g.drawLine(0, 0, 1000, 1000);
}
};
imagePanel.setBounds(0, 0, image.getIconWidth() + 200, image.getIconHeight() + 200);
imagePanel.setLayout(null);
// JLabel imageLabel = new JLabel("Hello, world!");
JLabel imageLabel = new JLabel(image);
imageLabel.setBounds(100, 100, image.getIconWidth(), image.getIconHeight());
imageLabel.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
System.out.println("mouseMoved");
imagePanel.repaint();
}
});
imagePanel.add(imageLabel);
contentPane.add(imagePanel);
}
}
You need to add:
imagePanel.setOpaque(false);
See Backgrounds With Transparency for more information.