JPanel闪烁

时间:2014-09-04 23:17:23

标签: java swing jframe rendering

目前我正在使用自定义JFrame创建自定义JPanel。渲染JFrame没有闪烁,但是当我渲染自定义`JPanel时,组件闪烁。我的代码:

我的代码JFrame

    public void paint(Graphics g) {
    Dimension d = getSize();
    Graphics og = g;
    g = b.getGraphics();
    //background
    g.setColor(SConstants.ct.FRAME_BACKGROUND());
    g.fillRect(SConstants.ct.FRAME_FRAME_WIDTH(), SConstants.ct.FRAME_FRAME_HEIGHT(), d.width - SConstants.ct.FRAME_FRAME_WIDTH(), d.height - SConstants.ct.FRAME_FRAME_WIDTH());

    //frame
    if(isFocused()){
        g.setColor(SConstants.ct.FRAME_FOCUSED_FRAME());
    }else{
        g.setColor(SConstants.ct.FRAME_UNFOCUSED_FRAME());
    }
    //top
    g.fillRect(0, 0, d.width, SConstants.ct.FRAME_FRAME_HEIGHT());
    //left
    g.fillRect(0, 0, SConstants.ct.FRAME_FRAME_WIDTH(), d.height);
    //bottom
    g.fillRect(0, d.height - SConstants.ct.FRAME_FRAME_WIDTH(), d.width, SConstants.ct.FRAME_FRAME_WIDTH());
    //right
    g.fillRect(d.width - SConstants.ct.FRAME_FRAME_WIDTH(), 0, SConstants.ct.FRAME_FRAME_WIDTH(), d.height);

    //icon
    if(getIconImage() != null)
        g.drawImage(getIconImage(), 15, SConstants.ct.FRAME_FRAME_HEIGHT() / 2 - getIconImage().getHeight(null) / 2, null);

    Graphics2D g2d = (Graphics2D) g;
    g2d.setFont(SConstants.ct.FRAME_FONT());
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setColor(Color.BLACK);
    g2d.drawString(getTitle(), d.width / 2 - g2d.getFontMetrics().stringWidth(getTitle()) / 2, SConstants.ct.FRAME_FRAME_HEIGHT() / 2 - g2d.getFontMetrics().getHeight() / 2 + g2d.getFontMetrics().getAscent());
    getContentPane().paint(og);
    og.drawImage(b, 0, 0, null);
}

我正在设置contentPane,如下所示:

getRootPane().setLayout(null);
    SPanel cp = new SPanel();
    cp.setBounds(SConstants.ct.FRAME_FRAME_WIDTH(), SConstants.ct.FRAME_FRAME_HEIGHT(), getWidth() - SConstants.ct.FRAME_FRAME_WIDTH() * 2, getHeight() - SConstants.ct.FRAME_FRAME_HEIGHT() - SConstants.ct.FRAME_FRAME_WIDTH());
    setContentPane(cp);

SPanel是这样的:

public void paint(Graphics g) {
    paintComponent(g);
}

protected void paintComponent(Graphics g) {
//paintComponents(g);
    for(Component c : getComponents())
        c.paint(g);
}

我正在渲染一个SLabel

public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.drawString(text, getX() + SConstants.ct.LABEL_SPACING_HORIZONTAL(), getY());
}

public Dimension getPreferredSize() {
    Rectangle2D d = getGraphics().getFontMetrics(SConstants.ct.LABEL_FONT()).getStringBounds(text, getGraphics());
    int w = (int)(d.getWidth() + SConstants.ct.LABEL_SPACING_HORIZONTAL() * 2);
    int h = (int)(d.getHeight() + SConstants.ct.LABEL_SPACING_VERTICAL() * 2);
    return new Dimension(w, h);
}

可运行的示例:https://drive.google.com/file/d/0B8czlxc22-xqOHlPdUZxV2dkMjQ/edit?usp=sharing

有人知道为什么SLabel会闪烁吗?

1 个答案:

答案 0 :(得分:4)

您似乎无法理解Swing的工作原理或Swing / AWT中的绘画效果......

SMAIN ...

此...

public class SMain {

    public static void main(String[] args) throws Exception {
        //...
        while(true){
            sf.repaint();
            Thread.sleep((int)(1000.0 / 24.0));
        }
    }
}

是个坏主意... Swing使用被动渲染模型,这意味着更新会在需要时发生,因为您似乎没有对UI的状态进行更改,这只是添加对你的系统施加更大的压力。

如果调用正确,也可以阻止您的UI永久更新。


SFrame ...

getRootPane().setLayout(null);

为什么呢?为什么? JRootPane拥有自己的布局管理流程,可确保contentPane提供包含框架内的所有空间减去菜单栏的空间(如果提供),您不会提供了,是的,默认实现将允许contentPane占用所有可用空间......

setSize可能会连续多次调用,最好只是将b无效(将其设置为null)并仅在需要时创建它(当paint被称为),但这引出了为什么?

的问题

为什么不让内容窗格为您执行此操作...

pack会自动调整contentPane的大小,如果你真的让JRootPane做它的工作......

paint完成了许多重要的工作,而且你已经规避了大部分工作,这将导致你无法解决问题和结果....

例如,在尝试绘制内容窗格之前,您没有翻译Graphics上下文,这意味着内容绘制的内容可能会覆盖什么内容你画了(即标题)。

你最好使用......

  • 内容窗格原样,将标题添加到BorderLayout.NORTH位置,其余内容包含在另一个容器中BorderLayout.CENTER默认位置contentPane
  • 使用单独的标题和内容组件实现您自己的JRootPane以提供所需的布局
  • JFrame实现自己的外观代理并自行绘制边框
  • 使用EmptyBorder上的contentPane为标题提供空间......
  • 其他任何事情,然后你做了什么......

请注意,MouseListenerMouseMotionListener可能被容器层次结构中较高的组件阻止,这些组件实现其中一个或两个接口


SPANEL ...

paint做了很多重要的工作,包括但不限于绘制组件,边框和组件(以及实现双缓冲),但是你决定绕过它们并且做你自己的事......

paintComponent假设绘制组件的背景,而不是它的孩子。这已由paintpaintChildren以及paintComponents

完成

子组件也可以独立于其父级绘制......


S-分量...

请注意,Component是一个重量级(AWT)组件,它的绘画要求与轻量级(Swing)组件的要求不同,事实上,您应该避免添加重量轻的组件以减轻重量容器....

Component已定义paint(Graphics) ...

默认情况下,重量级组件也不是双缓冲的...这意味着更新可能会导致闪烁...因此您的问题......

"但我已经双重缓冲框架" ...抱歉让你失望,但组件可以并且通常是独立于父母绘制的,因此它们可能不会被绘制为部分父母的更新...


结论...

你似乎并不了解绘画在AWT / Swing中是如何运作的。请查看Painting in AWT and Swing了解更多详情......

您似乎也不了解Swing和AWT之间的差异。虽然Swing位于AWT之上,但它有自己的框架要求,这与AWT和一些有意义的方式不同......

您似乎正在尝试实现自己的框架......为什么,我不知道,显然在Swing和AWT上最近20多年的开发还不够好或者什么......

您可以考虑查看Modifying the Look and Feel并使用UI委托API来实现您要执行的操作...

你有两个选择,你可以学习理解当前框架(Swing / AWT)如何工作并在其中工作以实现你的目标,或者在你的余生中度过追逐怪异,无法解释的问题和错误。

您还可以考虑查看JavaFX,它允许您通过CSS修改外观...