Java频繁重绘具有过高的CPU使用率

时间:2018-03-06 16:49:27

标签: java swing cpu-usage

所以我写了一个类,它绘制了一个具有一定透明度的透明盒子。只要将鼠标悬停在它上面,透明度就会改变(父组件使用setTransparency(浮动透明度)),但是当更改透明度时,CPU会从~2%上升到~40%CPU使用率。它在变化后再次下降,但这不应该发生,因为当你快速盘旋在几个组件上时它会变得更糟......

这是我写的TransparentBox类的代码:

public class TransparentBox extends JComponent{

private static final long serialVersionUID = 1L;

private Color color = Color.WHITE;
private int borderRadius = 0;
private float transparency = 0.85f;

public TransparentBox(Color color) {
    this.color = color;
}

public Color getColor() {
    return color;
}

public void setColor(Color color) {
    this.color = color;
}

public void setTransparency(float transparency) {
    this.transparency = transparency;
    repaint();
}

public float getTransparency() {
    return transparency;
}

public int getBorderRadius() {
    return borderRadius;
}

public void setBoderRadius(int borderRadius) {
    this.borderRadius = borderRadius;
    repaint();
}

@Override
protected void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING   , RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int alphaType = AlphaComposite.SRC_OVER;
    AlphaComposite composite = (AlphaComposite.getInstance(alphaType, transparency));
    g2d.setComposite(composite);
    g2d.setColor(color);
    g2d.fillRoundRect(0, 0, getWidth(), getHeight(), borderRadius, borderRadius);
}
}

我检查了循环或可能减慢它的东西,但我什么都没发现,我也查了一下,但找不到任何东西。经过大量的调试和寻找原因,我100%确定这些组件会导致高CPU使用率。

为了重新创建问题,我很快就创建了一个例子,你应该看到CPU上升,但可能不会达到40%,因为我的实际应用程序要大一些,但是重绘还是会扼杀性能。

public static void main(String[] args){
    JFrame newFrame = new JFrame("Demo");
    newFrame.setSize(new Dimension(900, 700));
    newFrame.setVisible(true);
    newFrame.getContentPane().setLayout(null);
    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    LeatherPanel content = new LeatherPanel();
    content.setLayout(null);
    content.setBounds(0, 0, newFrame.getWidth(), newFrame.getHeight());

    newFrame.getContentPane().add(content);

    LoginMenu lm = new LoginMenu();
    lm.setBounds((newFrame.getWidth()-780)/2, (newFrame.getHeight()-430)/2, 780, 430);
    content.add(lm);

    lm.update();
}

这是LoginMenu类

public class LoginMenu extends JComponent{

private static final long serialVersionUID = 1L;
private TransparentBox content = null;
private TransparentBox backButton = null;
private TransparentBox loginButton = null;
private JLabel currentIcon = null;
private JLabel currentUserName = null;
private JPasswordField passField = null;
private JPanel user_panel = null;
private JScrollPane user_scroll = null;
private int currentIconID = 0;
private String currentName = "NA";
private boolean userSelected = false;

public LoginMenu() {
    content = new TransparentBox(Color.BLUE);
    content.setBoderRadius(15);
    setLayout(null);

    user_panel = new JPanel();
    user_panel.setOpaque(false);
    user_panel.setLayout(null);
    user_panel.setBorder(BorderFactory.createEmptyBorder());

    user_scroll = new JScrollPane(user_panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    user_scroll.getVerticalScrollBar().setPreferredSize(new Dimension(0,0));
    user_scroll.setOpaque(false);
    user_scroll.setBorder(BorderFactory.createEmptyBorder());
    user_scroll.getViewport().setOpaque(false);
    user_scroll.getVerticalScrollBar().setUnitIncrement(CoreData.INCREMENT_UNIT);

    passField = new JPasswordField();
    passField.setFont(new Font("Calibri", Font.PLAIN, 20));
    passField.setForeground(Color.GRAY);
    backButton = new TransparentBox(Color.BLUE);
    loginButton = new TransparentBox(Color.BLUE);
}

public void update() {
    content.setBounds(0, 0, getWidth(), getHeight());
    add(content);

    content.removeAll();

    content.repaint();
    content.revalidate();

    if(!userSelected) {
        user_panel.removeAll();
        int x = 5;
        int h = 5;
        String[] users = {"Test","Test","Test","Test"}; 
        for(String usr : users) {
            UserComponent uc = new UserComponent(usr, null);
            uc.setBounds(x, h, 380, 90);
            uc.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    currentName = usr;
                    currentIconID = null;
                    userSelected = true;
                    update();
                }
            });
            user_panel.add(uc);
            uc.update();
            x += 390;
            if(x >= getWidth()-310) {
                x = 5;
                h += 100;
            }
        }
        h += 100;

        user_panel.setPreferredSize(new Dimension(getWidth()-10, h));

        user_scroll.repaint();
        user_scroll.revalidate();

