有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用多个重绘调用对Swing组件进行java自定义绘制

private void moveSquare(int x, int y) {
    int OFFSET = 1;
    if ((squareX!=x) || (squareY!=y)) {
        repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
        squareX=x;
        squareY=y;
        repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
    } 
}

在上面的代码中(完整的代码可以在“执行自定义绘制”Java教程的Demo App中找到),第一个repaint方法应该在前一个正方形的位置绘制一个正方形,第二个repaint应该在新正方形的位置绘制另一个正方形。但这实际上并没有发生。取而代之的是,前一个方块消失了,新的方块被粉刷了

当前一个广场消失时,新广场是如何被粉刷的


共 (3) 个答案

  1. # 1 楼答案

    您链接以回答问题的文档,至少在一般情况下:

    although we have invoked repaint twice in a row in the same event handler, Swing is smart enough to take that information and repaint those sections of the screen all in one single paint operation.

    当您调用repaint时,实际上您还没有绘制任何东西,而是请求在将来某个时间重新绘制

    虽然^{} JavaDoc没有详细说明,但它包含一个指向“Painting in AWT and Swing”的链接,该链接在“Paint Processing”部分中包含两个案例,第二个案例适用于此处:

    (B) [When the] paint request originates from a call to repaint() on an extension of javax.swing.JComponent:

    JComponent.repaint() registers an asynchronous repaint request to the component's RepaintManager, which uses invokeLater() to queue a Runnable to later process the request on the event dispatching thread.

    在这一节的后面:

    NOTE: if multiple calls to repaint() occur on a component or any of its Swing ancestors before the repaint request is processed, those multiple requests may be collapsed into a single call back to paintImmediately() [...]

    当事件处理程序返回时,JPanel的某些部分将被标记为重新绘制,可能是全部。这些区域被称为“脏区域”。Swing(最终)一次(并且仅一次)重新绘制所有脏区域。此绘制发生在事件处理程序返回后(即JPanel的外观已更改后),因此彩色方形显示在其新位置,而在其旧位置没有任何“剩余”

    简言之,不要认为repaint是“立即重新绘制此区域”,而是“稍后将此区域添加到要绘制的内容列表中”

  2. # 2 楼答案

    Oracle docs给出了很好的解释: moveSquare方法调用repait方法不是一次,而是两次。第一个调用告诉Swing重新绘制组件的区域,该区域以前是正方形(继承的行为使用UI委托使用当前背景色填充该区域)第二个调用绘制当前正方形所在的组件区域

  3. # 3 楼答案

    调用repaint()后,它不会立即重新绘制组件。但它添加了在EDT的事件队列中再次绘制组件的请求

    每个代码行中发生的情况如下所示

    repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
    

    标记将要重新绘制的正方形(squareX,squareY,squareW+OFFSET,squareH+OFFSET)所包围的区域。但是直到RepaintManager重新绘制之前,它不会被重新绘制

    squareX=x;
    squareY=y;
    

    更改squareXsquareY的值。但它不会更改要重新绘制的早期标记区域。现在,要重新绘制的区域也是以前的值

    repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
    

    标记将要重新绘制的正方形(squareX,squareY,squareW+OFFSET,squareH+OFFSET)所包围的区域。现在有两部分需要重新绘制。旧广场和新广场。但是直到RepaintManager重新绘制之前,它不会被重新绘制

    最后,当时机成熟时,RepaintManager绘制组件

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);       
        g.drawString("This is my custom Panel!",10,20);
        g.setColor(Color.RED);
        g.fillRect(squareX,squareY,squareW,squareH);
        g.setColor(Color.BLACK);
        g.drawRect(squareX,squareY,squareW,squareH);
    } 
    

    现在,该组件仅绘制了2个区域。(以前的广场和新广场)但红场将仅在新广场内绘制。在老广场上没有什么可画的。所以以前画的东西会被抹掉

    实际上,尽管有两个方法调用repaint(),但paintComponents()将只调用一次。要重新绘制的总面积由RepaintManager处理,paintComponents()只调用一次