JMenuBarのJMenuを折り返し
Total: 6240
, Today: 1
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
JMenuBar
のレイアウトマネージャーを変更して、JMenu
を折り返して表示します。
Screenshot
Advertisement
サンプルコード
JMenuBar menuBar = new JMenuBar();
menuBar.setLayout(new FlowLayout(FlowLayout.LEFT, 2, 2) {
@Override public Dimension preferredLayoutSize(Container target) {
synchronized (target.getTreeLock()) {
int targetWidth = target.getSize().width;
targetWidth = targetWidth == 0 ? Integer.MAX_VALUE : targetWidth;
Insets insets = target.getInsets();
int hgap = getHgap();
int vgap = getVgap();
int maxWidth = targetWidth - (insets.left + insets.right);
int height = vgap;
int rowWidth = hgap, rowHeight = 0;
int nmembers = target.getComponentCount();
for (int i = 0; i < nmembers; i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = m.getPreferredSize();
if (rowWidth + d.width > maxWidth) {
height += rowHeight;
rowWidth = hgap;
rowHeight = 0;
}
rowWidth += d.width + hgap;
rowHeight = Math.max(rowHeight, d.height + vgap);
}
}
height += rowHeight + insets.top + insets.bottom;
return new Dimension(targetWidth, height);
}
}
});
View in GitHub: Java, Kotlin解説
上記のサンプルでは、JMenuBar
にFlowLayout
を継承して折り返しを行うLayoutManager
を設定して(JMenuBar
のデフォルトLayoutManager
はBoxLayout
)、内部のJMenu
などがフレームの幅に収まらない場合は折り返して表示しています。
BorderLayout
を設定したJPanel#add(menubar, BorderLayout.NORTH)
としてJMenuBar
を追加してJFrame#setJMenuBar(...)
メソッドを使用した場合、以下のような不具合が存在する?JFrame
の最大化、最小化で折り返しが更新されない- 以下のような
WindowStateListener
をJFrame
に追加し、ContentPane
をrevalidate()
して回避frame.addWindowStateListener(new WindowStateListener() { @Override public void windowStateChanged(final WindowEvent e) { EventQueue.invokeLater(new Runnable() { @Override public void run() { System.out.println("windowStateChanged"); JFrame f = (JFrame) e.getWindow(); ((JComponent) f.getContentPane()).revalidate(); } }); } }); // frame.getContentPane().addComponentListener(new ComponentAdapter() { // @Override public void componentResized(ComponentEvent e) { // ((JComponent) e.getSource()).revalidate(); // } // });
- または、以下のように
FlowLayout#layoutContainer
をオーバーライドすることで回避// https://tips4java.wordpress.com/2008/11/06/wrap-layout/ // WrapLayout.java // Rob Camick on November 6, 2008 private Dimension preferredLayoutSize; @Override public void layoutContainer(Container target) { Dimension size = preferredLayoutSize(target); if (size.equals(preferredLayoutSize)) { super.layoutContainer(target); } else { preferredLayoutSize = size; Container top = target; while (!(top instanceof Window) && top.getParent() != null) { top = top.getParent(); } top.validate(); } }
JFrame#pack()
してもJFrame
のサイズが変更されないJFrame#setSize(...)
に変更することで回避