        user_scroll.setBounds(0, 0, getWidth(), getHeight());
        content.add(user_scroll);   
    }else {
        currentIcon.setBounds((getWidth()-90)/2, 40, 90, 90);

        currentUserName = new JLabel(currentName);
        currentUserName.setFont(new Font("Calibri", Font.PLAIN, 38));
        currentUserName.setForeground(Color.WHITE);
        currentUserName.setHorizontalAlignment(SwingConstants.CENTER);
        currentUserName.setBounds(20, 130, getWidth()-40, 42);
        content.add(currentUserName);

        passField.setText("");
        passField.setHorizontalAlignment(SwingConstants.CENTER);
        passField.requestFocus();
        passField.setBounds(20, getHeight()-202, getWidth()-40, 64);
        content.add(passField);

        backButton.setBounds(20, getHeight()-124, 64, 64);
        backButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                userSelected = false;
                update();
            }
            @Override
            public void mouseEntered(MouseEvent e) {
                backButton.setTransparency(0.6f);
            }
            @Override
            public void mouseExited(MouseEvent e) {
                backButton.setTransparency(0.85f);
            }
        });
        content.add(backButton);

        loginButton.setBounds(getWidth()-84, getHeight()-124, 64, 64);
        loginButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                loginButton.setTransparency(0.6f);
            }
            @Override
            public void mouseExited(MouseEvent e) {
                loginButton.setTransparency(0.85f);
            }
        });
        content.add(loginButton);

        JLabel backArrow = new JLabel("<");
        backArrow.setFont(new Font("Calibri", Font.PLAIN, 24));
        backArrow.setForeground(Color.WHITE);
        backArrow.setHorizontalAlignment(SwingConstants.CENTER);
        backArrow.setBounds(0, 0, 64, 64);
        backButton.add(backArrow);

        JLabel loginArrow = new JLabel(">");
        loginArrow.setFont(new Font("Calibri", Font.PLAIN, 24));
        loginArrow.setForeground(Color.WHITE);
        loginArrow.setHorizontalAlignment(SwingConstants.CENTER);
        loginArrow.setBounds(0, 0, 64, 64);
        loginButton.add(loginArrow);
    }
}
}

LeatherPanel类

public class LeatherPanel extends JComponent{

private static final long serialVersionUID = 1L;

@Override
protected void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING   , RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.setColor(Color.WHITE);
    g.fillRect(x,y,getWidth(),getHeight());
}

}

最后是UserComponent类

public class UserComponent extends JComponent implements MouseListener{

private static final long serialVersionUID = 1L;

private JLabel userLabel = null;
private JLabel userIcon = null;
private TransparentBox content = null;

public UserComponent(String user, int user_icon_id) {
    userLabel = new JLabel(user);
    userLabel.setFont(new Font("Calibri", Font.PLAIN, 30));
    userLabel.setForeground(Color.WHITE);
    userLabel.setHorizontalAlignment(SwingConstants.LEFT);

    userIcon.setBounds(5, 13, 64, 64);

    setLayout(null);
    addMouseListener(this);

    content = new TransparentBox(Color.WHITE);
    content.setTransparency(0.0f);

    add(content);
    add(userIcon);
    add(userLabel);
}

public void update() {
    content.setBounds(0, 0, getWidth(), getHeight());
}

@Override
public void mouseEntered(MouseEvent e) {
    content.setTransparency(0.2f);
}

@Override
public void mouseExited(MouseEvent e) {
    content.setTransparency(0.0f);
}

@Override
public void mouseClicked(MouseEvent e) {}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

}

1 个答案:

答案 0 :(得分:0)

如果我不得不猜测,我会说问题出在更新方法上:

public void update() {
    content.setBounds(0, 0, getWidth(), getHeight());
    add(content);

    content.removeAll();

    content.repaint();
    content.revalidate();

    if(!userSelected) {
        user_panel.removeAll();
        int x = 5;
        int h = 5;
        String[] users = {"Test","Test","Test","Test"};
        for(String usr : users) {
//            UserComponent uc = new UserComponent(usr, null);
            UserComponent uc = new UserComponent(usr, 1);
            uc.setBounds(x, h, 380, 90);
            uc.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    currentName = usr;
//                    currentIconID = null;
                    currentIconID = 1;
                    userSelected = true;
                    update();
                }
            });
            user_panel.add(uc);
            uc.update();
            x += 390;
            if(x >= getWidth()-310) {
                x = 5;
                h += 100;
            }
        }

在mousePressed()方法中,您可以调用update()方法。所以在我看来,当你不断更换组件并创建新的监听器时,你可以继续使用某种循环逻辑。

然后,您可以从我看到的内容中调用用户面板上的update()。

所以我建议你需要添加一些调试代码来查看哪些方法继续执行。我想某种程度上你是在一个与透明度无关的循环中,而是你删除/添加组件的方式。