creating a stroked shape - java

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.

Related

Java: Program doesn't save old graphics

So, I have been doing Java for a couple of months, and I'm now learing about Graphics. So, I am trying to make a paint kind of thing, where I can just draw with my mouse. Nothing really fancy, just something to get me started. The program just paints a small dot whenever I drag the mouse. It sort of works, except for the fact that it doesn't save my old dots. It just creates a new one! It would be kind if someone could help me with this problem:
Main class:
import javax.swing.JFrame;
public class Test{
public static void main(String args[]){
Ploofer ploof = new Ploofer();
PumpkinPie f = new PumpkinPie(ploof);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1000,1000);
f.setResizable(false);
ploof.setSize(1000,1000);
f.add(ploof);
f.setVisible(true);
}
}
"Ploofer" class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Ploofer extends JPanel{
PumpkinPie pObj = new PumpkinPie(this);
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
this.setBackground(Color.WHITE);
g2d.setColor(new Color(190, 50, 0));
if(pObj.draw==true){
g2d.fillRect(pObj.x, pObj.y, 2, 2);
pObj.draw = false;
}
}
#Override
public void update(Graphics g){
paint(g);
}
//I tried to override update, but it didn't really help
}
"PumpkinPie" class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Ploofer extends JPanel{
PumpkinPie pObj = new PumpkinPie(this);
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
this.setBackground(Color.WHITE);
g2d.setColor(new Color(190, 50, 0));
/* g2d.fillRect(475, 475, 50, 50);
g2d.drawString("^Red^", 484, 540); */
if(pObj.draw==true){
g2d.fillRect(pObj.x, pObj.y, 2, 2);
pObj.draw = false;
}
}
#Override
public void update(Graphics g){
paint(g);
}
//I tried to override update, but it didn't really help
}
It sort of works, except for the fact that it doesn't save my old dots. It just creates a new one!
Check out Custom Painting Approaches for the two common ways to do custom painting:
add objects to paint to an ArrayList and iterate through the list to paint all objects
draw to a BufferedImage and repaint the BufferedImage
In your case I would recommend approach 2.
//I tried to override update, but it didn't really help
Don't override update(). There is no reason to do that. That is an old AWT approach with is not needed in Swing.

What is wrong with my applet code?

I am following a tutorial on applets on Youtube. My code looks exactly the same as the tutorial's does, but the background does not turn pink and Eclipse tells me there are errors in implements MouseListener and g2.draw(line); What did I do wrong? Click here for the video and here is my code:
package applets1;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.JApplet;
public class clean extends JApplet implements MouseListener{
public void start(){
}
public void init(){
setBackground(Color.pink);
addMouseListener(this);
}
public void paint(Graphics g){
Graphics g2D = (Graphics2D) g;
g.drawString("WAZZUP", 100, 90);
g.drawRect(100, 100, 400, 400);
Point2D.Double topLeft = new Point2D.Double(0.0, 25.0);
Point2D.Double topRight = new Point2D.Double(100.0, 25.0);
Line2D.Double line = new Line2D.Double(topLeft, topRight);
g2D.draw(line);
}
}
EDIT: The error at g2D.draw(line); says The method draw(Line2D.Double) is undefined for the type Graphics. I changed g2D.drawLine to g2D.draw
I also fixed the implements typo. The background is still not pink, despite the absence of an error and everything else works. What can I do to fix the pinkness and g2D.draw?
You have a typographical error. implements not implemets:
public class clean extends JApplet implements MouseListener{
Also you have declared g2D with the wrong type (Graphics vs Graphics2D). In other words, instead of
Graphics g2D = (Graphics2D) g; you need to use
Graphics2D g2D = (Graphics2D) g;
Once you make the above change, you will be able to invoke the g2D.draw() methods using the various 2D classes as parameters.
Also you have overridden the paint() method but you have not included a call to super.paint() - this should be the first line in your paint() method. Once you do this the background color should be rendered correctly (because it is handled by the base class, JApplet)

Java: "non-static method drawRect" error

I am really new in Java. Thought I had figure some stuff out by now, but I have a problem that proves otherwise!
Ok! Here it is. I have this code (Edited - Not original):
import java.util.*;
import java.awt.*;
public class MyClass extends HisClass
{
public void drawRectangle(int width, int height)
{
int x1 = this.getXPos();
int y1 = this.getYPos();
java.awt.Graphics.drawRect(x1, y1, width, height);
}
public static void main(String[] args)
{
AnotherClass theOther = new AnotherClass();
MyClass mine = new MyClass(theOther);
mine.move();
}
}
The error it gives me is this:
MyClass.java:66: error: non-static method drawRect(int,int,int,int) cannot be referenced from a static context
Can you please provide me with a solution?
It would be very appreciated. Thanks.
java.awt.Graphics.drawRect(x1, y1, width, height);
drawRect method is not static.. You should get an instance of your Graphics class somehow to use it: -
(graphicsInstance).drawRect(x1, y1, width, height);
Since Graphics class is abstract, so you need to find appropriate way to instantiate your Graphics object, to get graphicsInstance
You can use GraphicsContext to draw whatever you want to.. GraphicsContext is an object belonging to Graphics class which you can use to drawRect()
See these post. Might be useful: -
How do I initialize a Graphics object in Java?
what is a graphics context (In Java)?
Here is some example code that draws a Rectangle using drawRect() onto the JPanel by overriding its paintComponent(Graphics g) method and adding it to the JFrame:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawRect extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//draw our rect
g.setColor(Color.blue);
g.drawRect(10, 10, 100, 50);
}
//or else we wont see the JPanel
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("DrawRect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawRect());
frame.pack();
frame.setVisible(true);
}
}

