来源地址http://www.wiui.net/?p=377
平时开发系统过程中,我们一般都要求界面简洁,操作简单,但是有些情况下,n多按钮的情况也是有的
比如绘图软件n多的编辑按钮,再比如移动综合资源管理系统中要把不同厂商提供不同设备类型都列举出来以供编辑之用。
n多按钮的情况下,如果简单的把按钮都放在JToolBar上,当窗口比较小的情况下,有些按钮会显示不出来。如图普通Toolbar
如何解决这种问题呢?本文提供了两种解决方案
1、如果当前toolbar的宽度已经不够把所有按钮都显示出来的时候,让其它组件自动换行,我们很自然就想到了FlowLayout,
但是FlowLayout有一个最直接的问题就是,如果一个面板设置了FlowLayout,当面板长度<按钮的长度之和,需要折行的时候,面板不会自动撑开
所以需要重载一下FlowLayout
/* * * @author zhangtao * * Msn & Mail: [email protected] */ package zht.popup.toolbar.wrap; import java.awt.Component; import java.awt.FlowLayout; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JToolBar; public class WrapToolbarAdapter { public static JComponent createWrapToolbar(JToolBar toolBar) { JToolBar panel = new JToolBar(); panel.setLayout(new WrapLayout(FlowLayout.LEADING, 0, 2)); int size = toolBar.getComponentCount(); List list = new ArrayList(); for (int i = 0; i < size; i++) { Component component = toolBar.getComponentAtIndex(i); list.add(component); } for (int i = 0; i < size; i++) { Component component = (Component) list.get(i); panel.add(component); } return panel; } } /* * * @author zhangtao * * Msn & Mail: [email protected] */ package zht.popup.toolbar.wrap; import java.awt.*; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; public class WrapLayout extends FlowLayout { public WrapLayout() { super(); } public WrapLayout(int align) { super(align); } public WrapLayout(int align, int hgap, int vgap) { super(align, hgap, vgap); } public Dimension preferredLayoutSize(Container target) { return layoutSize(target, true); } public Dimension minimumLayoutSize(Container target) { Dimension minimum = layoutSize(target, false); minimum.width -= (getHgap() + 1); return minimum; } private Dimension layoutSize(Container target, boolean preferred) { synchronized (target.getTreeLock()) { // Each row must fit with the width allocated to the containter. // When the container width = 0, the preferred width of the container // has not yet been calculated so lets ask for the maximum. int targetWidth = target.getSize().width; if (targetWidth == 0) targetWidth = Integer.MAX_VALUE; int hgap = getHgap(); int vgap = getVgap(); Insets insets = target.getInsets(); int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); int maxWidth = targetWidth - horizontalInsetsAndGap; // Fit components into the allowed width Dimension dim = new Dimension(0, 0); int rowWidth = 0; int rowHeight = 0; int nmembers = target.getComponentCount(); for (int i = 0; i < nmembers; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); // Can't add the component to current row. Start a new row. if (rowWidth + d.width > maxWidth) { addRow(dim, rowWidth, rowHeight); rowWidth = 0; rowHeight = 0; } // Add a horizontal gap for all components after the first if (rowWidth != 0) { rowWidth += hgap; } rowWidth += d.width; rowHeight = Math.max(rowHeight, d.height); } } addRow(dim, rowWidth, rowHeight); dim.width += horizontalInsetsAndGap; dim.height += insets.top + insets.bottom + vgap * 2; // When using a scroll pane or the DecoratedLookAndFeel we need to // make sure the preferred size is less than the size of the // target containter so shrinking the container size works // correctly. Removing the horizontal gap is an easy way to do this. Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); if (scrollPane != null) { dim.width -= (hgap + 1); } return dim; } } /* * A new row has been completed. Use the dimensions of this row * to update the preferred size for the container. * * @param dim update the width and height when appropriate * @param rowWidth the width of the row to add * @param rowHeight the height of the row to add */ private void addRow(Dimension dim, int rowWidth, int rowHeight) { dim.width = Math.max(dim.width, rowWidth); if (dim.height > 0) { dim.height += getVgap(); } dim.height += rowHeight; } }
2、将被隐藏的按钮通过菜单的方式展示出来,通过判断按钮是否在ToolBar的可视区域以决定是否加入到Menu菜单中弹出。
/* * * @author zhangtao * * Msn & Mail: [email protected] */ package zht.popup.toolbar.pop; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JToolBar; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; public class PopupToolbarAdapter { private static JMenu menu = new JMenu(); private static JMenuItem item = new JMenuItem("Expand"); public static JComponent createPopupToolbar(final JToolBar toolbar) { JPanel panel = new JPanel(new BorderLayout(0, 0)); final JMenuBar menuBar = new JMenuBar(); menu.setBorder(BorderFactory.createCompoundBorder()); menu.setMargin(new Insets(0, 0, 0, 0)); menu.setIcon(new ImageIcon(PopupToolbarAdapter.class.getResource("image/more.gif"))); menu.getPopupMenu().addPopupMenuListener(new PopupMenuListener() { public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { setMenu(toolbar); } public void popupMenuCanceled(PopupMenuEvent e) { } }); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { expandMenu(); } }); menuBar.add(menu); panel.add(toolbar, BorderLayout.CENTER); panel.add(menuBar, BorderLayout.EAST); toolbar.addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { boolean b = isVisible(toolbar.getComponent(toolbar.getComponentCount() - 1), toolbar.getVisibleRect()); menuBar.setVisible(!b); setMenu(toolbar); } }); menuBar.setVisible(isVisible(toolbar.getComponent(toolbar.getComponentCount() - 1), toolbar.getVisibleRect())); return panel; } private static void setMenu(JToolBar toolbar) { Component[] comp = toolbar.getComponents(); Rectangle visibleRect = toolbar.getVisibleRect(); List list = new ArrayList(); menu.removeAll(); int sum = 0; for (int i = 0; i < comp.length; i++) { if (!isVisible(comp[i], visibleRect)) { for (; i < comp.length; i++) { if (sum < 8) { if (comp[i] instanceof AbstractButton) { AbstractButton button = (AbstractButton) comp[i]; if (button.getAction() != null) menu.add(button.getAction()); } else if (comp[i] instanceof JSeparator) { menu.addSeparator(); } sum++; if (sum == 8 && i < (comp.length - 1)) { menu.add(item); } } else { if (comp[i] instanceof AbstractButton) { AbstractButton button = (AbstractButton) comp[i]; if (button.getAction() != null) list.add(button.getAction()); } else if (comp[i] instanceof JSeparator) { list.add(comp[i]); } menu.putClientProperty("more", list); } } } } } private static void expandMenu() { Object obj = menu.getClientProperty("more"); if (obj != null) { List list = (List) obj; int size = list.size(); for (int i = 0; i < size; i++) { Object o = list.get(i); if (o instanceof Action) { menu.add((Action) o); } else if (o instanceof JSeparator) { menu.addSeparator(); } } } menu.remove(item); MenuElement newPath[] = new MenuElement[4]; newPath[0] = (MenuElement) menu.getParent(); newPath[1] = menu; newPath[2] = menu.getPopupMenu(); newPath[3] = (MenuElement) menu.getMenuComponent(8); // any menu item MenuSelectionManager.defaultManager().setSelectedPath(newPath); } private static boolean isVisible(Component comp, Rectangle rect) { return comp.getLocation().x + comp.getWidth() <= rect.getWidth(); } }