JButton如何实现其图标?

时间:2016-05-11 12:21:37

标签: java swing icons jbutton

我试图了解Swings JButton / AbstractButton如何实现其图标的绘制(defaultIcon,disabledIcon,pressedIcon等)。

我在AbstractButton中找到了所有图标的字段/ getter / setter,但显然各种绘制方法都是直接从JComponent继承的。这引出了如何绘制图标的问题!?显然它们是,但我找不到代码来做它。

3 个答案:

答案 0 :(得分:3)

Swing中的组件选择由Look-n-Feel完成。因此,如果您想要查找按钮图标的绘制方式,只需查看类paintIcon的方法BasicButtonUI即可。但是你使用的每种Look-n-Feel都可以提供不同的绘画。

答案 1 :(得分:3)

JButton中的图标由UI类绘制。 UI类由外观定义。它是 javax.swing.plaf.ButtonUI 的实现。

JComponent.paint 方法从实例获取 ui 属性并调用其更新方法(并且图标被绘制的地方)。实例的UI由UIManager

获取。

您可以在Open JDK BasicButonUI

上查看绘画方法

答案 2 :(得分:0)

我希望我理解你的问题:你是否试图了解如何在JButton上绘制图标?看看JComponent(超级超类)的paint方法。我会添加注释以便于解释:

public void paint(Graphics g) {
     boolean shouldClearPaintFlags = false;

     //Check the size of the component: don't draw anything with a negative width or height!
     if ((getWidth() <= 0) || (getHeight() <= 0)) {
         return;
     }

     //Create new Graphics objects (why? to create the images)
     Graphics componentGraphics = getComponentGraphics(g);
     Graphics co = componentGraphics.create();

     try {
         RepaintManager repaintManager = RepaintManager.currentManager(this);
         //Initialize a RepaintManager (JavaDoc says: "This class manages repaint requests, allowing the number of repaints to be minimized")
         //Create a rectangle at the size of a graphics object
         Rectangle clipRect = co.getClipBounds();
         int clipX;
         int clipY;
         int clipW;
         int clipH;

         //If the rectangle is null, then give it default values
         if (clipRect == null) {
             clipX = clipY = 0;
             clipW = getWidth();
             clipH = getHeight();
         } else { //otherwise, use its coordinates
            clipX = clipRect.x;
            clipY = clipRect.y;
            clipW = clipRect.width;
            clipH = clipRect.height;
        }

        //Ajust the clip widths and heights
        if(clipW > getWidth()) {
            clipW = getWidth();
        }
        if(clipH > getHeight()) {
            clipH = getHeight();
        }
        //If your Component is placed on a JComponent (or extended class), then make adjustments
        if(getParent() != null && !(getParent() instanceof JComponent)) {
            adjustPaintFlags();
            shouldClearPaintFlags = true;
        }

        //Check if the component is printing (private flag IS_PRINTING)
        int bw,bh;
        boolean printing = getFlag(IS_PRINTING);

        //If the component is not printing its contents, and if the repain manager is double buffered, AND if not ancestor (subclass) is buffering AND if the components is buffered....
        //JavaDoc says for RepaintManager.isDoubleBufferingEnabled(): "Returns true if this RepaintManager is double buffered. The default value for this property may vary from platform to platform."
        if(!printing && repaintManager.isDoubleBufferingEnabled() &&
           !getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered()) {
            //... then start painting the Graphics
            repaintManager.beginPaint();
            try {
                repaintManager.paint(this, this, co, clipX, clipY, clipW, clipH);
            } finally {
                repaintManager.endPaint();
            }
            //if there is an exception, a try/finally is required to avoid the RepaintManager being "left in a state in which the screen is not updated" (JavaDoc)
        }
        else {
            // Will ocassionaly happen in 1.2, especially when printing.
            if (clipRect == null) {
                co.setClip(clipX, clipY, clipW, clipH);
            }

            //Checks if the rectangle at the specified coordinates if obscured
            if (!rectangleIsObscured(clipX,clipY,clipW,clipH)) {
                //Then paint the graphics (or print if printing is true)
                if (!printing) {
                    paintComponent(co);
                    paintBorder(co);
                } else {
                    printComponent(co);
                    printBorder(co);
                }
            }

            //Also paint the children (eg: a JPanel has a JLabel and a JButton as children if you add them to the panel) (or print if printing is true)
            if (!printing) {
                paintChildren(co);
            } else {
                printChildren(co);
            }
        }
    } finally {
        //Clean up!!
        co.dispose();
        if(shouldClearPaintFlags) {
            setFlag(ANCESTOR_USING_BUFFER,false);
            setFlag(IS_PAINTING_TILE,false);
            setFlag(IS_PRINTING,false);
            setFlag(IS_PRINTING_ALL,false);
        }
    }
}

换句话说,绘制Graphics对象时涉及很多代码,但是一旦分析了代码,步骤就非常简单了:

  • 从传入的参数中创建新的Graphics个对象;
  • 初始化RepaintManager以获取重绘请求;
  • 检查图形是否可以绘制,如果可能,请执行此操作;
  • 通过重新粉刷孩子来完成;
  • 你已经完成了!

如果您想了解更多关于如何应用绘画过程的信息,那么根据Oracle's Java documentation

  • 在Swing中,绘画从paint方法开始,然后调用paintComponent,paintBorder和paintChildren。当组件首次被绘制,调整大小或被另一个窗口隐藏后变为暴露时,系统将自动调用此方法。

  • 通过调用组件的重绘方法完成程序重绘。不要直接调用它的paintComponent。调用重绘会导致绘制子系统采取必要的步骤以确保在适当的时间调用paintComponent方法。

  • 您可以在同一个事件处理程序中多次调用重绘,但Swing将获取该信息并仅在一次操作中重新绘制该组件。

  • 对于具有UI委托的组件,您应该将图形参数与super.paintComponent(g)行作为paintComponent覆盖中的第一行代码传递。如果不这样做,那么您的组件将负责手动绘制其背景。您可以通过注释掉该行并重新编译来查看背景不再被绘制来进行实验。

我从here获取了代码。 我希望我能帮到你,

干杯