java JFrame scaled UI display with virtual drawing space

i have an application that has graphics which are thought to be displayed at 1024x768.
I want to make the application flexible in size without rewriting all drawing code, position calculation etc..
To achieve that my attempt was overriding the paint method of the JFrame container in the following way:
#Override
public void paint(Graphics g)
{
BufferedImage img = new BufferedImage(this.desiredWidth, this.desiredHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D gi = (Graphics2D) img.getGraphics();
gi.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
gi.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
gi.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
super.paint(gi);
gi.dispose();
((Graphics2D) g).drawImage(img, screenScale, null);
}
while screenScale is an AffineTransform Object i created in the constructor which does the appropriate scaling according to the target size.
The problem now is: My child components get drawn and scaled, but with the limitations of the parent JFrame. So if my parent frame has the dimension 640x480 the child layers that i have added to it can only draw inside a 640x480 fraction of the 1024x768 BufferedImage that it is painting on.
I guess in some place the child components use getPreferredSize of the JFrame parent, because the child always has this values as bounds. So in the end my scaling strategy is in conflict with the painting behavior of the childs, because they fully ignore the bounds of the graphics object they get delivered for drawing on.
In the end, what ever i do, my child layers (derived from jpanel if that matters) get cut off when the target size is smaller than my "virtual" screen size.
Can anyone provide a better solution or hints how i can circumvent the strange behavior that the graphics bounds are ignored?
Edit: updated outcome of above code with unscaled output, expectet output and resulting output
expected output
resulted output
update: working test code
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.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.print.attribute.standard.OrientationRequested;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class AffineTransformTest
{
private static TransformingFrame canvas;
private static JButton button;
private static TestLayer layer;
public static void main(String[] args)
{
canvas = new TransformingFrame();
canvas.addMouseWheelListener(new ScaleHandler());
layer=new TestLayer(canvas.originalSize);
canvas.getContentPane().add(layer);
layer.setVisible(true);
button = new JButton("asdf");
canvas.setUndecorated(true);
button.setVisible(true);
canvas.getContentPane().add(button);
canvas.pack();
canvas.setLayout(new BorderLayout());
canvas.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
canvas.setPreferredSize(canvas.originalSize);
canvas.setSize(canvas.originalSize);
canvas.setLayout(null);
canvas.setVisible(true);
canvas.validate();
}
#SuppressWarnings("serial")
private static class TransformingFrame extends JFrame
{
private double scale;
private final Dimension originalSize;
private AffineTransform tx = new AffineTransform();
TransformingFrame()
{
originalSize=new Dimension(800,600);
scale = 1;
}
#Override
public void paint(Graphics g)
{
BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
Graphics bufferGraphics=offscreenBuffer.getGraphics();
super.paint(bufferGraphics);
bufferGraphics.dispose();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}
#Override
public void paintComponents(Graphics g)
{
BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
Graphics bufferGraphics=offscreenBuffer.getGraphics();
super.paintComponents(bufferGraphics);
bufferGraphics.dispose();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}
#Override
public void paintAll(Graphics g)
{
BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
Graphics bufferGraphics=offscreenBuffer.getGraphics();
super.paintAll(bufferGraphics);
bufferGraphics.dispose();
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}
}
#SuppressWarnings("serial")
private static class TestLayer extends JPanel{
public TestLayer(Dimension originalSize)
{
this.setPreferredSize(originalSize);
this.setSize(originalSize);
setOpaque(false);
setDoubleBuffered(false);
}
#Override
public void paint(Graphics g)
{
Graphics2D ourGraphics = (Graphics2D) g;
super.paint(ourGraphics);
ourGraphics.setColor(Color.green);
ourGraphics.fillRect(0, 0, getWidth(), getHeight());
ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
ourGraphics.setColor(Color.BLACK);
ourGraphics.drawRect(50, 50, 50, 50);
ourGraphics.fillOval(100, 100, 100, 100);
ourGraphics.drawString("Test Affine Transform", 50, 30);
ourGraphics.drawString(canvas.tx.toString(), 50, 250);
}
}
private static class ScaleHandler implements MouseWheelListener
{
public void mouseWheelMoved(MouseWheelEvent e)
{
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL)
{
// make it a reasonable amount of zoom
// .1 gives a nice slow transition
canvas.scale += (.1 * e.getWheelRotation());
// don't cross negative threshold.
// also, setting scale to 0 has bad effects
canvas.scale = Math.max(0.00001, canvas.scale);
canvas.tx.setTransform(new AffineTransform());
canvas.tx.scale(canvas.scale, canvas.scale);
canvas.setPreferredSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale)));
canvas.setSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale)));
canvas.validate();
canvas.repaint();
}
}
}
}
for some reason this code is working (except the button disappearing).. maybe my error is somewhere else in the child layers.. i'll go investigate that
Okay after some hours fiddling around with it, i came to the conclusion that the drawing limitations that the child panels get in their paint(Graphics g) method don't allow painting more than the parent's size. In the example it works but in the full application not. Seems some settings force that behaviour on my application, but not the demo app.
So if my parent frame has the dimension 640x480 the child layers that i have added to it can only draw inside a 640x480 fraction of the 1024x768
create JFrame --> put there JScrollPane --> to the JScrollPane put :
1) JPanel or JComponent with override paintComponentn(Graphics g) not paint(Graphics g)
2) you wrote about BufferedImage, then better way is put BufferedImage as Icon to the JLabel
As you've observed, a component can be rendered in a scaled graphics context, but the result is effectively useless: the UI delegate has no knowledge of the altered geometry. As #mKorbel suggests, a JScrollPane is the traditional alternative.
You might also look at the scheme used in this game or the technique used in this scalable label. If you are willing to make your own components, you may be able to adapt the approach shown in this ScaledView.
My problem got completely solved after asking some ppl about this.
The solution was:
1.
Create a new Class which you can draw on and make the manipulation there, example:
private class ScaledPane extends JPanel
{
public ScaledPane(Window parent)
{
super();
setPreferredSize(new Dimension(parent.getDesiredWidth(), parent.getDesiredHeight()));
setSize(this.getPreferredSize());
}
#Override
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g.create(0, 0, getWidth(), getHeight());
g2.setTransform(screenScale);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); //
System.out.println(g2.getClip());
super.paint(g2);
}
}
after that set an instance of that class to your contentpane:
setScreenScale(AffineTransform.getScaleInstance((double) width / (double) desiredWidth, (double) height / (double) desiredHeight));
setContentPane(new ScaledPane(this));
after doing that everything just went fine, as the components of the window us the contentpanes paint method to draw themselves with the new graphics object that is set there
With that done i can scale my window to any desired size without manipulation of the movement formulas or positions of any child.

