当前位置: 首页 > 知识库问答 >
问题:

JScrollPane中的JPanel绘制问题

任长卿
2023-03-14

我已经在JScrollPane中放置了一个JPanel对象,滚动工作就像预期的那样。通过重写paintComponent(),我尝试在JPanel对象中进行自定义绘制。然而,当JPanel对象放置在JScrollPane中时,JPanel不再正确地绘制(而是只显示其背景颜色)。

因为我的应用程序要求JPanel不断更新,所以构造了一个单独的线程,以在特定的时间间隔重新绘制JPanel。

以下代码摘录显示了我当前的项目:

a)来自我的JPanel的paintComponent()(此方法已被削减为只有绘画,实际的绘画将是一个不断更新的BufferedImage,由另一个线程提供,而不是这个粉红色的大静态框):

@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);

    //Render Frame
    // 'RXDisplayCanvas' is the JPanel.
    Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics();

    G2D.setColor(Color.PINK);
    //800 and 600 are arbitrary values for this example, real values are calculated at runtime. The value calculation code is verified to work (as its used elsewhere in a similar scenario)
    G2D.fillRect(0, 0, 800, 600);
    G2D.dispose();
}

b)定期重新绘制帧的“更新器”线程:

@Override
public void run() {
    long MaxFrameTime;
    long Time;

    while(isVisible()){
        // 'FPSLimit' is a integer value (default to 30)
        MaxFrameTime = Math.round(1000000000.0 / FPSLimit);
        Time = System.nanoTime();

        try{
            SwingUtilities.invokeAndWait(new Runnable(){
                @Override
                public void run() {
                    // 'RXDisplayCanvas' is the JPanel.
                    RXDisplayCanvas.repaint(); //When using this, the JPanel does not display correctly.

                    //RXDisplayCanvas.paintImmediately(0, 0, RXDisplayCanvas.getWidth(), RXDisplayCanvas.getHeight()); When using this, the JPanel renders correctly but flickers.
                }
            });
        }catch(InterruptedException | InvocationTargetException e){}

        Time = System.nanoTime() - Time;
        if(Time < MaxFrameTime){
            try{
                Thread.sleep(Math.round((MaxFrameTime - Time)/1000000.0));
            }catch(InterruptedException ex){}
        }
    }
}

我已经考虑到repaint()不会立即重新绘制屏幕,但问题在于屏幕的不正确呈现。当程序单独运行时,它只呈现JPanel的背景颜色,直到JScrollPane滚动,在其中它正确呈现一帧,然后下一个repaint()调用绘制不正确的显示。

当将repaint()切换为paintimedialty()(在节选b中)时,框架呈现正确,但存在严重的闪烁,它不断地在绘制背景色和绘制粉红色框之间交替。我已经尝试添加和删除布局管理器,禁用重绘管理器,以及为两个组件启用和禁用‘双缓冲’标志,所有这些都导致了上面提到的两种行为之一(只呈现背景或闪烁)。

在这个问题上有人能帮我吗?

注:我很清楚Java的变量命名惯例,因为这是一个私人项目,我选择用大写字母开头的变量名,因为我觉得这样看起来更好,请不要发表评论。

共有1个答案

桂宏旷
2023-03-14

1)我不确定这一点:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    // 'RXDisplayCanvas' is the JPanel.
    Graphics2D G2D = (Graphics2D)RXDisplayCanvas.getGraphics();
    ..
    G2D.dispose();
}

我建议这样做:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    Graphics2D G2D = (Graphics2D)g;
    G2D.setColor(Color.PINK);
    G2D.fillRect(0, 0, 800, 600);
}

注意我是如何省略getGraphics,而使用PaintComponent的当前图形上下文传递的。

还请注意,我不调用g2d.dipose(),因为这会导致问题,它只应该在graphic上执行,您创建了component.getGraphics(),但在您的情况下,您甚至不应该创建graphic的上下文,因为它已经创建并传递给了paintComponent方法。(参见此类似问题)

2)不需要repaint()SwingUtilities.InvokExxx块,因为它是线程安全的。但特别是不需要SwingUtilites.InvokeAndWait(因为这是一个阻塞调用,并等待直到所有挂起的AWT事件得到处理并且run()方法完成),这是不好的,而且可能会添加到您看到的屏幕可视伪影。

3)我试过添加和删除布局管理器,禁用重绘管理器,以及为两个组件启用和禁用‘双缓冲’标志,所有这些都导致了上面提到的两种行为之一(只呈现背景或闪烁)。撤销所有这些,因为我看不出这对绘画有何影响。

如果我有一个SSCCE来说明不想要的行为,那会更有帮助。因为我可以尝试重现您的错误,但我很可能无法(由于应用于您的应用程序的特定条件,可能导致这些视觉伪影)

 类似资料:
  • 问题内容: 我有一个JFrame,在这个JFrame中,我有一个绘制的JPanel,此Panel可以是任何大小,因此我将其放在JScrollpane中,以便当面板大于窗口屏幕大小时可以滚动。 不幸的是,它没有按我预期的那样工作: 使JFrame窗口小于JPanel大小不会显示滚动条 现在,JScrollPane的大小似乎已锁定为我添加到其中的JPanel的大小,就像以前一样,它的大小已调整为JFr

  • 首先,我要说,我几乎可以保证这个问题是一个副本,但我找不到任何其他适合我的需要/在我的程序中工作的答案。我需要画一个,但我似乎无法画出显示所需的线条。 在我的中添加有什么问题吗?

  • 我使用子JPanel构造JScrollPane,然后尝试将JScrollPane添加到父JPanel中,希望有一个可滚动的自定义JPanel。 我有一个大的细白线前面的所有我的组件,他们是没有滚动。有什么想法吗?

  • 我想在我的基本框架中添加一个带有JPanel的JScrollpane 如果我将带有的直接添加到中,就可以了。但是现在,当我将帧的大小减小到500像素以下时,变得更小,如第二张图片所示。 如何使JScrollPane工作?

  • 所以,我正在制作一种文本编辑器,我需要一个用于垂直导航的JScrollPane。但我不能让它工作。 我已经阅读了谷歌搜索结果前十页上的每一篇奇怪的教程,但我无法让它发挥作用。 假设我有JFrame(尺寸1000x800)。我想在其中放置一个JPanel(1000x2000),以便它与JFrame水平对齐。我想在JPanel的右侧粘贴一个简单的滚动条,这样就可以访问它的其余部分。 我减少了大小,我将

  • 问题内容: 我如何告诉paint方法仅在JPanel上而不是在整个JFrame上绘制背景。我的JFrame大小大于JPanel。当我尝试为JPanel绘制网格背景时,网格似乎遍及整个JFrame,而不仅仅是JPanel。 以下是部分代码: 问题答案: camickr是正确的。所以: 您需要严格将工程图与不同组件分开。Swing已经在管理子组件,因此绝对不需要在Panel的Frame中实现图形(调用