`
xio
  • 浏览: 2270 次
  • 性别: Icon_minigender_1
  • 来自: 永春
文章分类
社区版块
存档分类
最新评论
  • mikewang: 做的,不错, 在给你你加个点击记忆功能 思路 1 每次点击菜单 ...
    JPopupButton

JPopupButton

阅读更多

 

 

本来在网上找了一个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未设置Rollover
			JPopupButton.this.getModel().setRollover(true);
		}

		public void mouseExited(MouseEvent e) {
			//防止部分L&F未设置Rollover
			JPopupButton.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状态,以便按钮的视图显示为Rollover
			if (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 icon2
 CENTER: icon1 is drawn first, icon2 is drawn over it
 
 and with horizontal and vertical orientations within the alloted space
 
 It'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 effect
	to 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 position
	and 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 position
	and 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 position
			paintIcon(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 position
			paintIcon(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

 

 

 

  • 大小: 2 KB
  • 大小: 20 KB
分享到:
评论
1 楼 mikewang 2009-04-09  
做的,不错, 在给你你加个点击记忆功能
思路
1 每次点击菜单的时候保存这个菜单的index,并且出发菜单下表变更事件
2 在JPopupButton中 监听事件, 并调用attachActionOnPopupMenu 绑定点击按钮所执行的菜单

实现:
JPopupMenu 达不到要求, 需要改造一下
package info.mikewang.part.test;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.util.Vector;

import javax.swing.AbstractButton;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;

class JPopupButtonMenu extends JPopupMenu {
	private static final long serialVersionUID = -8812143869773395718L;

	private int clickedMenuIndex = -1;

	public JPopupButtonMenu() {
		this(null);
	}

	public JPopupButtonMenu(String label) {
		super(label);
		addContainerListener(new XContainerListener());
	}

	public int getClickedMenuIndex() {
		return clickedMenuIndex;
	}

	public AbstractButton[] getSubClickedElements() {
		AbstractButton result[];
		Vector<AbstractButton> tmpx = new Vector<AbstractButton>();

		MenuElement tmp[] = getSubElements();
		for (MenuElement menuElement : tmp) {
			if (menuElement instanceof AbstractButton) {
				tmpx.add((AbstractButton) menuElement);
			}
		}

		result = new AbstractButton[tmpx.size()];
		for (int i = 0; i < tmpx.size(); i++) {
			result[i] = tmpx.elementAt(i);
		}

		return result;
	}

	// ----------------------------------

	class XContainerListener implements ContainerListener {

		@Override
		public void componentAdded(ContainerEvent e) {
			Component c = e.getChild();
			if (c instanceof AbstractButton) {
				((AbstractButton) c).addActionListener(new XActionListener());
			}
		}

		@Override
		public void componentRemoved(ContainerEvent e) {

		}
	}

	class XActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			AbstractButton ab = (AbstractButton) e.getSource();
			AbstractButton abs[] = getSubClickedElements();
			for (int i = 0; i < abs.length; i++) {
				if (ab == abs[i]) {
					int oldClickedMenuIndex = clickedMenuIndex;
					clickedMenuIndex = i;
					firePropertyChange("clickedMenuIndex", oldClickedMenuIndex, i);
					break;
				}
			}
		}
	}
}


JPopupButton 本部分都差不多, 就增加了一个属性监听器, 监听clickedMenuIndex, 并调用attachActionOnPopupMenu, 改变下标
private void initClickRemember() {
		menu.addPropertyChangeListener("clickedMenuIndex",
				new PropertyChangeListener() {
					@Override
					public void propertyChange(PropertyChangeEvent evt) {
						Integer ii = (Integer) evt.getNewValue();
						attachActionOnPopupMenu(ii.intValue());
					}
				});
	}

相关推荐

    OpenSwing---Java 常用控件集合

    2006/01/20 修正了JPopupButton在XP风格下呈两个按钮样子的BUG 对JFontDialog进行了部分修改 2006/03/08 从JDatePicker提出来一个组件JCalendarPanel日期选择面板 并修改了JDatePicker的设计方式 2006/03/23 ...

    OpenSwing开发包及源码

    只能输入0~255数字的IP地址 JListChooser 列表选择对话框 JNumberField 数字输入框,可限制小数位数,数字最大长度,最大最小能输入的数字 JPopupButton 带下拉菜单的工具栏按钮 JStatusBar 模拟Windows的...

    基于主从博弈的共享储能与综合能源微网优化运行研究:MATLAB与CPLEX实现

    内容概要:本文详细探讨了在主从博弈框架下,共享储能与综合能源微网的优化运行及其仿真复现。通过MATLAB和CPLEX的联合使用,展示了微网运营商和用户聚合商之间的动态博弈过程。上层模型关注微网运营商的定价策略,旨在最大化利润,考虑售电收益、储能运维成本等因素。下层模型则聚焦于用户聚合商的响应,根据电价调整电热负荷并参与共享储能调度。文中还介绍了电热耦合约束、充放电互斥约束等关键技术细节,并通过迭代博弈实现了策略更新。最终仿真结果显示,在引入电制热设备后,用户侧热负荷弹性提升,博弈收敛速度加快,达到双赢效果。 适合人群:从事能源系统优化、博弈论应用、MATLAB编程的研究人员和技术人员。 使用场景及目标:适用于希望深入了解主从博弈在综合能源系统中应用的学者和工程师。目标是掌握如何通过数学建模和编程实现复杂的能源系统优化,理解电热耦合机制和共享储能的作用。 其他说明:文章提供了详细的代码片段和仿真结果,帮助读者更好地理解和复现实验。此外,还讨论了一些常见的调试问题和解决方案,如约束冲突等。

    【基于矢量射线的衍射积分 (VRBDI)】基于矢量射线的衍射积分 (VRBDI) 和仿真工具附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    【深度学习应用综述】多领域关键技术及应用场景汇总:从计算机视觉到金融风控的全面解析

    内容概要:深度学习在多个领域有着广泛应用。在计算机视觉方面,涵盖图像分类、目标检测、图像分割等任务,应用于自动驾驶、医疗影像分析等领域;在自然语言处理上,包括机器翻译、文本分类、文本生成等功能,服务于信息检索、内容创作等;语音识别与合成领域,实现了语音到文本的转换以及文本到语音的生成,推动了智能交互的发展;医疗领域,深度学习助力医学影像分析、疾病预测、个性化治疗及健康监测;金融领域,深度学习用于信用风险评估、欺诈检测、高频交易等,保障金融安全并优化投资策略;自动驾驶方面,环境感知与决策控制系统确保车辆安全行驶;娱乐与媒体领域,个性化推荐和内容生成提升了用户体验;工业与制造业中,质量检测和预测性维护提高了生产效率和产品质量。 适合人群:对深度学习及其应用感兴趣的初学者、研究人员以及相关领域的从业者。 使用场景及目标:帮助读者全面了解深度学习在不同行业的具体应用场景,明确各领域中深度学习解决的实际问题,为后续深入研究或项目实施提供方向指引。 其他说明:随着深度学习技术的持续进步,其应用范围也在不断扩大,文中提及的应用实例仅为当前主要成果展示,未来还有更多潜力待挖掘。

    【ARIMA-LSTM】合差分自回归移动平均方法-长短期记忆神经网络研究附Python代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    周梁伟-大模型在融合通信中的应用实践.pdf

    周梁伟-大模型在融合通信中的应用实践

    基于S7-200 PLC与组态王的花式喷泉控制系统设计及应用

    内容概要:本文详细介绍了利用西门子S7-200 PLC和组态王软件构建的一个花式喷泉控制系统的设计与实现。首先阐述了系统的硬件组成,包括三个环形喷泉组、七彩LED灯带以及功放喇叭等组件,并给出了详细的IO分配表。接着深入解析了关键的梯形图程序逻辑,如自动模式循环、灯光控制、喷泉舞步等部分的具体实现方法。此外,还分享了一些实际调试过程中遇到的问题及其解决方案,例如电源隔离、电磁干扰处理等。最后展示了组态王界面上生动有趣的动画效果设计思路。 适合人群:对PLC编程和工业自动化感兴趣的工程师和技术爱好者。 使用场景及目标:适用于需要设计类似互动娱乐设施的专业人士,旨在帮助他们掌握从硬件选型、程序编写到界面美化的完整流程,从而能够独立完成类似的工程项目。 其他说明:文中不仅提供了理论知识讲解,还包括了许多实践经验教训,对于初学者来说非常有价值。同时,作者还在系统中加入了一些趣味性的元素,如隐藏模式等,增加了项目的吸引力。

    基于COMSOL的电弧熔池多物理场耦合仿真技术详解

    内容概要:本文详细介绍了利用COMSOL进行电弧熔池多物理场耦合仿真的方法和技术要点。首先解释了电弧熔池的本质及其复杂性,然后依次讲解了几何建模、材料属性设置、求解器配置以及后处理等方面的具体步骤和注意事项。文中提供了大量实用的MATLAB、Java和Python代码片段,帮助用户更好地理解和应用相关技术。此外,作者分享了许多实践经验,如分阶段激活物理场、使用光滑过渡函数处理相变、优化网格划分等,强调了参数选择和边界条件设定的重要性。 适合人群:从事电弧熔池仿真研究的专业人士,尤其是有一定COMSOL使用经验的研究人员。 使用场景及目标:适用于需要精确模拟电弧熔池行为的研究项目,旨在提高仿真精度并减少计算时间。主要目标是掌握多物理场耦合仿真的关键技术,解决实际工程中遇到的问题。 其他说明:文章不仅提供了详细的理论指导,还包括许多实用的操作技巧和常见错误的解决方案,有助于读者快速上手并深入理解电弧熔池仿真的难点和重点。

    9f148310e17f2960fea3ff60af384a37_098bb292f553b9f4ff9c67367379fafd.png

    9f148310e17f2960fea3ff60af384a37_098bb292f553b9f4ff9c67367379fafd

    spring-ai-hanadb-store-1.0.0-M7.jar中文-英文对照文档.zip

    # 【spring-ai-hanadb-store-1.0.0-M7.jar中文-英文对照文档.zip】 中包含: 中文-英文对照文档:【spring-ai-hanadb-store-1.0.0-M7-javadoc-API文档-中文(简体)-英语-对照版.zip】 jar包下载地址:【spring-ai-hanadb-store-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-hanadb-store-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-hanadb-store-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-hanadb-store-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-hanadb-store-1.0.0-M7.jar中文-英文对照文档.zip,java,spring-ai-hanadb-store-1.0.0-M7.jar,org.springframework.ai,spring-ai-hanadb-store,1.0.0-M7,org.springframework.ai.vectorstore.hanadb,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,hanadb,store,中文-英文对照API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【spring-ai-hanadb-store-1.0.0-M7.jar中文-英文

    azure-ai-openai-1.0.0-beta.7.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    3dmax插件复制属性.ms

    3dmax插件

    单相全桥PWM整流双闭环控制系统:电压环PI与电流环PR控制策略及其应用

    内容概要:本文详细介绍了单相全桥PWM整流器采用双闭环控制策略的具体实现方法和技术要点。电压环采用PI控制器来稳定直流侧电压,电流环则使用PR控制器确保交流电流与电压同相位并实现单位功率因数。文中提供了详细的MATLAB、C和Python代码片段,解释了各个控制器的设计思路和参数整定方法。此外,文章还讨论了突加负载测试、电压前馈补偿、PWM生成以及硬件选型等方面的内容,强调了系统的稳定性和快速响应能力。 适合人群:从事电力电子、自动控制领域的工程师和技术人员,尤其是对PWM整流器和双闭环控制感兴趣的读者。 使用场景及目标:适用于需要精确控制直流电压和交流电流的应用场景,如工业电源、新能源发电等领域。目标是提高系统的电能质量和动态响应速度,确保在负载变化时仍能保持稳定的输出。 其他说明:文章不仅提供了理论分析,还包括了大量的实际测试数据和波形图,帮助读者更好地理解和掌握双闭环控制的实际效果。同时,文中提到的一些调试技巧和注意事项对于实际工程应用非常有价值。

    easyocr安装包和模型

    easyocr安装包和模型

    AC-DIMMER交流调光灯stm32.7z

    AC_DIMMER交流调光灯stm32.7z

    仲量联行-负责任的房地产:实现社会价值,赋能建筑环境,创造积极的环境和社会影响.pdf

    仲量联行-负责任的房地产:实现社会价值,赋能建筑环境,创造积极的环境和社会影响

    C语言全部知识点复习资料.doc

    C语言全部知识点复习资料.doc

    【蓝桥杯EDA】客观题解析:第十二届省赛第一场真题.pdf

    【蓝桥杯EDA】客观题解析

Global site tag (gtag.js) - Google Analytics