I had to make an applet that shows its own source code. This is what I have:
//Reference the required Java libraries
import java.applet.Applet;
import java.awt.*;
//The applet code
public class FirstApplet extends Applet {
public void paint(Graphics g) {
//Draw a rectangle width=250, height=100
g.drawRect(0,0,250,600);
//Set the color to blue
g.setColor(Color.blue);
//Write the message to the web page
g.drawString("\n //Reference the required Java libraries\n import java.applet.Applet;\n import java.awt.*; \n //The applet code\n public class FirstApplet extends Applet {\n public void paint(Graphics g) {\n //Draw a rectangle width=250, height=100\n g.drawRect(0,0,250,100); \n //Set the color to blue\n g.setColor(Color.blue); \n //Write the message to the web page\n g.drawString",10,50);
}
}
However, the \n is not making a new line. My text continues horizontally until finished. How would I crate new lines inside the g.drawString field?
Perhaps you could try something like this (Untested):
public static void draw(final Graphics g, final int startX, final int startY, final String... lines){
final FontMetrics metrics = g.getFontMetrics();
final int spacing = metrics.getHeight() + metrics.getMaxDescent();
draw(g, startX, startY, spacing, lines);
}
public static void draw(final Graphics g, final int startX, final int startY, final int vSpacing, final String... lines){
int y = startY;
for(final String line : lines){
g.drawString(line, startX, y);
y += vSpacing;
}
}
The first method will calculate the height (based on the height and descent of the current Font of your Graphics object). The second method allows you to input a custom vertical spacing value for more customizability.
I had to make an applet that shows its own source code.
Two alternatives:
Use AppletContext.showDocument(URL) to browse to the source file.
Use a JTextArea with JTextComponent.read(Reader,Object) to read the source.
BTW
Why code an applet? If it is due to spec. by teacher, please refer them to Why CS teachers should stop teaching Java applets.
Why AWT rather than Swing? See this answer on Swing extras over AWT for many good reasons to abandon using AWT components. If you need to support older AWT based APIs, see Mixing Heavyweight and Lightweight Components.
Related
I want to get the exact height of my string in pixels on my panel. So I wrote a program that draws the string, and then draws a rectangle around it.
Using FontMetrics I used the getStringBounds method to get me the enclosing rectangle.
However it looks wrong :
I was expecting the rectangle to perfectly enclose my text, but there is space at the top (And a tiny bit of space on the left and right). Why is it giving me this result?
Here is my code :
public class Test extends JPanel {
#Override
protected void paintComponent(Graphics g) {
Font font = new Font("Arial", Font.PLAIN, 60);
g.setFont(font);
FontMetrics fm = this.getFontMetrics(font);
String str = "100dhgt";
Rectangle2D rect = fm.getStringBounds(str, g);
int x = 5;
int y = 100;
g.drawRect(x, y - (int)rect.getHeight(), (int)rect.getWidth(), (int)rect.getHeight());
g.drawString(str, x, y);
}
public static void main(String[] args) {
JFrame f = new JFrame();
Test test = new Test();
f.add(test);
f.setVisible(true);
f.setSize(400, 400);
}
}
Regarding your rectangle, you have to consider the font's descend (how far is it below the line)
g.drawString(str, x, y - fm.getDescent());
Also note that the font height usually considers some kind of line spacing. In this case fm.getDescent() + fm.getAscent() = 68 whereas fm.getHeight() = 70
The space at the top can be explained by your not taking account of the descent (which takes me back to one of my favorite methods from java 1.0: getMaxDecent)
Otherwise, the box looks pretty good. The only other advice I can offer is that fm.getStringBounds works better with some fonts than it does with others
My issues is the following: My actual project (of which the code below is a simplified version of) involves many concentric circles (each with a different colour) and animation utilising a Timer. The circles are drawn using the drawOval method.
My problem is that when these concentric circles are drawn, there appears to be loads of gaps in the outline of these circles, which I'm guessing is something to do with the fact that a circle is composed of pixels and lines as is any shape so the appearance of roundness is an illusion. I say this because when I swap the drawOval method for drawRect the painting looks as you would expect.
When messing around with other people's codes I saw that using RenderingHints somehow solved this problem however slowed down the animation beyond a point that I felt was acceptable.
Below is a screenshot of what is painted. Rather than seeing a solid opaque circle (as all of the circles drawn have the same colour in this example) we see this:
Here is my simplified code:
Test10
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Test10 extends JPanel {
Circle[] circles;
public static void main(String[] args) {
new Test10().go();
}
void go() {
JFrame frame = new JFrame("Circle Test");
frame.getContentPane().add(this);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
circles = new Circle[200];
for (int i = 0; i < 200; i++) {
circles[i] = new Circle(i, ((2 * ( 200 - i) + 1)));
}
repaint();
frame.setPreferredSize(new Dimension(500,500));
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
for (Circle circle : circles ) {
circle.draw(g);
}
}
}
Circle
import java.awt.Graphics;
public class Circle {
int topLeft;
int diameter;
public Circle(int topLeft, int diameter) {
this.topLeft = topLeft;
this.diameter = diameter;
}
void draw(Graphics g) {
g.drawOval(topLeft, topLeft, diameter, diameter);
}
}
Could anyone explain to me a) Why this is happening and b) How to overcome this problem.
UPDATE
Having tried various methods including starting with the outermost circle and using fillOval instead of drawOval, and using a higher stroke value, I still find I have a problem with certain artefacts appearing similar to the screenshot Pavel posted. Here is a screenshot from my full application running the animation, if you look carefully you can see inconsistencies in the colour of mostly any given circle, resulting in these strange results. Their distribution actually follows the same pattern as the screenshot posted above so clearly something fundamental isn't being addressed by these options. Here is my screen shot:
It is impossible to draw perfect circle.
Try using the following method
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2));
int i = 0;
for (Circle circle : circles ) {
Shape circle2 = new Ellipse2D.Double(i++, i, circle.diameter, circle.diameter);
g2d.draw(circle2);
}
}
You said you tried with RenderingHints, and it slowed your animation, but you haven't give us any code with animation, so maybe try my code (it would be good to see animation implementation). It looked better, but still not what you wanted. Setting stroke to another value will solve this (set to at least 2). Another one is to use .fill() instead of .draw(). I know that it is not perfect, but you may try it.
ANOTHER IDEA
I thought, that maybe you could add some blur to your image, so those artifacts are not visible?
I haven't done it before, but I found this (found HERE):
private class BlurGlass extends JComponent {
private JFrame f;
public BlurGlass(JFrame f) {
this.f = f;
setOpaque(false);
setFocusable(false);
}
public void paintComponent(Graphics g) {
int w = f.getWidth();
int h = f.getHeight();
setLocation(0, 0);
setSize(w, h);
g.setColor(new Color(0, 0, 0, 0.3f));
g.fillRect(0, 0, w, h);
}
}
now somwhere in go() method:
frame.setGlassPane(new BlurGlass(frame));
frame.getGlassPane().setVisible(true);
It looks a lot better for me. Play a bit with this GlassPane color (try changing .3f to some other value).
You might want to make the Stroke bigger. I've had luck with this in situations similar to yours
You can try by adding this line in your Circle class inside draw function:
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//and draw the Oval on g2
Also another solution might be to fill the circles:
Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2.fill(circle);
That happens because a computer cannot draw a perfect circle.
A computer uses square pixels to approximate a real circle but its just not possible to achieve perfection and that results in some pixels not being shown
Drawing a filled circle will help you
a detailed explanation
Can you please try fillOval method instead of drawOval.
g.fillOval(topLeft, topLeft, diameter, diameter);
Reverse your idea. Start with the outermost circle, then draw the inner circle and so on, finishing with the smallest circle. You should use fillOval in the process.
The other rendering hint that is often useful for circles/ovals is
g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
See my other answer with more details and example.
This question already has answers here:
Adding Image to a Polygon
(2 answers)
Closed 8 years ago.
I'm trying to basically remake Asteroids in java, but I'm going to use a bald eagle as a ship that shoots down Soviet flags. Right now, my bald eagle image is a square with a white outline around the eagle. I would like to remove this, is there any way to map this in a one-to-one fashion to a polygon of sorts?
Here's my code, though I don't know exactly how this will help anything:
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
GameTest t = new GameTest();
}
public static class GameTest extends JFrame {
private static final int WINDOW_WIDTH = 800;
private static final int WINDOW_HEIGHT = 500;
private GamePanel gamePanel;
public GameTest() throws IOException {
super("Deep Fried Freedom");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLayout(new BorderLayout());
gamePanel = new GamePanel();
add(gamePanel);
center(this);
setVisible(true);
}
public static void center(JFrame frame) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Point center = ge.getCenterPoint();
int w = frame.getWidth();
int h = frame.getHeight();
int x = center.x - w / 2, y = center.y - h / 2;
frame.setBounds(x, y, w, h);
frame.validate();
}//end of center method
}
}
public class GamePanel extends JPanel {
public static BufferedImage baldEagleImage;
public GamePanel() throws IOException {
super();
baldEagleImage = ImageIO.read(new File("baldeagleimage.jpg"));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);// set color black
g.fillRect(0, 0, getWidth(), getHeight()); // paint background
g.drawImage(baldEagleImage, 350, 175, null);//paint the launcher
}//end paintComponent method
}//end GamePanel class
You have several ways that you can achieve this effect. Your best bet would be to use the alpha channel of your image. Just open your image in an image editing tool such as Gimp. In this set the background of your image to transparent around your image.
Another option (which is not the best) but fulfils your request is to use a paint stroke in Java2D. Have a look at using the java2d clipping feature. You can get a tutorial on this here
Usually you will have a Java object that represents the ship, and it has x and y coordinates called something like centerX and centerY. That gives you the center of the ship on your screen within the bounds of the viewable area. You modify these values when you want the ship to move up and down, and you g.drawImage the image you want to use at these coordinates as well (plus any offsets as needed to make the image appear centered to your liking).
A common method is to have a thread started upon initialization, and in that thread is a while(true) block that does an update() method on all objects that need to be updated, and then a Thread.sleep(17) that mimics a framerate of about 60 frames per second. In this method, your ship has its X and Y coords updated and then the image drawn at that location every 17 milliseconds, and that's how you get a ship (and any other object for that matter) to appear like they are moving around on the screen.
I am creating lines and other components and want them to respond like a Swing button events as a line would be clickable :
class CustomLine extends JComponent {
private int destx = 100;
private int desty = 100;
private int startx = 0;
private int starty = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(startx, starty, destx, desty);
}
}
how this works?
It would be a math problem. You need to find the equation of the line and then find the distance from point (mouse click).
The math is done for you, for example here
You will also need to figure out handling mouse events.
What about extending it from JButton?
Just overrive the paint-Method like you did with JComponent and use it like a normal Button.
I'm not sure, if you need to alter the Border, too. I'm not familiar with altering GUI-Elements, but maybe this should do the trick.
How can I draw a String in Java (using Graphics2d) in monospace mode? I have a font that looks like LCD screen font, and I want to draw something like LCD label.
I am using Digital 7 Mono font.
Do you know where I can find another font that will be monospace and lcd (I wan to type only digitals)?
How can I draw a String in Java (using Graphics2d) in monospace mode?
The essential method needed to render text is drawString(), as outlined below. There is no "monospace mode", per se, but even proportionally spaced fonts typically use a constant width for digit glyphs .
private static final Font font = new Font("Monospaced", Font.PLAIN, 32);
private static final String s = "12:34";
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(font);
int xx = this.getWidth();
int yy = this.getHeight();
int w2 = g.getFontMetrics().stringWidth(s) / 2;
int h2 = g.getFontMetrics().getDescent();
g.setColor(Color.green);
g.drawString(s, xx / 2 - w2, yy / 2 + h2);
}
There's a complete example here, and you can extend a suitable JComponent to control positioning using a layout manager, as seen here.