Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Easy Java Lecture 12a: Painting Concepts. Teach/learn online

JavaFAQ Home » Java Lectures by Anatoliy Malyarenko Go to all tips in Java Lectures by Anatoliy Malyarenko


Bookmark and Share

Introduction to Painting Concepts

by: Anatoliy Malyarenko

Contents

  • The Coordinate System
  • The Graphics Object and Graphics2D
  • Implementing a Custom Component
  • Example
  • GraphicsDemo.html
  • GraphicsPanel.java
  • GraphicsDemo.java
  • Conclusion

The Coordinate System


Each component has its own integer coordinate system, ranging from (0, 0) to (width - 1, height - 1), where width and height are the size of the component in pixels. As the following figure shows, the upper left corner of a component's painting area is (0, 0). The x coordinate increases to the right, and the y coordinate increases downward.

When painting, you must take into account not only the component's size but also the size of the component's border, if any. For example, a border that paints a one-pixel line around a component effectively changes the top leftmost corner of the component's non-background painting area from (0,0) to (1,1) and reduces the width and the height of the painting area by two pixels each (one pixel per side). The following figure demonstrates this:

You can get the width and height of any JComponent using its getWidth and getHeight methods. The getSize method is another option that works for all Components. To deter mine the border size, use the getInsets method.

The Graphics Object and Graphics2D

The Graphics object passed into the paintComponent method provides both a context and some methods for simple painting. In almost every case, Graphics objects are actually Graphics2D objects. The Graphics2D class extends Graphics to provide more sophisticated control over geometry, coordinate transformations, colour management, and text layout.

You can cast any Graphics parameter into a Graphics2D object as long as your program uses the Java 2 platform (1.2 or later).

The painting methods defined by Graphics include such standbys as drawRect, fillRect, and drawLine. The Graphics2D class adds more flexible methods such as draw(Shape) and fill(Shape).

The graphics context provided by a Graphics object consists of state such as the current painting colour, the current font, and the current painting area. The Graphics2D class adds more state, such as the alpha compositing mode, stroke, rendering hints, and colour patterns such as textures and gradients.

In JComponents, the Graphics object is initialised just before it's passed to paintComponent, so that its colour and font are set to the foreground colour and font of the component.

Implementing a Custom Component

If you really need to perform custom painting, then you need to decide which superclass to use. Your component can extend JComponent, JPanel, or a more specialised Swing component class.

For example, if you're creating a custom button class, you should probably implement it by extending a button class such as JButton or JToggleButton. That way you'll inherit the state management provided by those classes. If you're creating a component that paints on top of an image, you might want to create a JLabel subclass. A component that's a specialised
container should probably extend JPanel. On the other hand, if you're implementing a component that generates and displays a graph, for example -- with or without providing user interaction -- then you might want to use a JComponent subclass.

When implementing custom painting code for a component, keep these rules in mind:

  • Your custom painting code should be in a method with the signature protected void paintComponent(Graphics).
  • You can -- and probably should -- use a border to paint the outside edges of your component.
  • Except when painting the background of the component, you should avoid painting over the border area of the component. You can determine this area using the getInsets method.
  • Make sure that when the paintComponent method exits, the Graphics object that was passed into it has the same state that it had at the start of the method.
  • To gain access to the power of the 2D graphics API, you can cast the Graphics parameter into a Graphics2D object.

Example

Our example consists of three files.

GraphicsDemo.html

Here is the first file, GraphicsDemo.html.

<HTML>
    <HEAD>
        <TITLE>GraphicsDemo</TITLE>
    </HEAD>
    <BODY>
        <H1>GraphicsDemo</H1>
        <HR>
        <P>
            <APPLET CODE="GraphicsDemo.class" WIDTH="640" HEIGHT="480">
            </APPLET>
        </P>
        <HR>
    </BODY>
</HTML>

This file was created automatically by RealJ. I changed only the width and the height of the applet's window.

GraphicsPanel.java

The next file is called GraphicsPanel.java. This is a subclass of JComponent:

import java.awt.*;
import javax.swing.*;

