本来在网上找了一个JPopupButton【@author SunKing】,但是实际使用的时候,无法满足L&F效果,在JGoodies Looks下无法正常显示。

期间还在网络找了一个JPopupToggleButton【@author Alexander Wenckus】,但是感觉过于简单,也不够满意。

于是只好自己重写一个。

以下为相关代码:

注意: 勿遗落最后的/name/xio/util/swing/toolbar-buttonarrow.png文件。

name.xio.util.swing.JPopupButton

package name.xio.util.swing;import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;
import javax.swing.MenuElement;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;import name.xio.util.swing.icon.CompositeIcon;
import name.xio.util.swing.icon.HTextIcon;import com.by.yb.util.Utilities;
import com.jgoodies.looks.LookUtils;
import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
import com.jgoodies.looks.plastic.theme.ExperienceBlue;
import com.jgoodies.looks.windows.WindowsLookAndFeel;/*** 弹出菜单按钮* @author xio**/
public class JPopupButton extends JButton {private static final long serialVersionUID = -6783978058195706887L;/*** 弹出菜单*/private JPopupMenu menu = new JPopupMenu();/*** 按钮点击事件,与菜单中的第几项绑定*/private int attachActionOnPopupMenuIndex = -1;/*** 是否显示箭头部分的分割线*/private boolean showSeparator = false;public final static int NARROW_WIDTH = 11;public JPopupButton(Icon icon, JPopupMenu menu) {this(null, icon, menu);}public JPopupButton(String text, JPopupMenu menu) {this(text, null, menu);}public JPopupButton(String text, Icon icon, JPopupMenu menu) {initView(text, icon, menu);}/*** 初始化菜单按钮的视图* @param text* @param icon* @param menu*/private void initView(String text, Icon icon, JPopupMenu menu) {//1.按钮绘制this.setFocusable(false);this.setText(null);HTextIcon hTextIcon = new HTextIcon(this, text, 10);if (icon != null) {CompositeIcon commonButtonIcon = new CompositeIcon(icon, hTextIcon, CompositeIcon.LEFT);CompositeIcon popupButtonIcon = new CompositeIcon(commonButtonIcon, new ImageIcon(JPopupButton.class.getResource("toolbar-buttonarrow.png")), CompositeIcon.LEFT, 2, 0);this.setIcon(popupButtonIcon);}else {CompositeIcon popupButtonIcon = new CompositeIcon(hTextIcon, new ImageIcon(JPopupButton.class.getResource("toolbar-buttonarrow.png")), CompositeIcon.LEFT, 2, 0);this.setIcon(popupButtonIcon);}//this.setMargin(new Insets());this.menu = menu;//2.事件监听//Rollover监听this.addChangeListener(new RolloverChangeListener());//添加按钮鼠标事件监听PopupButtonListener popupButtonListener = new PopupButtonListener();this.addMouseMotionListener(popupButtonListener);this.addMouseListener(popupButtonListener);//添加菜单事件监听if (menu != null) {menu.addPopupMenuListener(popupButtonListener);}//初始按钮事件绑定clearAttachActionOnPopupMenu();}/*** 清空按钮绑定事件*/public void clearAttachActionOnPopupMenu() {attachActionOnPopupMenu(-1);}/*** 按钮行为绑定为弹出菜单第一项*/public void attachDefaultActionOnPopupMenu() {attachActionOnPopupMenu(0);}/*** 按钮的行为绑定为弹出菜单* @param index*/public void attachActionOnPopupMenu(int index) {if (menu == null) {attachActionOnPopupMenuIndex = -1;}else {MenuElement[] menuElements = menu.getSubElements();if ((index < 0) || (Utilities.isEmpty(menuElements)) || (index >= menuElements.length)) {attachActionOnPopupMenuIndex = -1;}else {attachActionOnPopupMenuIndex = index;}}}/*** @return Returns the menu.*/public JPopupMenu getMenu() {return menu;}private void showMenu() {if (menu == null) {return;}Point locate = locateMenu();menu.show(this, locate.x, locate.y);}private void showSeparator(boolean b) {showSeparator = b;this.repaint();}/*** 按钮左部触发*/public void onClick() {//点击位置为箭头位置  boolean mouseInNarrow = isMouseInNarrow();if (mouseInNarrow) {onClickNarrow();}else {if (attachActionOnPopupMenuIndex < 0) {onClickNarrow();}else {MenuElement[] menuElements = menu.getSubElements();((AbstractButton) menuElements[attachActionOnPopupMenuIndex]).doClick();}}}/*** 按钮箭头部触发*/private void onClickNarrow() {showMenu();}/*** 菜单位置* @return*/protected Point locateMenu() {Point locate = new Point((int) getAlignmentX(),(int) getAlignmentY() + (getHeight() == 0 ? getPreferredSize().height : getHeight()));return locate;}public void paint(Graphics g) {super.paint(g);//绘制分离线if (showSeparator) {Color oldColor = g.getColor();Insets insets = this.getInsets();int width = getWidth();int height = getHeight();Icon icon = this.getIcon();//int x = icon == null ? (width - NARROW_WIDTH) : (mrgin.left - insets.left + icon.getIconWidth() - NARROW_WIDTH);int x = icon == null ? (width - NARROW_WIDTH) : (insets.left + icon.getIconWidth() - NARROW_WIDTH);int y = 0;//          Button.light//          Button.shadow//         Button.darkShadow//         Button.highlight//g.setColor(new Color(216, 214, 207));g.setColor(UIManager.getColor("Button.shadow"));g.drawLine(x, y + 1, x, y + height - 3);//g.setColor(new Color(250, 250, 248));g.setColor(UIManager.getColor("Button.highlight"));g.drawLine(x + 1, y + 1, x + 1, y + height - 3);g.setColor(oldColor);}}/*** 当前鼠标是否在按钮上* @return*/public boolean isMouseOver() {return this.getMousePosition() != null;}/*** 鼠标位置是否在箭头部分* @return*/public boolean isMouseInNarrow() {Point position = this.getMousePosition();if (position == null) {return false;}else {return isMouseInNarrow(position);}}/*** 鼠标位置是否在箭头部分* @param position* @return*/public boolean isMouseInNarrow(Point position) {Insets insets = this.getInsets();Icon icon = this.getIcon();int width = this.getWidth();int height = this.getHeight();//int narrowFromX = icon == null ? (width - NARROW_WIDTH) : (mrgin.left - insets.left + icon.getIconWidth() - NARROW_WIDTH);int narrowFromX = icon == null ? (width - NARROW_WIDTH) : (insets.left + icon.getIconWidth() - NARROW_WIDTH);int narrowFromY = 0;int narrowEndX = width;int narrowEndY = height;int eventX = (int) position.getX();int eventY = (int) position.getY();return ((narrowFromX <= eventX) && (eventX <= narrowEndX)) && ((narrowFromY <= eventY) && (eventY <= narrowEndY));}/*** 按钮Rollover监听* @author xio**/class RolloverChangeListener implements ChangeListener {public void stateChanged(ChangeEvent e) {ButtonModel buttonModel = JPopupButton.this.getModel();showSeparator(buttonModel.isRollover() || buttonModel.isPressed());}}/*** 按钮和菜单的事件监听* @author xio**/class PopupButtonListener extends MouseAdapter implements PopupMenuListener {public void mouseEntered(MouseEvent e) {//防止部分L&F未设置RolloverJPopupButton.this.getModel().setRollover(true);}public void mouseExited(MouseEvent e) {//防止部分L&F未设置RolloverJPopupButton.this.getModel().setRollover(false);showSeparator(false);}public void mouseClicked(MouseEvent e) {JPopupButton.this.onClick();}public void popupMenuCanceled(PopupMenuEvent e) {}public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {//菜单不可见时,如果鼠标还在按钮上,设置Rollover状态,以便按钮的视图显示为Rolloverif (isMouseOver()) {JPopupButton.this.getModel().setRollover(true);}}public void popupMenuWillBecomeVisible(PopupMenuEvent e) {//菜单显示时,修改按钮Rollover状态JPopupButton.this.getModel().setRollover(false);}}public static void main(String[] args) {try {//不显示ToolBar的边界UIManager.put("ToolBar.border", BorderFactory.createEmptyBorder());if (LookUtils.IS_LAF_WINDOWS_XP_ENABLED) {UIManager.setLookAndFeel(new WindowsLookAndFeel());}else {PlasticXPLookAndFeel.setCurrentTheme(new ExperienceBlue());UIManager.setLookAndFeel(new PlasticXPLookAndFeel());}//                                PlasticXPLookAndFeel.setCurrentTheme(new ExperienceBlue());//                               UIManager.setLookAndFeel(new PlasticXPLookAndFeel());}catch (UnsupportedLookAndFeelException e) {e.printStackTrace();}catch (Exception e) {e.printStackTrace();}JFrame frame = new JFrame("JPopupButton");frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);frame.setSize(400, 320);//SwingUtils.locateCenterOnScreen(frame);class DemoAction extends AbstractAction {private static final long serialVersionUID = 5232174589593930544L;public DemoAction(String id) {super.putValue(Action.NAME, "Demo JPopupButton " + id);}public void actionPerformed(ActionEvent e) {JOptionPane.showMessageDialog((Component) e.getSource(), super.getValue(Action.NAME));}}JPopupMenu popup = new JPopupMenu("PopupMenu");popup.add(new DemoAction("0"));popup.add(new DemoAction("1"));popup.add(new DemoAction("2"));JPopupButton btt1 = new JPopupButton("中文文字", null, popup);JPopupButton btt2 = new JPopupButton("中文文字", null, popup);btt2.attachDefaultActionOnPopupMenu();JPopupButton btt3 = new JPopupButton("中文文字", UIManager.getIcon("FileView.computerIcon"), popup);btt3.attachActionOnPopupMenu(2);JToolBar toolbar = new JToolBar();toolbar.add(btt1);toolbar.add(btt2);toolbar.add(btt3);toolbar.add(new JButton("中文文字", UIManager.getIcon("FileView.computerIcon")));toolbar.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 3));frame.getContentPane().add(toolbar, BorderLayout.NORTH);frame.setVisible(true);}}

name.xio.util.swing.icon.CompositeIcon

package name.xio.util.swing.icon;import java.awt.Component;
import java.awt.Graphics;import javax.swing.Icon;
import javax.swing.SwingConstants;/**CompositeIcon is an Icon implementation which draws two icons with a specified relative position:LEFT, RIGHT, TOP, BOTTOM specify how icon1 is drawn relative to icon2CENTER: icon1 is drawn first, icon2 is drawn over itand with horizontal and vertical orientations within the alloted spaceIt's useful with VTextIcon when you want an icon with your text: if icon1 is the graphic icon and icon2 is the VTextIcon, you get a similar effectto a JLabel with a graphic icon and text* @from http://www.macdevcenter.com/pub/a/mac/2002/03/22/vertical_text.html?page=last&x-order=date* @changedBy xio*/
public class CompositeIcon implements Icon, SwingConstants {Icon fIcon1, fIcon2;int fPosition, fHorizontalOrientation, fVerticalOrientation;int widthOffset, heightOffset;/**Create a CompositeIcon from the specified Icons,using the default relative position (icon1 above icon2)and orientations (centered horizontally and vertically)*/public CompositeIcon(Icon icon1, Icon icon2) {this(icon1, icon2, TOP);}/**Create a CompositeIcon from the specified Icons,using the specified relative positionand default orientations (centered horizontally and vertically)*/public CompositeIcon(Icon icon1, Icon icon2, int position) {this(icon1, icon2, position, CENTER, CENTER, (position == LEFT || position == RIGHT) ? 2 : -7, (position == LEFT || position == RIGHT) ? 0 : 6);}public CompositeIcon(Icon icon1, Icon icon2, int position, int widthOffset, int heightOffset) {this(icon1, icon2, position, CENTER, CENTER, widthOffset, heightOffset);}/**Create a CompositeIcon from the specified Icons,using the specified relative positionand orientations*/public CompositeIcon(Icon icon1, Icon icon2, int position, int horizontalOrientation, int verticalOrientation, int widthOffset, int heightOffset) {fIcon1 = icon1;fIcon2 = icon2;fPosition = position;this.widthOffset = widthOffset;this.heightOffset = heightOffset;fHorizontalOrientation = horizontalOrientation;fVerticalOrientation = verticalOrientation;}/*** Draw the icon at the specified location.  Icon implementations* may use the Component argument to get properties useful for * painting, e.g. the foreground or background color.*/public void paintIcon(Component c, Graphics g, int x, int y) {int width = getIconWidth();int height = getIconHeight();if (fPosition == LEFT || fPosition == RIGHT) {Icon leftIcon, rightIcon;if (fPosition == LEFT) {leftIcon = fIcon1;rightIcon = fIcon2;}else {leftIcon = fIcon2;rightIcon = fIcon1;}// "Left" orientation, because we specify the x positionpaintIcon(c, g, leftIcon, x, y, width, height, LEFT, fVerticalOrientation);paintIcon(c, g, rightIcon, x + leftIcon.getIconWidth(), y, width, height, LEFT, fVerticalOrientation);}else if (fPosition == TOP || fPosition == BOTTOM) {Icon topIcon, bottomIcon;if (fPosition == TOP) {topIcon = fIcon1;bottomIcon = fIcon2;}else {topIcon = fIcon2;bottomIcon = fIcon1;}// "Top" orientation, because we specify the y positionpaintIcon(c, g, topIcon, x, y, width, height, fHorizontalOrientation, TOP);paintIcon(c, g, bottomIcon, x, y + topIcon.getIconHeight(), width, height, fHorizontalOrientation, TOP);}else {paintIcon(c, g, fIcon1, x, y, width, height, fHorizontalOrientation, fVerticalOrientation);paintIcon(c, g, fIcon2, x, y, width, height, fHorizontalOrientation, fVerticalOrientation);}}/* Paints one icon in the specified rectangle with the given orientations*/void paintIcon(Component c, Graphics g, Icon icon, int x, int y, int width, int height, int horizontalOrientation,int verticalOrientation) {int xIcon, yIcon;switch (horizontalOrientation) {case LEFT:xIcon = x;break;case RIGHT:xIcon = x + width - icon.getIconWidth();break;default:xIcon = x + (width - icon.getIconWidth()) / 2;break;}switch (verticalOrientation) {case TOP:yIcon = y;break;case BOTTOM:yIcon = y + height - icon.getIconHeight();break;default:yIcon = y + (height - icon.getIconHeight()) / 2;break;}icon.paintIcon(c, g, xIcon, yIcon);}/*** Returns the icon's width.** @return an int specifying the fixed width of the icon.*/public int getIconWidth() {if (fPosition == LEFT || fPosition == RIGHT)return fIcon1.getIconWidth() + fIcon2.getIconWidth() + widthOffset;return Math.max(fIcon1.getIconWidth(), fIcon2.getIconWidth()) + widthOffset;}/*** Returns the icon's height.** @return an int specifying the fixed height of the icon.*/public int getIconHeight() {if (fPosition == TOP || fPosition == BOTTOM)return fIcon1.getIconHeight() + fIcon2.getIconHeight() + heightOffset;return Math.max(fIcon1.getIconHeight(), fIcon2.getIconHeight()) + heightOffset;}}

name.xio.util.swing.icon.HTextIcon

package name.xio.util.swing.icon;import java.awt.Component;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;import javax.swing.Icon;/*** 水平文本Icon* @author xio**/
public class HTextIcon implements Icon, PropertyChangeListener {private String text;private int textWidth;private int textHeight;private int fontCharHeight;private Component fontComponent;private int marginLeft;private int marginRight;static final int MARGIN = 4;static final int MIN_TEXT_HEIGHT = 15;static final int MIN_TEXT_WIDTH = 16;public HTextIcon(Component component, String label) {this(component, label, MARGIN, MARGIN);}public HTextIcon(Component component, String label, int marginRight) {this(component, label, MARGIN, marginRight);}/*** 指定一个Component,创建水平文本Icon* @param component* @param label*/public HTextIcon(Component component, String label, int marginLeft, int marginRight) {fontComponent = component;text = label;this.marginLeft = marginLeft;this.marginRight = marginRight;calcDimensions();fontComponent.addPropertyChangeListener(this);}/*** sets the label to the given string, updating the orientation as needed* and invalidating the layout if the size changes* @see #verifyRotation*/public void setLabel(String label) {text = label;recalcDimensions();}/*** Checks for changes to the font on the fComponent* so that it can invalidate the layout if the size changes*/public void propertyChange(PropertyChangeEvent e) {String prop = e.getPropertyName();if ("font".equals(prop)) {recalcDimensions();}}/** * Calculates the dimensions.  If they've changed,* invalidates the component*/void recalcDimensions() {int wOld = getIconWidth();int hOld = getIconHeight();calcDimensions();if (wOld != getIconWidth() || hOld != getIconHeight())fontComponent.invalidate();}void calcDimensions() {FontMetrics fontMetrics = fontComponent.getFontMetrics(fontComponent.getFont());int fontDescent = fontMetrics.getDescent();fontCharHeight = fontMetrics.getAscent() + fontDescent;textWidth = fontMetrics.stringWidth(text) + marginLeft + marginRight;if (textWidth < MIN_TEXT_WIDTH) {textWidth = MIN_TEXT_WIDTH;}textHeight = fontCharHeight + fontDescent;if (textHeight < MIN_TEXT_HEIGHT) {textHeight = MIN_TEXT_HEIGHT;}//      //强制调整尺寸//      fWidth -= 5;//     fHeight += 6;}/*** 绘制文本*/public void paintIcon(Component c, Graphics g, int x, int y) {g.setColor(c.getForeground());g.setFont(c.getFont());g.drawString(text, x + marginLeft, y + fontCharHeight - 2);}/*** icon宽度*/public int getIconWidth() {return textWidth;}/*** icon高度*/public int getIconHeight() {return textHeight;}}

/name/xio/util/swing/toolbar-buttonarrow.png: http://xio.iteye.com/upload/attachment/44097/f0b31625-ac6e-36a5-a5cd-d86bca96e72d.png

最新文章

