Concepts / Off-screen Canvas Usage with Graphics2D

Off-screen Canvas Usage with Graphics2D

A custom Swing component can be defined as a subclass of JPanel, which supplies its layout, size handling, and inherited colors and fonts.

  • Programming

Why a Mirror Image Needs a Hidden Step

Suppose you need a component that behaves much like a JLabel, showing one line of text, except that the text appears in mirror-reversed form. No standard Swing component does this. When the component you need does not exist, you build one yourself. This article follows one such example, a class called MirrorText, and uses it to show how a custom component is assembled, how its content is painted, and where a mistake would reveal itself.

What do you think happens?

If paintComponent() can draw straight onto the visible area, why would a designer need anything in between?

Reveal answer
Answer:

The mirror-reversal technique depends on an intermediate image. The text is drawn into a hidden off-screen canvas first, and the reversal happens when that finished image is copied to the screen.

Drawing the text directly would produce normal-orientation text. Reversing the text requires a separate image whose orientation is changed during the copy step, so the intermediate image is what makes the reversal possible.

Building a Component by Subclassing JPanel

The MirrorText class is defined as a subclass of JPanel. That single decision determines most of what the class inherits. Because it extends JPanel, it gets the panel's ability to be placed in a layout, its size handling, and its use of colors and fonts. The class then adds only what is specific to it: a constructor that receives the text to show, and a setText() method that replaces that text later.

The class also respects the standard appearance settings of the panel. The source states that MirrorText uses any background color, foreground color, and font set on the JPanel. It does not need its own color or font fields for these. It reads them from the panel it extends, so a caller who sets a font on the component changes the text's font without any extra work in the class.

  • Inherited from JPanel: placement inside a layout, size handling, background color, foreground color, and font
  • Added by MirrorText: a constructor that accepts the text to display
  • Added by MirrorText: a setText() method that replaces the text after construction
  • Overridden by MirrorText: paintComponent(), which produces everything the user sees inside the component
Best practice

Before writing a custom component, check whether a standard component already supplies the behavior you need. Subclass JPanel only when no existing component does the job, and then add only the fields and methods that are specific to your component. Let the inherited colors and fonts do their work instead of duplicating them.

Painting Content with paintComponent()

Everything the user sees inside a custom component comes from one method: paintComponent(). MirrorText overrides this method to draw its text mirror-reversed, centered within the available area. Centering is not guessed. The method uses information from a FontMetrics object, which describes how large the text will be when drawn in the current font, so the text can be positioned in the middle of the component.

Because the visible output of the component is produced entirely inside paintComponent(), any question about what appears on screen can be answered by asking what this method does, in order. The method does not simply write text to the screen. It calls the steps that prepare an image and then copy that image into the visible area. Each of those steps is a place where the final result can be correct or incorrect.

Drawing into the Off-screen Canvas

The reversal is achieved with an off-screen canvas. An off-screen canvas is an image that exists in memory but is not shown to the user. The text is first drawn onto this image in the ordinary way, exactly as if the text were being drawn normally. Nothing about the text is reversed during this first step. The reversal happens later, in the copy.

The movement is one-way. Text goes into the hidden image, and the finished image is then handed to the screen by a single drawing call. The component never draws the reversed text directly. It draws an image that was prepared earlier, and the copy operation is the only place where the image's orientation is changed.

Text drawn normallyinto the off-screen canvasOff-screen imagehidden, not shown to theuserdrawImage copyswapped x corners reversethe imageVisible componentshows mirror-reversed textdrawsingle copy commandpixels copied
In what order do the drawing calls, the off-screen image, and the drawImage call move pixels from the buffer to the visible component?

Reading the drawImage Corner Arguments

The copy step is performed by one command. In it, OSC names the off-screen canvas, and width and height give the size of both the component and the off-screen canvas, which are the same size. The remaining information is in the corners. The drawImage method, as used here, takes a destination rectangle followed by a source rectangle, each given by two corners. Read the arguments in pairs.

RectangleCorner oneCorner twoDirection across the width
Source (off-screen image)(0, 0)(width, height)Left edge to right edge
Destination (visible component)(width, 0)(0, height)Right edge back to left edge

The destination corners are swapped relative to the source, which is what flips the image horizontally.

The source covers the whole off-screen image from left to right. The destination runs in the opposite direction, from the right edge back to the left edge. Copying an image into a region whose horizontal corners are swapped is what makes the result a mirror image. The vertical corners are not swapped, so the text keeps its top-to-bottom orientation and only the left-right order changes.

Source x = 0left edge of the off-screenimageDestination x = widthright edge of the componentSource x = widthright edge of theoff-screen imageDestination x = 0left edge of the componentleft edge lands on rightright edge lands on left
Which position at the left of the source ends up at the right of the result, and how does the coordinate mapping change?
Worked example

Tracing One Edge Through the Copy

The off-screen image and the component are both 200 pixels wide. Follow the leftmost column of the source through the drawImage copy.

  1. 1
    Identify the source corners

    The source runs from (0, 0) to (200, height), so its leftmost column is at x = 0.

  2. 2
    Identify the destination corners

    The destination runs from (200, 0) to (0, height), so its first corner is at x = 200, the right edge.

  3. 3
    Pair the endpoints

    The source's left edge is paired with the destination's first corner, which sits at the right edge of the component.

  4. 4
    Read the result

    The column that started on the left of the hidden image is drawn on the right of the visible component. Repeating this for every column produces the mirror image.

Result

The leftmost source column appears at the rightmost position on screen, so the text reads in mirror-reversed order.

Finding Where Wrong Output Begins

A custom component has several places where its output can go wrong, and the pipeline above tells you where to look. Because the visible result is produced by a copy from an intermediate image, a mismatch between what you expect and what you see usually comes from one of three stages: the drawing into the off-screen canvas, the copy command, or the painting method that calls them. The source identifies the copy arguments as the first place to look when the output is wrong.

paintComponent()overridden by MirrorTextOff-screen canvastext drawn normallydrawImage copycorner arguments setorientationVisible componentwhat the user sees1. draw text into canvas2. copy canvas with corner arguments3. swapped corners flip the output
Which step in the sequence of paintComponent, off-screen drawing, and drawImage is the one where a wrong result is most likely to start, and what happens downstream of it?

Read the diagram as a chain of dependence. The paint method calls the drawing into the canvas, then calls the copy. Whatever the copy receives determines the final orientation. If the corner arguments are not swapped, the text appears in normal order even though the drawing itself was correct. If the drawing into the canvas was wrong, the copy faithfully carries that error to the screen. This is why the copy command is the most likely origin of a reversal-specific mistake, while the canvas drawing is the most likely origin of a mistake in the text's content or position.

Mistakes That Produce Wrong Output

  • Common mistake

    Drawing the text straight onto the visible area and expecting it to be reversed

    Why it fails

    The reversal does not happen during ordinary drawing. It happens only in the copy from the off-screen image.

    Do this instead

    Draw into the off-screen canvas first, then copy that image to the component with drawImage.

  • Common mistake

    Keeping the destination corners in the same order as the source corners

    What it looks like

    Passing (0, 0) and (width, height) for the destination as well as the source

    Why it fails

    With matching corner order, the copy preserves left-to-right order and the output is not mirrored.

    Do this instead

    Swap the horizontal corners of the destination so it runs from (width, 0) to (0, height).

  • Common mistake

    Assuming the vertical corners must also be swapped

    Why it fails

    The mirror effect comes from the horizontal swap. Swapping vertical corners as well would change the top-to-bottom orientation.

    Do this instead

    Swap only the horizontal corners and keep the vertical corners as the source describes.

  • Common mistake

    Hard-coding the component's color and font in MirrorText

    Why it fails

    The class inherits the background, foreground, and font from the JPanel it extends. Hard-coding them overrides the caller's settings without a reason.

    Do this instead

    Read colors and fonts from the inherited panel settings, and add fields only for behavior that is genuinely specific to the class.

  • Common mistake

    Positioning text without FontMetrics, so the text is not centered within the available area

Predicting the Result of a Changed Corner

MEDIUM

A MirrorText component is 300 pixels wide. Its paintComponent() method draws the text into the off-screen canvas correctly, but the drawImage call uses the destination corners (0, 0) and (300, height) instead of swapping them. Predict what a viewer sees, and identify which of the three stages the mistake belongs to.

Hints
  • Compare the destination corners with the source corners. Do they run in the same direction or opposite directions?
  • Ask whether the mirror effect in this design comes from the drawing step or the copy step.
  • The drawing into the canvas is correct in this scenario, so the error is confined to one stage.

Key Takeaways

  • A custom Swing component can be built as a subclass of JPanel, inheriting layout behavior, size handling, and the panel's colors and fonts, while the subclass adds only its own constructor and methods.
  • The visible content of a custom component is produced by overriding paintComponent(), which can use FontMetrics information to center its output.
  • A mirror-reversed image is produced by drawing into an off-screen canvas first, then copying that image to the screen with drawImage, where swapping the horizontal destination corners relative to the source flips the result.
  • When the output is wrong, the first place to look is the copy arguments in drawImage, because the visible result is a copy of the intermediate image.