Swing/MenuBarLayout のバックアップ(No.6)
- バックアップ一覧
 - 差分 を表示
 - 現在との差分 を表示
 - 現在との差分 - Visual を表示
 - ソース を表示
 - Swing/MenuBarLayout へ行く。
  
- 1 (2010-12-27 (月) 11:25:50)
 - 2 (2011-01-05 (水) 21:51:06)
 - 3 (2012-12-25 (火) 11:14:32)
 - 4 (2012-12-26 (水) 05:52:04)
 - 5 (2014-06-23 (月) 20:54:10)
 - 6 (2014-11-01 (土) 00:30:01)
 - 7 (2014-12-25 (木) 17:02:45)
 - 8 (2016-04-08 (金) 15:16:59)
 - 9 (2017-07-27 (木) 15:01:08)
 - 10 (2017-11-02 (木) 15:32:16)
 - 11 (2018-03-26 (月) 14:44:48)
 - 12 (2020-03-22 (日) 01:46:35)
 - 13 (2021-09-29 (水) 11:33:41)
 - 14 (2025-01-03 (金) 08:57:02)
 - 15 (2025-01-03 (金) 09:01:23)
 - 16 (2025-01-03 (金) 09:02:38)
 - 17 (2025-01-03 (金) 09:03:21)
 - 18 (2025-01-03 (金) 09:04:02)
 - 19 (2025-06-19 (木) 12:41:37)
 - 20 (2025-06-19 (木) 12:43:47)
 - 21 (2025-08-18 (月) 01:34:21)
 
 
- title: JMenuBarのJMenuを折り返し tags: [JMenuBar, JMenu, LayoutManager, FlowLayout] author: aterai pubdate: 2010-12-27T11:25:50+09:00 description: JMenuBarのレイアウトマネージャーを変更して、JMenuを折り返して表示します。
 
概要
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;
      if (targetWidth == 0) targetWidth = Integer.MAX_VALUE;
      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(デフォルトのLayoutManagerはBoxLayout)に、FlowLayoutを継承して折り返しを行うLayoutManagerを設定して、JMenuがフレームの幅に収まらない場合は折り返して表示するようにしています。
上記のサンプルでは、BorderLayoutを設定したJPanel#add(menubar, BorderLayout.NORTH)としてJMenuBarを追加していますが、JFrame#setJMenuBarメソッドを使用した場合、以下のような不具合?があります。
JFrameの最大化、最小化で折り返しが更新されない- 以下のような、
WindowStateListenerをJFrameに追加し、ContentPaneをrevalidate()して回避frame.addWindowStateListener(new WindowAdapter() { @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をオーバーライドすることで回避//http://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(...)に変更することで回避