The simplest way to draw a string is to do it in paint() i.e
public void paint(Graphics g) { // This will draw the string in a red "TimesRoman" font g.setColor(Color.red); g.setFont(new Font("TimesRoman", Font.BOLD, 12)); // This draws the string given the x,y co-ordinates of the _baseline_ // Don't think the point you give it is the upper-left corner g.drawString("Hi There", 10, 50) }You can override paint in a Panel, Frame, Dialog, etc.. I would sub-class a Panel. Thus not messing around with the Frame's paint routine.
public class MyPanel extends Panel { ... ... public void paint(Graphics g) ... }Note: "Graphics" is abstract and thus you can not just instantiated. I.e.,
Graphics g = new Graphics() g.drawString(...);is illegal in Java. Thus the easiest way to retrieve a Graphics instance is in paint(), update(), etc. But if you have any instance of Graphics you should be able to draw a string.
drawLine(x1, y1, x2, y2)is a method in the Graphics class, so you'll need an instance of it. You can't create one yourself since it is abstract. I.e.
// g is an instance of Graphics g.drawLine(10, 10, 100, 100); // This is a nice little app I wrote for my "Introduction to the AWT" // document. (A newbie guide before I overload them with information // with my new (and IMPROVED) "AWT Tutorial"). // It draws 50 squares within each other import java.awt.*; public class FiftySquares extends Frame { float xA, yA, xB, yB, xC, yC, xD, yD, xA1, yA1, xB1, yB1, xC1, yC1, xD1, yD1,p,q,r; int i; int x_center, y_center; static final int H_SIZE = 300; static final int V_SIZE = 300; public FiftySquares() { q = (float)0.05; p = 1 - q; r = (float)0.95 * H_SIZE; x_center = H_SIZE/2; y_center = V_SIZE/2; resize(H_SIZE, V_SIZE); show(); } public void paint(Graphics g) { xA = xD = x_center - r; xB = xC = x_center + r; yA = yB = y_center - r; yC = yD = y_center + r; for(i=0; i<50; i++) { g.drawLine((int)xA, (int)yA, (int)xB, (int)yB); g.drawLine((int)xB, (int)yB, (int)xC, (int)yC); g.drawLine((int)xC, (int)yC, (int)xD, (int)yD); g.drawLine((int)xD, (int)yD, (int)xA, (int)yA); xA1= p*xA+q*xB;yA1= p*yA+q*yB; xB1= p*xB+q*xC;yB1= p*yB+q*yC; xC1= p*xC+q*xD;yC1= p*yC+q*yD; xD1= p*xD+q*xA;yD1= p*yD+q*yA; xA=xA1;xB=xB1;xC=xC1;xD=xD1; yA=yA1;yB=yB1;yC=yC1;yD=yD1; } } public static void main(String args[]) { new FiftySquares(); } }
To fill a region you must call the fill method. For example, say that you want to fill a rectangular region. This is good to be implemented in the paint method.(Submitted by Maria Winslow)public void paint(Graphics g) { g.drawRect(100, 100, 70, 80); // define the area g.SetColor(Color.blue); // define the fill color g.fillRect(100,100,70,80); // fill it with red color g.SetColor(Color.black); // change color so you are able to write // in the (blue) area if you want, and be visible }
There are also fill methods on the following shapes; all can be found in java.awt.Graphics.fill3DRect() fillArc() fillOval() fillPolygon() fillRect() fillRoundRect()If you want a filled circle, use fillRoundRect() with an arcWidth=width and arcHeight=height.
The folowing code in the init() method of an applet will get an image into an Image object. The image can be loaded only if the getDocumentBase() is valid i.e. - works well with an applet. Will not load images from arbitrary URLs
public void init() { Image image1 = null; image1 = getImage(getDocumentBase(), "\somepath\xyz.gif") // other code ..... } public void paint(Graphics g) { g.drawImage(image1, 0, 0, this); // other code ..... }
If you clip a graphics object, you must dispose of it before attempting to clip in a different way or nothing will be drawn:(Submitted by Paul Walker)Graphics g = this.getGraphics(); g.clipRect(LeftPoint, TopPoint, RectWidth, RectHeight); g.drawImage(Img, X, Y, this); g.dispose(); g = this.getGraphics(); g.clipRect(LeftPoint2, TopPoint2, RectWidth2, RectHeight2); g.drawImage(Img2, X, Y, this); g.dispose();
This is how you clip a rectangular region. This draws a cross on the full screen with and without clipping so you can see the effect.(Submitted by Glenn Murray)
import java.awt.*; import java.applet.Applet; // Demonstrates using clipRect to clip a rectangular region public class ClipEG extends Applet { public void init() { resize(300,300); } public void paint(Graphics g) { // Draw a diagonal cross without clipping g.drawLine(0,0,300,300); g.drawLine(300,0,0,300); // Draw a vertical cross with clipping Graphics gsave = g.create(); g.clipRect(100,100,100,100); g.setColor(Color.blue); g.drawLine(0,150,300,150); g.drawLine(150,0,150,300); // reset and check. Note that we can't naievely reset // g.clipRect, it seems, since the clipRect is an intersection. g = gsave; g.setColor(Color.red); g.drawLine(0,149,300,149); } }
For a rectangular region:
Graphics g = this.getGraphics(); Graphics clipg = g.create(); clipg.clipRect(LeftPoint, TopPoint, RectWidth, RectHeight); clipg.drawImage(Img, X, Y, this);
The image is "placed" at the specified X,Y location in the drawImage call, but the only part of the image which is painted, is that area which lies in the area specified by the clipRect call.
import java.awt.*; import java.applet.Applet; public class MovingImage extends Applet { int Ix, Iy; Image image1=null; public void init() { image1 = getImage(getDocumentBase(), "F1.gif"); } public void paint(Graphics g) { if(image1 != null) g.drawImage(image1, Ix, Iy, this); } public boolean mouseDrag(Event evt, int x, int y) { Ix = x; Iy = y; repaint(); return true; } }
(Submitted by Brian Miller)public void paint(Graphics g) { Rectangle r = g.getClipRect(); // r contains the clip rect. Do something // like see if it intersects my expensive-to-draw // thing or not }
Be forwarned that Graphics.getClipRect() will return null if the entire Component or Image is to be redrawn.
The following answer I found in newsgroup comp.lang.java:
From hvvliet@inter.nl.net (Hanpeter van Vliet)... How to do Offscreen drawing. This technique is also described on the Java home site, albeit in terms of alpha3 API's. A search for "flash" will yield those samples. Here's the list of it in beta1 terms. It uses a boolean "doubleBuffer" switch so you can see how the code differs from the standard case: class MyApplet extends Applet { .... private boolean doubleBuffer=true; // or false of course private Image buf; // bitmap for double buffering private Graphics gBuf; // gc to draw on bitmap public void init() { .... if (doubleBuffer) { Dimension d = size(); buf = createImage(d.width, d.height); gBuf = buf.getGraphics(); } } public void destroy() { .... if (doubleBuffer) gBuf.dispose(); } protected void paintApplet(Graphics g) { // pre-clear the bitmap or the applet // remove this if you paint the entire area anyway Dimension d = size(); g.setColor(getBackground()); g.fillRect(0, 0, d.width, d.height); ....code that was originally in paint()... } public void paint(Graphics g) { if (doubleBuffer) { paintApplet(gBuf); g.drawImage(buf, 0, 0, this); } else { paintApplet(g); } } public void update(Graphics g) { // override this because the default implementation always // calls clearRect first, causing unwanted flicker paint(g); } } -- hanpeter
The following code will take m_Image and copy its bytes into pix_src. You can then manipulate these bytes and create a new image using MemoryImageSource. I am tying to put together a RotatingImage class that would use this code. If anyone has suggestions/experiences about manipulating images in Java, please email me: jmarin@superlink.com(Submitted by Garth A. Dickie)// wait for the whole image to load (look at imageUpdate) while(m_width == -1) m_width = m_Image.getWidth(null); m_height = m_Image.getHeight(null); pix_src = new int[m_width*m_height]; m_pg = new PixelGrabber( m_Image, 0, 0, m_width, m_height, pix_src, 0, m_width); m_Image.getSource().addConsumer(m_pg); boolean stat = false; try { stat = m_pg.grabPixels(); } catch(InterruptedException e) { Debug("interrupted waiting for pixels"); return; } if((m_pg.status() & ImageObserver.ABORT) != 0) { Debug("image fetch aborted or errored"); return; } // m_Image bytes are now pix_src!
If an image was created with a call toComponent.createImage( width, height )orToolbox.createImage( width, height )then you can set individual pixels by creating a Graphics object which draws to the image:public static void setOnePixel( Image image, int x, int y, Color color ) { Graphics g = image.getGraphics( ); g.setColor( color ); g.fillRect( x, y, 1, 1 ); g.dispose( ); }For reading the pixels of an image, or modifying an image which you obtained from a URL, you need to use the ImageProducer, ImageConsumer, ImageFilter classes from the package java.awt.image. There is an example ImageFilter provided with the awt (for changing the ColorModel). The documentation seems good.
To draw a stippled rectangle, create a 1 pixel wide by 1 pixel high offscreen image whose pixel is set to the color you would like. Then draw it to the screen with scaling. The drawImage call with dither your single color into the available onscreen colors.Here is an applet which does this:
import java.awt.*; import java.awt.image.*; import java.applet.Applet; public class FuzzyTestApplet extends Applet { private Color rectangleColor = new Color( 250, 240, 230 ); private Image solidImage; public void init( ) { solidImage = createOnePixelImage( rectangleColor ); } public void update( Graphics g ) { paint( g ); } public void paint( Graphics g ) { g.drawImage( solidImage, 0, 0, size( ).width, size( ).height, this ); } public Image createOnePixelImage( Color color ) { byte[ ] red = { ( byte ) color.getRed( ) }; byte[ ] green = { ( byte ) color.getGreen( ) }; byte[ ] blue = { ( byte ) color.getBlue( ) }; byte[ ] pixel = { 0 }; IndexColorModel colorModel = new IndexColorModel( 8, 1, red, green, blue ); MemoryImageSource source = new MemoryImageSource( 1, 1, colorModel, pixel, 0, 1 ); return createImage( source ); } }
The first thing to do is to override the method update() for the canvas (or whatever component you are displaying the image in). The default behavior of update() is that it first clears the display: this causes flicker.Next, do not put all of your drawing code into paint(). Only put in there the code that is necessary to recreate the canvas when the window is minimized and then restored - that is the purpose of paint(). One approach is to use "double-buffering", in which you apply all drawing operations twice whenever you do them: (1) to the canvas; and (2) to the buffer. Then, in paint(), simply restore the canvas with the drawImage() method. An example of a paint() method that does this is:
public void paint(Graphics g) { // Check if window was just resized Dimension d = size(); if ((d.width != buffer.getWidth(this)) || (d.height != buffer.getHeight(this))) { { // Save the currently displayed image Image temp = buffer; // Reallocate a buffer to match the new size setupBuffer(d.width, d.height); // Restore the image to the new buffer bg.drawImage(temp, 0, 0, this); } System.gc(); // force the old buffer to be free'd } // Restore the image to the screen -- this is the key part getGraphics().drawImage(buffer, 0, 0, this); }
In Java 1.0, you cannot change the width of the pen. You'll have to draw multiple parallel lines or fill a polygon.(Submitted by Cliff Berg)
Here is an algorithm I wrote for doing that. I hope it's right - it seems to work!
public void drawLine( Graphics g, int startX, int startY, int endX, int endY, int wid, Color col) { // Make this reflect the current width and color... g.setColor(col); // // We draw a thick line by computing the four corners of an equivalent // diagonal rectangle, and filling it. // // Compute the corner points of the rectangle to fill // // The x and y deltas from the start to the end of the line... int dX = endX - startX; int dY = endY - startY; // The length of the line... double D = Math.sqrt(dX * dX + dY * dY); // The ratio of half the line thickness to the length of the line... double scale = (double)(wid) / (2 * D); // The x and y increments from an endpoint needed to create a rectangle... double ddx = -scale * (double)dY; double ddy = scale * (double)dX; if (ddx > 0) ddx += 0.5; else ddx -= 0.5; // round off if (ddy > 0) ddy += 0.5; else ddy -= 0.5; // " int dx = (int)ddx; int dy = (int)ddy; // Now we can compute the corner points... int xPoints[] = new int[4]; int yPoints[] = new int[4]; xPoints[0] = startX + dx; yPoints[0] = startY + dy; xPoints[1] = startX - dx; yPoints[1] = startY - dy; xPoints[2] = endX - dx; yPoints[2] = endY - dy; xPoints[3] = endX + dx; yPoints[3] = endY + dy; // Fill the rectangle, effectively drawing a thick line g.fillPolygon(xPoints, yPoints, 4); }
I have done this using PixelGrabber and MemoryImageSource. Imagine a 50x50 image to be rotated by 90 degrees:Image img = createImage(...); int buffer[] = new int[50 * 50]; int rotate[] = new int[50 * 50]; PixelGrabber grabber = new PixelGrabber(img, 0, 0, 50, 50, buffer, 0, 50); try { grabber.grabPixels(); } catch(InterruptedException e) { ... } for(int y = 0; y < 50; y++) { for(int x = 0; x < 50; x++) { rotate[((50-x-1)*50)+y] = buffer[(y*50)+x]; } } Image rot = createImage(new MemoryImageSource(50, 50, rotate, 0, 50));
One form of the drawImage method lets you specify the width wd and height ht (in pixels) of the image to be drawn. The displayed image will then be scaled to those dimensions. An example:
Image img = getImage("picture.gif"); g.drawImage(img,0,0,wd,ht,this);where g is the Graphics usually found in the paint(Graphics g) method.
This is related to the question above on right-adjusting strings. To get the width of a string tx, useint tw = g.getFontMetrics().stringWidth(tx);To get its height use (note that you do not need to mention the string tx this time):int th = g.getFontMetrics().getHeight();Both commands must be used within the Context of a Grahpics g, such as in paint(Graphics g). Alternatively, if you know the Font f to be used for the string, you can useint tw = getFontMetrics(f).stringWidth(tx);without involving g.