打电话给 Component.getGraphics 真的不行吗?

Is it truly never okay to call Component.getGraphics?

MadProgrammer 发表评论 指出你永远不应该使用 Component.getGraphics,我通常同意这一点:在几乎所有情况下,它都是错误的。

但以我多年前创建的 class 为例。我正在发布我认为是相关代码的内容。你可以找到完整的代码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 从 mouseDragged 和 mouseMoved(当配置为)调用。如果不是很明显,它所做的是在组件上调用重绘(因此组件已准备好在其上绘制),然后 运行 之后的 mRunner。我已经在许多情况下非常成功地使用了它,其好处是 MouseDragOutliner 不需要任何自定义(特别是在 paintComponent 中)来容纳的组件。

如果调用 Component.getGraphics 真的永远不可能,有人可以为此提出更好的解决方案吗?

谢谢!


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

我从来不喜欢说永远。我认为您只需要了解使用不推荐的方法时的缺点。

关于getGrapahics()的要点是,这幅画只是暂时的。每当 Swing 确定组件需要重新绘制时,您将丢失自定义绘制。例如,尝试创建轮廓,然后最小化或最大化框架,轮廓将丢​​失。如果你在Windows中使用Alt+Tab切换应用程序你也会丢掉这幅画。

我同意在这种情况下,用户做那样的事情的可能性不大,但它可能会导致问题并导致错误报告。所以你需要决定你是否关心这个问题。谁知道,也许这是一项要求,所以没什么大不了的?

正如@kiheru 所建议的,您或许可以使用 JLayer class。当您创建代码时,我认为 JLayer 不是 API 的一部分。我不太熟悉它,但是 Swing 教程中有一段关于使用 JLayer class 时的 Responding to Events,这似乎表明你可以做你想做的事。

使用 JLayer 时,您无法将功能动态添加到任何组件(您的代码的方式)。您需要在设计时添加功能,但我认为这不是问题。