1

I'm fairly new to Java so I hopefully I don't over complicate my question.

Basically I'm trying to add two JToolbar vertically on top of one another to the north container of a border layout. However, I don't think you can add more than one JToolbar to single positional container within a border layout so my possible solution to this I thought would be to embed a borderlayout within a borderlayout and place one in the north and the other in the centre but I don't know how to achieve this. Any advice on what is the best solution to achieve this would be greatly appreciated.

Below is the source code for my program. For the purpose of making my program run, the second JToolbar I want too position under the "bar" JToolbar has been place in the south container.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FeedBar2 extends JFrame {

public FeedBar2() {
    super("FeedBar 2");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // create icons
    ImageIcon loadIcon = new ImageIcon("load.gif");
    ImageIcon saveIcon = new ImageIcon("save.gif");
    ImageIcon subscribeIcon = new ImageIcon("subscribe.gif");
    ImageIcon unsubscribeIcon = new ImageIcon("unsubscribe.gif");
    // create buttons
    JButton load = new JButton("Load", loadIcon);
    JButton save = new JButton("Save", saveIcon);
    JButton subscribe = new JButton("Subscribe", subscribeIcon);
    JButton unsubscribe = new JButton("Unsubscribe", unsubscribeIcon);

    //create help buttons
    JButton help = new JButton("Help");
    JButton about = new JButton("About");
    JButton contact = new JButton("Contact Us");

    // add buttons to toolbar
    JToolBar bar = new JToolBar();
    bar.add(load);
    bar.add(save);
    bar.add(subscribe);
    bar.add(unsubscribe);

    //add buttons to help toolbar
    JToolBar helpbar = new JToolBar();
    helpbar.add(help);
    helpbar.add(about);
    helpbar.add(contact);

    // create dropdown menu
    JMenuItem j1 = new JMenuItem("Load");
    JMenuItem j2 = new JMenuItem("Save");
    JMenuItem j3 = new JMenuItem("Subscribe");
    JMenuItem j4 = new JMenuItem("Unsubscribe");
    JMenuItem h1 = new JMenuItem("Help");
    JMenuItem h2 = new JMenuItem("About");
    JMenuItem h3 = new JMenuItem("Contact Us");
    JMenuBar menubar = new JMenuBar();
    JMenuBar helpmenubar = new JMenuBar();
    JMenu menu = new JMenu("Feeds");
    menu.add(j1);
    menu.add(j2);
    menu.addSeparator();
    menu.add(j3);
    menu.add(j4);


    JMenu helpmenu = new JMenu("Help");
    helpmenu.add(h1);
    helpmenu.add(h2);
    helpmenu.add(h3);
    menubar.add(menu);
    menubar.add(helpmenu);

    // prepare user interface
    JTextArea edit = new JTextArea(8, 40);

    JScrollPane scroll = new JScrollPane(edit);

   BorderLayout bord = new BorderLayout();


   //Looking for the "help bar" to be vertically placed under the "bar" 
   //toolbar.

    setLayout(bord); 
    add("North", bar);
    add("Center", scroll);
    add("South", helpbar);

    setJMenuBar(menubar);



    pack();
    setVisible(true);
}

public static void main(String[] arguments) {
    FeedBar2 frame = new FeedBar2();
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
user2994367
  • 11
  • 1
  • 7

2 Answers2

1

I would use a GridLayout:

//setLayout(bord); // the default layout of a frame is a BorderLayout
//add("North", bar); // don't use String literals, the API has variables for you to use
//add("Center", scroll);
//add("South", helpbar);


JPanel toolbars = new JPanel( new GridLayout(0, 1) );
toolbars.add(bar);
toolbars.add(helpBar);

add(toolBars, BorderLayout.NORTH)
add(scroll, BorderLayout.CENTER);
camickr
  • 321,443
  • 19
  • 166
  • 288
0

Based on this code (http://java-sl.com/tip_multiple_floatable_toolbars.html) from Stanislav Lapitsky, here is a working implementation for a new Layout that behaves similar to a BorderLayout, but you can add more than one child per location, including toolbars:


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * Extends BorderLayout with multiple components in the northList, southList,
 * eastList, westList and centerList. Layout is used for correct working
 * multiple toolbars.
 *
 * @author Stanislav Lapitsky
 * @version 1.0
 */

public class MultiBorderLayout implements LayoutManager2, java.io.Serializable {
  private int vgap;
  private int hgap;
  /**
   * list of the northList region components
   */
  private Vector<Component> northList = new Vector<>();

  /**
   * list of the southList region components
   */
  private Vector<Component> southList = new Vector<>();

  /**
   * list of the westList region components
   */
  private Vector<Component> westList = new Vector<>();

  /**
   * list of the eastList region components
   */
  private Vector<Component> eastList = new Vector<>();

  /**
   * list of the centerList region components
   */
  private Vector<Component> centerList = new Vector<>();

  /**
   * Constructs default layout instance.
   */
  public MultiBorderLayout() {
    this( 0, 0 );
  }

  /**
   * Constructs new layout instance with defined parameters.
   *
   * @param hgap the horizontal gap.
   * @param vgap the vertical gap.
   */
  public MultiBorderLayout( int hgap, int vgap ) {
    this.hgap = hgap;
    this.vgap = vgap;
  }

  /**
   * Returns the horizontal gap between components.
   *
   * @return the horizontal gap between components
   */
  public int getHgap() {
    return hgap;
  }

  /**
   * Sets the horizontal gap between components.
   *
   * @param hgap the horizontal gap between components
   */
  public void setHgap( int hgap ) {
    this.hgap = hgap;
  }

  /**
   * Returns the vertical gap between components.
   *
   * @return the vertical gap between components
   */
  public int getVgap() {
    return vgap;
  }

  /**
   * Sets the vertical gap between components.
   *
   * @param vgap the vertical gap between components
   */
  public void setVgap( int vgap ) {
    this.vgap = vgap;
  }

  private List<Component> getComponentList( Object constraint ) {
    if ( BorderLayout.CENTER.equals( constraint ) ) {
      return centerList;
    }
    if ( BorderLayout.NORTH.equals( constraint ) ) {
      return northList;
    }
    if ( BorderLayout.SOUTH.equals( constraint ) ) {
      return southList;
    }
    if ( BorderLayout.EAST.equals( constraint ) ) {
      return eastList;
    }
    if ( BorderLayout.WEST.equals( constraint ) ) {
      return westList;
    }

    throw new IllegalArgumentException( "Unknown constraint: " + constraint );
  }

  /**
   * Removes the specified component from this border layout. This method is
   * called when a container calls its <code>remove</code> or
   * <code>removeAll</code> methods. Most applications do not call this method
   * directly.
   *
   * @param comp the component to be removed.
   */
  public void removeLayoutComponent( Component comp ) {
    synchronized ( comp.getTreeLock() ) {
      southList.remove( comp );
      northList.remove( comp );
      centerList.remove( comp );
      westList.remove( comp );
      eastList.remove( comp );
    }
  }

  /**
   * Determines the minimum size of the <code>target</code> container using this
   * layout manager.
   * <p>
   *
   * This method is called when a container calls its <code>getMinimumSize</code>
   * method. Most applications do not call this method directly.
   *
   * @param target the container in which to do the layout.
   * @return the minimum dimensions needed to lay out the subcomponents of the
   *         specified container.
   */
  public Dimension minimumLayoutSize( Container target ) {
    synchronized ( target.getTreeLock() ) {
      Dimension dim = new Dimension( 0, 0 );

      Component c;

      if ( eastList.size() > 0 ) {
        for ( int i = 0; i < eastList.size(); i++ ) {
          c = (Component) eastList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getMinimumSize();
          dim.width += d.width + this.getHgap();
          dim.height = Math.max( d.height, dim.height );
        }
      }
      if ( westList.size() > 0 ) {
        for ( int i = 0; i < westList.size(); i++ ) {
          c = (Component) westList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getMinimumSize();
          dim.width += d.width + this.getHgap();
          dim.height = Math.max( d.height, dim.height );
        }
      }
      if ( centerList.size() > 0 ) {
        for ( int i = 0; i < centerList.size(); i++ ) {
          c = (Component) centerList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getMinimumSize();
          dim.width += d.width;
          dim.height = Math.max( d.height, dim.height );
        }
      }
      if ( northList.size() > 0 ) {
        for ( int i = 0; i < northList.size(); i++ ) {
          c = (Component) northList.get( i );
          if ( !c.isVisible() ) {

            continue;
          }
          Dimension d = c.getMinimumSize();
          dim.width = Math.max( d.width, dim.width );
          dim.height += d.height + this.getVgap();
        }
      }
      if ( southList.size() > 0 ) {
        for ( int i = 0; i < southList.size(); i++ ) {
          c = (Component) southList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getMinimumSize();
          dim.width = Math.max( d.width, dim.width );
          dim.height += d.height + this.getVgap();
        }
      }

      Insets insets = target.getInsets();
      dim.width += insets.left + insets.right;
      dim.height += insets.top + insets.bottom;

      return dim;
    }

  }

  /**
   * Determines the preferred size of the <code>target</code> container using this
   * layout manager, based on the components in the container.
   * <p>
   *
   * Most applications do not call this method directly. This method is called
   * when a container calls its <code>getPreferredSize</code> method.
   *
   * @param target the container in which to do the layout.
   * @return the preferred dimensions to lay out the subcomponents of the
   *         specified container.
   */

  @Override
  public Dimension preferredLayoutSize( Container target ) {
    synchronized ( target.getTreeLock() ) {
      Dimension dim = new Dimension( 0, 0 );

      Component c;

      if ( eastList.size() > 0 ) {
        for ( int i = 0; i < eastList.size(); i++ ) {
          c = (Component) eastList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          dim.width += d.width + this.getHgap();
          dim.height = Math.max( d.height, dim.height );
        }
      }

      if ( westList.size() > 0 ) {
        for ( int i = 0; i < westList.size(); i++ ) {
          c = (Component) westList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          dim.width += d.width + this.getHgap();
          dim.height = Math.max( d.height, dim.height );
        }
      }

      if ( centerList.size() > 0 ) {
        for ( int i = 0; i < centerList.size(); i++ ) {
          c = (Component) centerList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          dim.width += d.width;
          dim.height = Math.max( d.height, dim.height );
        }
      }

      if ( northList.size() > 0 ) {
        for ( int i = 0; i < northList.size(); i++ ) {
          c = (Component) northList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          dim.width = Math.max( d.width, dim.width );
          dim.height += d.height + this.getVgap();
        }
      }

      if ( southList.size() > 0 ) {
        for ( int i = 0; i < southList.size(); i++ ) {
          c = (Component) southList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          dim.width = Math.max( d.width, dim.width );
          dim.height += d.height + this.getVgap();
        }
      }

      Insets insets = target.getInsets();
      dim.width += insets.left + insets.right;
      dim.height += insets.top + insets.bottom;

      return dim;
    }
  }

  /**
   * Lays out the container argument using this border layout.
   * <p>
   *
   * This method actually reshapes the components in the specified container in
   * order to satisfy the constraints of this <code>BorderLayout</code> object.
   * The <code>NORTH</code> and <code>SOUTH</code> components, if any, are placed
   * at the top and bottom of the container, respectively. The <code>WEST</code>
   * and <code>EAST</code> components are then placed on the left and right,
   * respectively. Finally, the <code>CENTER</code> object is placed in any
   * remaining space in the middle.
   * <p>
   *
   * Most applications do not call this method directly. This method is called
   * when a container calls its <code>doLayout</code> method.
   *
   * @param target the container in which to do the layout.
   */
  public void layoutContainer( Container target ) {
    synchronized ( target.getTreeLock() ) {
      Insets insets = target.getInsets();
      int top = insets.top;
      int bottom = target.getHeight() - insets.bottom;
      int left = insets.left;
      int right = target.getWidth() - insets.right;

      Component c;

      if ( northList.size() > 0 ) {
        for ( int i = 0; i < northList.size(); i++ ) {
          c = (Component) northList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          c.setSize( right - left, d.height );
          c.setBounds( left, top, right - left, c.getHeight() );
          top += d.height;
        }
      }

      if ( southList.size() > 0 ) {
        for ( int i = 0; i < southList.size(); i++ ) {
          c = (Component) southList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          c.setSize( right - left, d.height );
          c.setBounds( left, bottom - d.height, right - left, c.getHeight() );
          bottom -= d.height;
        }
      }

      if ( eastList.size() > 0 ) {
        for ( int i = 0; i < eastList.size(); i++ ) {
          c = (Component) eastList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          c.setSize( d.width, bottom - top );
          c.setBounds( right - d.width, top, c.getWidth(), bottom - top );
          right -= d.width;
        }
      }

      if ( westList.size() > 0 ) {
        for ( int i = 0; i < westList.size(); i++ ) {
          c = (Component) westList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          Dimension d = c.getPreferredSize();
          c.setSize( d.width, bottom - top );
          c.setBounds( left, top, c.getWidth(), bottom - top );
          left += d.width;
        }
      }

      if ( centerList.size() > 0 ) {
        for ( int i = 0; i < centerList.size(); i++ ) {
          c = (Component) centerList.get( i );
          if ( !c.isVisible() ) {
            continue;
          }
          c.setBounds( left, top, right - left, bottom - top );
        }
      }

    }
  }

  public List<Component> getLayoutComponents( Object constraints ) {
    if ( ( constraints == null ) || ( constraints instanceof String ) ) {
      // Return copy, don't expose internal Vectors
      return new ArrayList<>( getComponentList( constraints == null ? BorderLayout.CENTER : (String) constraints ) );
    }
    throw new IllegalArgumentException( "Cannot get layout components: constraint must be a string (or null)" );
  }

  /**
   * Adds the specified component to the layout, using the specified constraint
   * object. For border layouts, the constraint must be one of the following
   * constants: <code>NORTH</code>, <code>SOUTH</code>, <code>EAST</code> ,
   * <code>WEST</code>, or <code>CENTER</code>.
   * <p>
   *
   * Most applications do not call this method directly. This method is called
   * when a component is added to a container using the <code>Container.add</code>
   * method with the same argument types.
   *
   * @param name The feature to be added to the LayoutComponent attribute.
   * @param comp the component to be added.
   */

  @Override
  public void addLayoutComponent( Component comp, Object constraints ) {
    synchronized ( comp.getTreeLock() ) {
      if ( ( constraints == null ) || ( constraints instanceof String ) ) {
        addLayoutComponent( (String) constraints, comp );
      } else {
        throw new IllegalArgumentException( "cannot add to layout: constraint must be a string (or null)" );
      }
    }
  }

  /**
   * Returns the maximum dimensions for this layout given the components in the
   * specified target container.
   * 
   * @param target the component which needs to be laid out
   * @see Container
   * @see #minimumLayoutSize
   * @see #preferredLayoutSize
   */
  @Override
  public Dimension maximumLayoutSize( Container target ) {
    return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
  }

  /**
   * Returns the alignment along the x axis. This specifies how the component
   * would like to be aligned relative to other components. The value should be a
   * number between 0 and 1 where 0 represents alignment along the origin, 1 is
   * aligned the furthest away from the origin, 0.5 is centered, etc.
   */
  public float getLayoutAlignmentX( Container parent ) {
    return 0.5f;
  }

  /**
   * Returns the alignment along the y axis. This specifies how the component
   * would like to be aligned relative to other components. The value should be a
   * number between 0 and 1 where 0 represents alignment along the origin, 1 is
   * aligned the furthest away from the origin, 0.5 is centered, etc.
   */
  public float getLayoutAlignmentY( Container parent ) {
    return 0.5f;
  }

  @Override
  public void invalidateLayout( Container target ) {
  }

  @Override
  public void addLayoutComponent( String name, Component comp ) {

    synchronized ( comp.getTreeLock() ) {
      /*
       * Special case: treat null the same as "Center".
       */
      if ( name == null ) {
        name = "Center";
      }

      getComponentList( name ).add( comp );

    }
  }

}

The original code has a typo in the method name preferredLayoutSize, also it extends BorderLayout inheriting some methods (i.e. public Component getLayoutComponent(Object constraints)) or assumptions that don't make sense for this case.

Aldo Canepa
  • 1,791
  • 2
  • 16
  • 16