AWTUtilities.setWindowOpaque引起的字体质量问题的一种解决方案_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > AWTUtilities.setWindowOpaque引起的字体质量问题的一种解决方案

AWTUtilities.setWindowOpaque引起的字体质量问题的一种解决方案

 2011/1/11 8:56:42  003  http://003.javaeye.com  我要评论(1)
  • 摘要:上个周末,将三号管家更新到了V1.0.4,其实主要是修改了SwingC,管家本身只改了版本号。更新说明里我写的是“优化菜单字体显示”。请大家仔细观察下面的截图:这张图片是在三号管家V1.0.3中抓取的,左边是菜单有一部分超出了主界面的范围(那部分是全透明的,所以不能说人家不存在),右边是菜单全部显示在主界面区域内。很明显,左边菜单中字体的质量要差很多,这还是我在绘制的时候修改了某些参数优化过的,未经参数优化的比现在看到的效果还要差很多。为什么会这样呢
  • 标签:解决方案 解决 AWT 问题
    上个周末,将三号管家更新到了V1.0.4,其实主要是修改了SwingC,管家本身只改了版本号。更新说明里我写的是“优化菜单字体显示”。请大家仔细观察下面的截图:

    这张图片是在三号管家V1.0.3中抓取的,左边是菜单有一部分超出了主界面的范围(那部分是全透明的,所以不能说人家不存在),右边是菜单全部显示在主界面区域内。很明显,左边菜单中字体的质量要差很多,这还是我在绘制的时候修改了某些参数优化过的,未经参数优化的比现在看到的效果还要差很多。为什么会这样呢?TWaver的那位刀客在他的“Swing是一把刀”系列中曾经提到过,我在这里再说一下。可以认为这是JDK的一个bug,具体问题是:java.awt.Window及其子类如果使用com.sun.awt.AWTUtilities.setWindowOpaque(window, false)设为全透明,那么这个窗体及其下的所有子组件所显示的字体都会变得很粗糙。既然是窗体的问题,为什么会影响到菜单呢?原因就在于JPopupMenu显示的区域如果未超出其父窗体的范围,那么它是一个轻量级的JComponent,但是一旦超出了,那这个时候显示出来的实际上是一个重量级的Window。为了实现弹出菜单边框半透明的模糊效果,我重写了setVisible,如果显示的是重量级的Window,直接使用AWTUtilities.setWindowOpaque(window, false)将其置为全透明,所以字体质量就严重下降了。

    这是个很棘手的问题,我使劲的谷歌、百度一番过后,仍一无所获。TWaver的刀客采用的解决方案是在JFrame之上放一个JDialog,然后采取一些手段使它们保持同步,所以看起来仍然是一个窗体,但我这个仅仅只是弹出菜单,如果使用这个方案感觉成本太高。经过几番研究和尝试之后,发现在绘制字体的时候改改某些参数的默认值可以稍稍优化一下,不至于和正常字体的效果差太多,但终究还是有差,这也就是上面图片中大家看到的效果。心头之痛哪,但是没有更好的解决方案只能如此了。

    再然后就到了2011年的某一天,灵感突然告诉我,有个办法或许可行,于是试之,果然没让老三失望。我先把代码帖上来吧,后面再慢慢说闲话。
   
class="java">public void paint(Graphics g)
    {
        if(!buffered)
        {
            super.paint(g); 
        }
        else
        {
            Insets insets = this.getInsets();
            int x = insets.left;
            int y = insets.top;
            int width = this.getWidth();
            int height = this.getHeight();
            int contentWidth = width - insets.left - insets.right;
            int contentHeight = height - insets.top - insets.bottom;
            BufferedImage image = UIUtil.getGraphicsConfiguration(this)
				.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            BufferedImage contentImage = UIUtil.getGraphicsConfiguration(this)
				.createCompatibleImage(contentWidth, contentHeight, Transparency.OPAQUE);
            Graphics2D g2d = image.createGraphics();
            Graphics2D contentG2d = contentImage.createGraphics();
            contentG2d.translate(-x, -y);
            super.paint(g2d);
            super.paint(contentG2d);
            g2d.dispose();
            contentG2d.dispose();
            g.drawImage(image, 0, 0, this);
            g.drawImage(contentImage, x, y, this);
        }
    }

    代码很简单,创建了两个BufferedImage。注意createCompatibleImage中最后一个参数,第一张图片使用Transparency.TRANSLUCENT,这种类型的图片可以设置透明度,用它来绘制边框的半透明模糊效果,为了避免复杂的计算,直接将菜单的所有内容都绘制上去,但这种类型的图片上面显示的字体效果依然很差,所以在中间内容部分用另外一张图片来填充,前提是这张图片不能覆盖掉边框的效果,于是它的长和宽都比第一张图片小,起始位置也跳过了边框,这就是第二个BufferedImage,类型为Transparency.OPAQUE(即完全不透明,默认背景为黑色)。在这种类型的图片上绘制字体,效果与JComponent组件正常的字体完全一致,最后再将这两张图片绘制到组件上。问题就这么解决了,这也就是三号管家V1.0.4中的菜单效果。上面这段代码呢,只做讲解使用,大家如果要用的话可能还需要实际情况实际绘制,但是方法就是这么个方法,万变不离其踪。
    网友 2014/9/22 10:20:54 发表

    一般来说,AWTUtilities.setWindowOpaque引起的字体质量问题可以用如下方法解决:label.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, null);

发表评论
用户名: 匿名