/* * Copyright (C) 2015 Jack Jiang(cngeeker.com) The BeautyEye Project. * All rights reserved. * Project URL:https://github.com/JackJiang2011/beautyeye * Version 3.6 * * Jack Jiang PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * BEToolBarUI.java at 2015-2-1 20:25:41, original version by Jack Jiang. * You can contact author with [email protected] */ package org.jb2011.lnf.beautyeye.ch8_toolbar; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Stroke; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import javax.swing.AbstractButton; import javax.swing.JComponent; import javax.swing.JToolBar; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicToolBarUI; import org.jb2011.lnf.beautyeye.ch3_button.BEButtonUI; import org.jb2011.ninepatch4j.NinePatch; /** * JToolBar的UI实现类。 * * <p><b>Since v3.4:</b><br> * 可以使用"ToolBar.isPaintPlainBackground"来控制BEToolBarUI还是 * 默认的渐变NinePatch图实现背景的填充(效果好,但是背景比较强烈,不适于组件密集的场景). * 全局控制可以通过UIManager.put("ToolBar.isPaintPlainBackground", Boolean.FALSE)(UIManager中默认是false) * 或者通过JToolBar.putClientProperty("ToolBar.isPaintPlainBackground", Boolean.FALSE) * 独立控制,ClientProperty中的设置拥有最高优先级。 * * @author Jack Jiang([email protected]) */ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 一些说明 Start //本类实现代码参考了WindowsToolBarUI。 //特别说明:JToolBar比较特殊,加入到JToolBar中的组件,其UI(主要是Border)将由ToolBarUI额 //外控制而不受自身UI控制,比如放入到JToolBar中的JToggleButton,它的border就是受ToolBarUI //控制,这些JToggleButton将无论如何修改ToolgleButtonUI.border也不会起效。 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 一些说明 END public class BEToolBarUI extends BasicToolBarUI implements org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.__UseParentPaintSurported { /** * Creates the ui. * * @param c the c * @return the component ui */ public static ComponentUI createUI(JComponent c) { return new BEToolBarUI(); } /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicToolBarUI#installDefaults() */ protected void installDefaults() { // if (XPStyle.getXP() != null) { setRolloverBorders(true); } super.installDefaults(); } //* 本方法由Jack Jiang于2012-09-07日加入 /** * 是否使用父类的绘制实现方法,true表示是. * <p> * 因为在BE LNF中,工具条背景是使用N9图,没法通过设置背景色和前景 * 色来控制工具条的颜色,本方法的目的就是当用户设置了工具条的Background * 时告之本实现类不使用BE LNF中默认的N9图填充绘制而改用父类中的方法(父类中的方法 * 就可以支持颜色的设置罗,只是丑点,但总归是能适应用户的需求场景要求,其实用户完全可以 * 通过JToolBar.setUI(new MetalToolBar())等方式来自定义UI哦). * * @return true, if is use parent paint */ public boolean isUseParentPaint() { return toolBar != null && (!(toolBar.getBackground() instanceof UIResource)); } /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicToolBarUI#createRolloverBorder() */ protected Border createRolloverBorder() { return new EmptyBorder(3, 3, 3, 3); } /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicToolBarUI#createNonRolloverBorder() */ protected Border createNonRolloverBorder() { return new EmptyBorder(3, 3, 3, 3); } /* (non-Javadoc) * @see javax.swing.plaf.ComponentUI#paint(java.awt.Graphics, javax.swing.JComponent) */ public void paint(Graphics g, JComponent c) { //~* @since 3.4, add by Jack Jiang 2012-11-05 //~* 【BeautyEye外观的特有定制属性】:true表示BEToolBarUI里,将使用其它典型外观 //~* 一样的默认纯色填充背景(颜色由ToolBar.background属性指定), 否则将使用BeautyEye //~* 默认的渐变NinePatch图实现背景的填充。另外,还可以使用 //~* JToolBar.putClientProperty("ToolBar.isPaintPlainBackground", Boolean.TRUE);来进行 //~* 独立控制背景的填充方法,ClientProperty相比UIManager中的本方法拥有最高优先级 boolean isPaintPlainBackground = false; String isPaintPlainBackgroundKey = "ToolBar.isPaintPlainBackground";//~* 【BeautyEye外观的特有定制属性】@since 3.4 //首先看看有没有独立在ClientProperty中设置"ToolBar.isPaintPlainBackground"属性(ClientProperty中设置拥有最高优先级) Object isPaintPlainBackgroundObj = c.getClientProperty(isPaintPlainBackgroundKey); //如果ClientProperty中没有设置,则尝试取UIManager中的该属性默认值 if(isPaintPlainBackgroundObj == null) isPaintPlainBackgroundObj = UIManager.getBoolean(isPaintPlainBackgroundKey); if(isPaintPlainBackgroundObj != null) isPaintPlainBackground = (Boolean)isPaintPlainBackgroundObj; //* 如果用户作了自定义颜色设置则使用父类方法来实现绘制,否则BE LNF中没法支持这些设置哦 if(isPaintPlainBackground || isUseParentPaint()) { super.paint(g, c); } else { //* 根据工具条所放在父类的位置不同来决定它的背景该使用哪个图片(图片的差别在于方向不同,主要是边缘阴影的方向) NinePatch np = __Icon9Factory__.getInstance().getToolBarBg_NORTH(); //int orientation = toolBar.getOrientation(); Container parent = toolBar.getParent(); if(parent != null) { LayoutManager lm = parent.getLayout(); if(lm instanceof BorderLayout) { Object cons = ((BorderLayout)lm).getConstraints(toolBar); if(cons != null) { if(cons.equals(BorderLayout.NORTH)) np = __Icon9Factory__.getInstance().getToolBarBg_NORTH(); else if(cons.equals(BorderLayout.SOUTH)) np = __Icon9Factory__.getInstance().getToolBarBg_SOUTH(); else if(cons.equals(BorderLayout.WEST)) np = __Icon9Factory__.getInstance().getToolBarBg_WEST(); else if(cons.equals(BorderLayout.EAST)) np = __Icon9Factory__.getInstance().getToolBarBg_EAST(); } } } np.draw((Graphics2D)g, 0, 0, c.getWidth(), c.getHeight()); } } /** * Gets the rollover border. * * @param b the b * @return the rollover border * {@inheritDoc} * @since 1.6 */ protected Border getRolloverBorder(AbstractButton b) { return new BEButtonUI.XPEmptyBorder(new Insets(3,3,3,3));//xp.getBorder(b, WindowsButtonUI.getXPButtonType(b)); } //* 由jb2011修改,只加了一行代码哦 /** * 重写父类方法实现自已的容器监听器. * 自定义的目的就是为了把加入到其中的组件设置为透明,因为BE LNF的工具栏是有背景,否则 * 因有子组件的背景存在而使得整体很难看. * * @return the container listener */ @Override protected ContainerListener createToolBarContListener( ) { return new ToolBarContListenerJb2011(); } //* 由jb2011修改自父类的Handler里的ContainerListener监听代码 /** * The Class ToolBarContListenerJb2011. */ protected class ToolBarContListenerJb2011 implements ContainerListener { // // ContainerListener // /* (non-Javadoc) * @see java.awt.event.ContainerListener#componentAdded(java.awt.event.ContainerEvent) */ public void componentAdded(ContainerEvent evt) { Component c = evt.getChild(); if (toolBarFocusListener != null) { c.addFocusListener(toolBarFocusListener); } if (isRolloverBorders()) { setBorderToRollover(c); } else { setBorderToNonRollover(c); } //## Bug FIX:Issue 51(https://code.google.com/p/beautyeye/issues/detail?id=51) //* 由Jack Jiang201210-12日注释掉:它样做将导致各种放入的组 //* 件(如文本框)等都将透明,从而不绘制该 组件的背景,那就错误了哦 //* 其实以下代码原本是为了解决放入到JToggleButton的白色背景问题,现在它 //* 已经在BEToolgleButtonUI里解决了,此处就不需要了,也不应该要! // //* 只有它一行是由jb2011加的 // if(c instanceof JComponent) // ((JComponent)c).setOpaque(false); } /* (non-Javadoc) * @see java.awt.event.ContainerListener#componentRemoved(java.awt.event.ContainerEvent) */ public void componentRemoved(ContainerEvent evt) { Component c = evt.getChild(); if (toolBarFocusListener != null) { c.removeFocusListener(toolBarFocusListener); } // Revert the button border setBorderToNormal(c); } } //* 本类由Jack Jiang实现,参考了com.sun.java.swing.plaf.windows.WindowsBorders.getToolBarBorder /** * 工具条边框,左边(或右、或上方)有拖动触点的绘制,方便 告之用户它是可以拖动的 * A border for the ToolBar. If the ToolBar is floatable then the handle grip is drawn * <p> * @since 1.4 */ public static class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants { /** The shadow. */ protected Color shadow; /** The highlight. */ protected Color highlight; protected Insets insets; /** * Instantiates a new tool bar border. * * @param shadow the shadow * @param highlight the highlight */ public ToolBarBorder(Color shadow, Color highlight, Insets insets) { this.highlight = highlight; this.shadow = shadow; this.insets = insets; } /* (non-Javadoc) * @see javax.swing.border.AbstractBorder#paintBorder(java.awt.Component, java.awt.Graphics, int, int, int, int) */ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { g.translate(x, y); //需要绘制拖动触点 if (((JToolBar)c).isFloatable()) { boolean vertical = ((JToolBar)c).getOrientation() == VERTICAL; //虚线样式 Stroke oldStroke = ((Graphics2D)g).getStroke(); Stroke sroke = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{1, 1}, 0);//实线,空白 ((Graphics2D)g).setStroke(sroke); // int gap_top = 5,gap_bottom = 4; //!!10,-1 if (!vertical) { int gap_top = 8,gap_bottom = 8; if (c.getComponentOrientation().isLeftToRight()) { int drawX = 3; drawTouchH(g, drawX, gap_top -1, drawX, height - gap_bottom -1); } else { int drawX = 3 - 1; drawTouchH(g, width - drawX, gap_top -1, width - drawX, height - gap_bottom -1); } } else // Vertical { int gap_left = 8,gap_right = 8; int drawY = 3; drawTouchV(g, gap_left -1, drawY, width - gap_right -1, drawY); } ((Graphics2D)g).setStroke(oldStroke); } g.translate(-x, -y); } //水平工具条的触点绘制方法 private void drawTouchH(Graphics g, int x1 , int y1, int x2, int y2) { //第1条竖虚线(深色) g.setColor(shadow); g.drawLine(x1, y1, x1, y2-1); //第2条竖虚线(与第1条形成立体效果的浅色,Y坐标相对第1条下偏一个像素) g.setColor(highlight); g.drawLine(x1+1 , y1+1, x1+1, y2); //第3条竖虚线 g.setColor(shadow); g.drawLine(x1+2 , y1, x1+2, y2-1); //第4条竖虚线(与第3条形成立体效果的浅色,Y坐标相对第3条下偏一个像素) g.setColor(highlight); g.drawLine(x1+3 , y1+1, x1+3, y2); } //垂直工具条的触点绘制方法 private void drawTouchV(Graphics g, int x1 , int y1, int x2, int y2) { //第1条横虚线(深色) g.setColor(shadow); g.drawLine(x1, y1, x2-1, y2); //第2条横虚线(与第1条形成立体效果的浅色,X坐标相对第1条右偏一个像素) g.setColor(highlight); g.drawLine(x1+1, y1+1, x2, y2+1); //第3条横虚线 g.setColor(shadow); g.drawLine(x1, y1+2, x2-1, y2+2); //第4条横虚线(与第3条形成立体效果的浅色,X坐标相对第3条右偏一个像素) g.setColor(highlight); g.drawLine(x1+1, y1+3, x2, y2+3); } /* (non-Javadoc) * @see javax.swing.border.AbstractBorder#getBorderInsets(java.awt.Component) */ public Insets getBorderInsets(Component c) { //** 根据toolbar所放面板的方位不同而设置不一样的border(参照的目标是水平toolbar时的insets)! //tollbar上下设置的空白多一点看起来大气一些(它也将决定toolbar的整体高度和宽度哦) final Insets DEFAILT_IS = insets;//8,0,9,0);//6, 0, 11, 0); Insets is = DEFAILT_IS; if(c instanceof JToolBar) { Container parent = c.getParent(); if(parent != null) { LayoutManager lm = parent.getLayout(); if(lm instanceof BorderLayout) { Object cons = ((BorderLayout)lm).getConstraints((JToolBar)c); if(cons != null) { if(cons.equals(BorderLayout.NORTH)) is = DEFAILT_IS; else if(cons.equals(BorderLayout.SOUTH)) is = new Insets(DEFAILT_IS.bottom, 0, DEFAILT_IS.top, 0); else if(cons.equals(BorderLayout.WEST)) is = new Insets(0, DEFAILT_IS.top, 0, DEFAILT_IS.bottom); else if(cons.equals(BorderLayout.EAST)) is = new Insets(0, DEFAILT_IS.bottom, 0, DEFAILT_IS.top); } } } } return getBorderInsets(c, is);//5, 0, 10, 0));//默认是 1,1,1,1 } /* (non-Javadoc) * @see javax.swing.border.AbstractBorder#getBorderInsets(java.awt.Component, java.awt.Insets) */ public Insets getBorderInsets(Component c, Insets insets) { // insets.top = insets.left = insets.bottom = insets.right = 1; if (((JToolBar)c).isFloatable()) { // int gripInset = (XPStyle.getXP() != null) ? 12 : 9;//原windows外观中默认的 int gripInset = 9; if (((JToolBar)c).getOrientation() == HORIZONTAL) { if (c.getComponentOrientation().isLeftToRight()) insets.left = gripInset; else insets.right = gripInset; } else insets.top = gripInset; } return insets; } } }