JPanel什么时候绘制(或重绘)其子组件? [英] When does a JPanel paint (or repaint) its child components?

查看:128
本文介绍了JPanel什么时候绘制(或重绘)其子组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用自定义UI委托绘制的JButton(CustomButtonUI扩展了BasicButtonUI)。 CustomButtonUI的paint()方法绘制带有圆角抗锯齿角的按钮,使外观尽可能平滑。

I've got a JButton which is painted using a custom UI delegate (CustomButtonUI extends BasicButtonUI). The CustomButtonUI's paint() method draws the button with rounded "antialiased" corners, to make the apperance as "smooth" as possible.

不知何故,抗锯齿边缘每次我将鼠标拖到
按钮上时按钮都会消失。这使按钮边缘看起来像素化。但是,一旦我添加了一行代码来重新绘制按钮的父级,即使我将鼠标拖到按钮上,抗锯齿也会启动。

Somehow the "antialiased" edges of the button disappears each time i drag the mouse over the button. This makes the button edges look "pixelized". However, once I add a line of code to repaint the parent of the button, the antialiasing kicks in even when i drag the mouse over the button.

现在,我的问题涉及到这是一个好主意?我会从子组件重绘父组件。我想知道这是否会导致重绘的循环?如果父
尝试重新绘制其子项并且子项尝试重新绘制其父项 - 那么我假设我们正在讨论循环。

Now, my question relates to wether this is a good idea? I do after all repaint the parent component from a child component. I wonder if this lead to a loop of repaints? If the parent tries to repaint its children and the children tries to repaint its parent - then i assume we're talking about a loop.

我已经附上我的代码作为参考。非常欢迎任何评论!

I've attached my code as a reference. Any comments are very welcome!

public class JCustomButtonUI extends BasicButtonUI {

    @Override
    public void installUI(JComponent c) {
        super.installUI(c);

        AbstractButton b = (AbstractButton) c;
        b.setBorderPainted(false);
    }

    @Override
    public void paint(Graphics g, JComponent c) {

        //Cast the Graphics instance to a Graphics2D instance.
        Graphics2D g2d = (Graphics2D) g;
        JButton b = (JButton) c;

        //Repaint parent component to make sure that we get "antialiased"
        //edges.
        b.getParent().repaint();

        //Get the component's height and width.
        int w = (int) g.getClipBounds().getWidth();
        int h = ((int) g.getClipBounds().getHeight());

        //Make sure the button is drawn with "antialiased" edges.
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(Color.GRAY);
        g2d.fillRoundRect(0, 0, w, h, w, h);       
    }
}



更新1



为了说明别名和抗锯齿边框,请看下面的两张图片。当我(来自ButtonUI的paint()方法)手动调用父JPanel的重绘方法时,所有边框都是完全抗锯齿的。但是,当我不手动调用父JPanel的重绘方法时,一旦我将鼠标悬停在按钮上,边框就不再被抗锯齿了。

Update 1

Just to illustrate the alias and antialiased border, please have a look at the below two pictures. When i (from the ButtonUI's paint() method) manually invoke the parent JPanel's repaint method, all borders are perfectly antialiased all the time. However, when i do not manually invoke the parent JPanel's repaint method, then the borders are no longer antialiased once i hoover the mouse over the button.


我已经分享了整个组件,其中包含一个JPanel,一个JSlider和Snipt上的几个JButton。请从 http://snipt.org/wnllg 获取。

I have shared the entire "component" which consists of a JPanel, a JSlider and a couple of JButtons on Snipt. Please get it from http://snipt.org/wnllg.

似乎我设法让它运转起来。我没有在paintComponent()方法中绘制JPanel的背景,而是创建了一个安装在JPanel上的JCustomPanelUI。我不认为这是解决方案本身,但我没有使用Graphics实例的宽度和高度,而是尝试使用JPanel本身的widht和height。当我使用Graphics实例的宽度和高度时,我不太确定为什么出了问题。我认为Graphics实例的宽度和高度已经根据JPanel组件的尺寸进行了准备。您可以在此处查看最终组件: http://snipt.org/wnlli

It seems that i have managed to get it working. Instead of painting the JPanel's background in its paintComponent() method, i created a JCustomPanelUI which i installed on the JPanel. I don't think that was the solution itself, but instead of using width and height from the Graphics instance, I tried using widht and height from the JPanel itself. I'm not quite sure why things go wrong when i use width and height from the Graphics instance. I thought the width and height from the Graphics instance was already "prepared" with regard to dimensions from the JPanel component. You can have a look at the final component here: http://snipt.org/wnlli,

推荐答案

我已将示例简化为抗锯齿,我无法重现该问题。它似乎不依赖于平台。我不确定你为什么使用 getClipBounds()

I've reduced the example to just the anti-aliasing, and I am unable to reproduce the problem. It doesn't appear to be platform dependent. I'm not sure why you are using getClipBounds().

附录:


JPanel 背景(渐变)需要闪耀......

The JPanel background (a gradient) needs to shine through…

我更新了示例,使用透明按钮后面的渐变背景;我并排放置了反锯齿(左)和别名(右)的例子。我没有看到意外的行为。

I've update the example to use a gradient background behind a transparent button; I've put anti-aliased (left) and aliased (right) examples side-by-side. I see no unexpected behavior.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.plaf.basic.BasicButtonUI;

/** @see http://stackoverflow.com/questions/5169647 */
public class ButtonUITest extends JPanel {

    public ButtonUITest() {
        this.setLayout(new GridLayout(1, 0));
        this.setPreferredSize(new Dimension(640, 480));
        this.add(new CustomButton(true));
        this.add(new CustomButton(false));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int w = this.getWidth();
        int h = this.getHeight();
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(new GradientPaint(0, 0, Color.blue, w, h, Color.red));
        g2d.fillRect(0, 0, w, h);
    }

    private void display() {
        JFrame f = new JFrame("ButtonUITest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class CustomButton extends JButton {

        public CustomButton(boolean antialiased) {
            this.setOpaque(false);
            this.setUI(new CustomButtonUI(antialiased));
        }
    }

    private static class CustomButtonUI extends BasicButtonUI {

        private boolean antialiased;

        public CustomButtonUI(boolean antialiased) {
            this.antialiased = antialiased;
        }

        @Override
        public void paint(Graphics g, JComponent c) {
            int w = c.getWidth();
            int h = c.getHeight();
            Graphics2D g2d = (Graphics2D) g;
            if (antialiased) {
                g2d.setRenderingHint(
                    RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            }
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.fillOval(0, 0, w, 2 * h);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ButtonUITest().display();
            }
        });
    }
}

这篇关于JPanel什么时候绘制(或重绘)其子组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