public class GraphicsPanel extends JComponent {

First of all, our class should contain a reference to trajectory:

private double[] trajectory = null;

You create trajectory in you main class in response to pressing some button. Then, you pass the reference to trajectory into the instance of GraphicsPanel, using the next method:

public void setTrajectory(double[] trajectory) {
    this.trajectory = trajectory;
}

Now we start to write our custom painting code:

public void paintComponent(Graphics g) {

First, we paint an instance of the superclass, JComponent, using its paintComponent method:

super.paintComponent(g);

Next, we must determine, is it the first appearance of our custom JComponent in applet's window? If so, then we paint nothing. Otherwise, we paint something.

How can one distinguish between two cases? The answer is: when our custom JComponent appears for the first time, the value of trajectory is equal to null. Otherwise trajectory points to some array of values. So, the next line of code is

if (trajectory != null) {

Now we prepare to paint. First, we determine the maximal and minimal values in our array:

double maxValue = trajectory[0];
double minValue = trajectory[0];
for (int i=1; i<trajectory.length; i++) {
    if (trajectory[i] > maxValue) {
        maxValue = trajectory[i];
    }
    if (trajectory[i] < minValue) {
        minValue = trajectory[i];
    }
}

In any case we plan to draw x-axis. It follows, that if the actual minimal value is positive, we must put it equal to 0:

if (minValue > 0) {
    minValue = 0;
}

To determine the width and height available for custom painting, we use the getInsets method as follows:

Insets insets = getInsets();

int currentWidth = getWidth() - insets.left - insets.right;

int currentHeight = getHeight() - insets.top - insets.bottom;

Now we create a copy of the Graphics object and cast it into a Graphics2D object.

Graphics2D g2d = (Graphics2D)g.create();

This has two consequences. First, we can guarantee, that the Graphics object g does not change its state. Second, we obtain access to the power of the 2D graphics API, while we do not actually use it in this example.

We paint a white background.

g2d.setColor(Color.white);
g2d.fillRect(insets.left,insets.top,
                    currentWidth,currentHeight);

Now we calculate, how many pixels are containing in one unit of measurement on both x- and y-axes.

double xStep = currentWidth/(trajectory.length-1);
double yStep = currentHeight/(maxValue-minValue);

We put x-axis into the bottom of our window. However, if the minimal value is negative, we must shift the axis up.

int xLocation = insets.left + currentHeight;
if (minValue <0) {
    xLocation += minValue*yStep;
}

We draw axes in black.

g2d.setColor(Color.black);
g2d.drawLine(insets.left,insets.top,
insets.left,currentHeight);
g2d.drawLine(insets.left,xLocation,
            currentWidth,xLocation);

Now we draw graph in blue

g2d.setColor(Color.blue);

for (int i=0; i<trajectory.length-1; i++) {
    g2d.drawLine(insets.left+(int)(i*xStep),
            xLocation+(int)(trajectory[i]*yStep),
            insets.left+(int)((i+1)*xStep),
            xLocation+(int)(trajectory[i+1]*yStep));
    }
and release the copy's resources
            g2d.dispose();
        }
    }
}

GraphicsDemo.java

Our main class, GraphicsDemo.java, is a subclass of JApplet:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GraphicsDemo extends JApplet {

First of all, we define trajectory:

private double[] trajectory = null;

Next, for simplification of future changes, we define all of our text labels.

private static String generate = "Generate";

Our applet has three panels. The first one is mainPanel:

private JPanel mainPanel = null;

mainPanel has two subpanels. The first one is called commandPanel. It is the instance of the standard class JPanel:

private JPanel commandPanel = null;

The second subpanel is called graphicsPanel. It is the instance of our custom class GraphicsPanel:

private GraphicsPanel graphicsPanel = null;

Finally, we define all of our buttons.

private JButton generateButton = null;

That's all variables of our class.

All elements of the applet's graphical user interface must appear, when the applet initialises itself, i.e., in the init method:

public void init() {

In Swing, every top-level container has a content pane that contains, directly or indirectly, all the visible components (except for menus and window decorations) in the top-level container. To obtain the reference to the applet's content pane, we use the getContentPane method:

Container contentPane = getContentPane();

Now, we create mainPanel,

mainPanel = new JPanel();

set its layout as vertical box layout,

mainPanel.setLayout(
         new BoxLayout(mainPanel,BoxLayout.PAGE_AXIS));
add empty border,

mainPanel.setBorder(
        BorderFactory.createEmptyBorder(5,5,5,5));

and add mainPanel to the applet's content pane:

contentPane.add(mainPanel);

Next, we create commandPanel,

commandPanel = new JPanel();

and add black line border
commandPanel.setBorder(
            BorderFactory.createLineBorder(Color.black));

Now, we create a button,

generateButton = new JButton(generate);

and add it to commandPanel:

commandPanel.add(generateButton);

We want to handle the button-click event, so we add an event listener to the button.

generateButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {

Inside the listener, we first create trajectory, if it was not created before:

if (trajectory == null) {
    trajectory = new double[10];
}

Next, we fill trajectory by some values, just to show something:

for (int i=0; i<10; i++) {
    trajectory[i] = Math.sin(i);
}

Finally, we pass the reference to trajectory into graphicsPanel,

graphicsPanel.setTrajectory(trajectory);

and invoke our custom painting:

        graphicsPanel.repaint();
    }
});

Method repaint automatically calls our custom paintComponent, and the graph is painting.

Now we add commandPanel to mainPanel;

mainPanel.add(commandPanel);

and add the additional 5 pixels between our subpanels:

mainPanel.add(Box.createRigidArea(new Dimension(0,5)));

Finally, we create graphicsPanel,

graphicsPanel = new GraphicsPanel();

add the raised bevel border,

graphicsPanel.setBorder(
        BorderFactory.createRaisedBevelBorder());

and add graphicsPanel to mainPanel:

        mainPanel.add(graphicsPanel);
    }
}

That's all, folks!

Conclusions

You can use the GraphicsDemo applet as a pattern for your project. Moreover, you can do the following.

  • Try different layout managers for your content pane and control panel.
  • Realise various elements of Swing's graphical user interface inside your control panel.
  • Try to use HTML in your text labels.
  • Customise your graphical output, using different capabilities of both Graphics and Graphics2D classes.

Good luck!

References

[1] 2D Graphics, click here
[2] Class Graphics, click here
[3] The Swing tutorial, click here


 Printer Friendly Page  Printer Friendly Page
 Send to a Friend  Send to a Friend

.. Bookmark and Share

Search here again if you need more info!
Custom Search



Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy