Isn't it really impossible to call Component.getGraphics?

MadProgrammer made a comment here pointing out that NEVER EVER use Component.getGraphics, which I generally agree with: this is not true in almost all situations.

But consider the case of this class that I created a few years ago. I am posting what I think is the relevant code. You can find the complete code here

public class MouseDragOutliner extends MouseAdapter implements MouseMotionListener {
private class MyRunnable implements Runnable {
    public void run() {
        Graphics g = mComponent.getGraphics();
        if (g == null) {
            return;
        }
        Graphics2D g2 = (Graphics2D) g;
        Stroke s = g2.getStroke();
        g2.setStroke(DASH_STROKE);
        int x = Math.min(mStart.x, mEnd.x);
        int y = Math.min(mStart.y, mEnd.y);
        int w = Math.abs(mEnd.x - mStart.x);
        int h = Math.abs(mEnd.y - mStart.y);
        if (w == 0 || h == 0) return;
        g2.setXORMode(Color.WHITE);
        if (mCustomShape != null) {
            Rectangle r = mCustomShape.getBounds();
            AffineTransform scale = AffineTransform.getScaleInstance(w / (double)r.width, h / (double)r.height);
            AffineTransform trans = AffineTransform.getTranslateInstance(x - r.x, y-r.y);
            g2.transform(trans);
            g2.transform(scale);
            g2.draw(mCustomShape);
        } else {
            if (mShape == RECTANGLE) g2.drawRect(x, y, w, h);
            else if (mShape == OVAL) g2.drawOval(x, y, w, h);
            else if (mShape == LINE) g2.drawLine(mStart.x, mStart.y, mEnd.x, mEnd.y);
        }
        g2.setStroke(s);    
    }
}

public void doMouseDragged(MouseEvent me) {
    mEnd = me.getPoint();
    if (mStart != null) {
        mComponent = me.getComponent();
        mComponent.repaint();
        SwingUtilities.invokeLater(mRunner);
    }
}
}

      

doMouseDragged is called from mouseDragged and mouseMoved (if configured). In case it isn't obvious, what it does is redraw the messages on the component (so the component is ready to draw) and then run mRunner after. I have used this in several situations quite successfully, with the advantages that the component that MouseDragOutliner does not need to be configured (in paintComponent in particular) to be placed.

If you really can't call Component.getGraphics, can anyone suggest a better solution for this?

Thank!


http://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/ui/drag/MouseDragOutliner.java#l66

+3


source to share


1 answer


I would never want to say never. I think you just need to be aware of the downsides of using an approach that is not recommended.

The main getGrapahics()

thing about is that the picture is temporary. Whenever Swing determines that a component should be repainted, you lose the usual picture. For example, try creating a path and then lowering or increasing the frame and the path will be lost. If you use Alt + Tab to switch an application in Windows, you will also lose the picture.

I agree that in this case the user will not do something like this, but it can cause problems and lead to an error. Therefore, you need to decide whether you care about this issue or not. Who knows, maybe this is a requirement, so this isn't a big deal?



As @kiheru suggested, you can probably use the JLayer class. I don't think JLayer was part of the API when you created your code. I'm not familiar with this, but the Swing manual has a section on Responding to Events when using the JLayer class, which seems to indicate that you can do whatever you want.

When using JLayer, you cannot dynamically add functionality to any component (as your code does). You need to add functionality at design time, but I don't think that should be a problem.

+3


source







All Articles