  1. 网站上传到服务器mysql数据库,网站上传到服务器mysql数据库吗
  2. mantelhean.test r语言_请教如何将mantel test报告性的结果转化为表格。
  3. Jquery Easy UI--datagrid的使用(转)
  4. 百度地图的实现,IIS6.0,.net4.0 无法使用POST和GET
  5. [网络安全自学篇] 五十九.Windows安全缺陷利用之MS08-067远程代码执行及深度防御解析
  6. Adobe Lifecycle ES的安装截图
  7. python 网络框架twisted基础学习及详细讲解
  8. 最近,程序员又被区别对待了
  9. springboot中使用@Value读取配置文件
  10. Intelij IDEA解决Dependency无法更新问题
  11. “如何学习”系列文章2007年全部文章索引
  12. spring 中execution 表达式语法
  13. 塞尔之光的树心旋转机关_塞尔之光
  14. max点缓存烘焙帧_3DMAX怎么进行点缓存?
  15. linux cat命令追加,linux cat命令
  16. Win10环境下初始化MySQL
  17. 沧海的孤塔-chimera
  18. Adb连不上夜神模拟器的原因adb devices显示设备信息为空
  19. 体验DCGAN生成漫画头像
  20. 下载Excel文件功能通过火狐浏览器下载没有后缀名

热门文章

  1. 感受Java的魅力——基于Java二维数组和if语句编制的税后工资计算方法
  2. ​KAKA NFT | 潮物来袭!烤仔英雄系列NFT盲盒即将发售~
  3. AlertDialog点击确定必定会dismiss问题
  4. 目标检测之YOLOX: Exceeding YOLO Series in 2021
  5. Web--html认识、标签、基本结构
  6. 使用物理学和领域知识的神经网络的无标签监督解读(上)
  7. div布局三栏-左中右
  8. div实现页面划分为左,中,右三栏
  9. Beta的计划和人员的变动
  10. linux下安装jdk7