How can I resize and paintComponent inside a frame

Write a program that fills the window with a larrge ellipse. The ellipse shoud touch the window boundaries, even if the window is resized.
I have the following code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
public class EllipseComponent extends JComponent {
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double ellipse = new Ellipse2D.Double(0,0,150,200);
g2.draw(ellipse);
g2.setColor(Color.red);
g2.fill(ellipse);
}
}
And the main class:
import javax.swing.JFrame;
public class EllipseViewer {
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(150, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EllipseComponent component = new EllipseComponent();
frame.add(component);
frame.setVisible(true);
}
}
in your EllipseComponent you do:
Ellipse2D.Double ellipse = new Ellipse2D.Double(0,0,getWidth(),getHeight());
I'd also recommend the changes given by Hovercraft Full Of Eels. In this simple case it might not be an issue but as the paintComponent method grows in complexity you realy want as little as possible to be computed in the paintComponent method.
Do not resize components within paintComponent. In fact, do not create objects or do any program logic within this method. The method needs to be lean, fast as possible, do drawing, and that's it. You must understand that you do not have complete control over when or even if this method is called, and you certainly don't want to add code to it unnecessarily that may slow it down.
You should create your ellipse in the class's constructor. To resize it according to the JComponent's size and on change of size, use a ComponentListener.:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
public class EllipseComponent extends JComponent {
Ellipse2D ellipse = null;
public EllipseComponent {
ellipse = new Ellipse2D.Double(0,0,150,200);
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// set the size of your ellipse here
// based on the component's width and height
}
});
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.draw(ellipse);
g2.setColor(Color.red);
g2.fill(ellipse);
}
}
Caveat: code not run nor tested

Categories