0

I'm trying to add a JTextField as a search bar to a JMenuBar at the top of my JFrame. My problem is that the JTextField keeps getting resized to take up all available space in the JMenuBar, and I don't want it to. I've tried setPreferredSize() and setMaximum Size(), but these didnt work, presumably because the LayoutManager used in the JMenuBar doesn't respect these sizes. I also tried adding the JTextField to a JPanel with a FlowLayout and adding the panel to the JMenuBar, but I get something that looks like this:

The panel is on the right side of the JMenuBar, and the size seems to be correct, but I can't see anything in it other than this weird blue bar.

Here's the code that (I think) is relevant. Let me know if more is needed:

       JPanel searchPanel = new JPanel();
    searchPanel.setPreferredSize(new Dimension(100, 25));


    JTextField searchBar = new JTextField(50);

    String[] fields = {"title", "author", "subject", "publisher", "year", "circulating", "catalog" };


    JComboBox searchFields = new JComboBox(fields);

    JButton searchBtn = new JButton("search");

    searchPanel.add(searchBar);
    searchPanel.add(searchFields);
    searchPanel.add(searchBtn);
    searchPanel.setVisible(true);

    fileMenu.add(open);
    fileMenu.add(save);
    fileMenu.add(exit);

    libMenu.add(viewLib);
    libMenu.addSeparator();
    libMenu.add(newBook);
    libMenu.add(search);

    this.setJMenuBar(topBar);
       topBar.add(fileMenu);
    topBar.add(libMenu);
    topBar.add(Box.createHorizontalGlue());
   topBar.add(searchPanel);
mKorbel
  • 109,525
  • 20
  • 134
  • 319
drew moore
  • 31,565
  • 17
  • 75
  • 112
  • The `JMenuBar` has it's own layout manager which is likely ignoring your size hints – MadProgrammer Mar 06 '13 at 01:44
  • Yes I know, but surely there's a workaround here. It seems like the one I posted (adding the JTextField etc to a JPanel) would work, but the JPanel isn't displaying correctly, which is what I really don't understand – drew moore Mar 06 '13 at 01:46
  • The `JPanel` would be subject to the same restrictions as the `JTextField`...sorry, need a little thinking room about this ;) – MadProgrammer Mar 06 '13 at 01:56
  • [don't use setXXSize](http://stackoverflow.com/a/7229519/203657), for @splungebob that's _never-ever-ever_ true to at least 2nd approximation, that is extremely near the real value :-) Actually, I don't remember having seen a single use-case (in real world appliations as opposed to quick examples) in all these years where it didn't elicit more problems than it was supposed to solve. – kleopatra Mar 07 '13 at 16:06

2 Answers2

3

This works for me.

menuBar.add(Box.createHorizontalGlue());
JTextField textField = new JTextField(10);
textField.setMaximumSize( textField.getPreferredSize() );
menuBar.add(textField);

Post an SSCCE if you need more help.

Edit:

Again, the code is posted was just to show that the problem is in containing the maximum size of the text field. How you choose to do this is up to you.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • +1 for relying on [`getPreferredSize()`](http://stackoverflow.com/q/7229226/230513). – trashgod Mar 06 '13 at 06:33
  • Interesting that this worked. It's the exact same code I had before, only I had created the JTextField earlier in the code and added it to the menubar after creating the horizontalglue. For some reason, creating AND adding it after creating the glue made it work. Can anyone explain why this is? – drew moore Mar 06 '13 at 08:48
  • arrggg ... that's still _hard-coding_ the max to the current pref, which is a **bad idea** for all the known reasons. Instead override and let getMax return getPref – kleopatra Mar 07 '13 at 15:40
3

My solution is similar to camickr's, but without the need for setMaximumSize(). Not that I'm against it, but I know there are zealots on SO who swear by "never ever ever ever call setXxxsize() EVER!!!" I'm not one of them, but they're out there.

Anyway, I'd make a JPanel with GridBagLayout, and put the JTextField in it with a fill of NONE, and a Box.createHorizontalGlue() with a fill of HORIZONTAL. Then, put this panel in your menubar.

EDIT:

For completeness, here's a solution using a JPanel w/o having to call setMaximumSize(...)
(and thus avoid burning in hell for all eternity... according to some):

GridBagConstraints gbc = new GridBagConstraints();
JPanel gbPanel = new JPanel(new GridBagLayout());
gbc.gridx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbPanel.add(Box.createHorizontalGlue(), gbc);
gbc.gridx = 1;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
gbPanel.add(new JTextField(10), gbc);
menuBar.add(gbPanel);

Some comments:
1) Man, I forgot how verbose GBL is. Normally I use a helper class that reduces the code greatly, but I didn't feel like posting it for such a small example.

2) If going the panel route, camickr's suggestion (see comment below) of using BorderLayout not only works, but is far simpler code.

3) Also, as camickr pointed out, using a panel affects the appearance of the "glue" area. It gets painted like a JPanel instead of a JMenuBar. Honestly, I didn't even notice it on my machine (using Metal L&F) until he mentioned it, but it IS different and may be an undesireable side-effect.

splungebob
  • 5,357
  • 2
  • 22
  • 45
  • @camickr's approach does not violate the principle, as it relies on [`getPreferredSize()`](http://stackoverflow.com/q/7229226/230513). – trashgod Mar 06 '13 at 06:36
  • 1
    @trashgod: I think it does violate "The NEVER Principle" for 2 reasons: (1) It sets the max size ONCE, meaning that if pref size changes later, max doesn't. (2) The claim is "never". As in "NEVER EVER EVER" (as I have seen it written). No qualifications or exceptions, which is why I basically disagree with this absolute. If instead, it were a "strongly recommended guideline", then I'd agree. Just my 2c. – splungebob Mar 06 '13 at 14:39
  • You are correct any use of `setMaximumSize()` should be examined critically for unintended consequences. +1 for an alternative. – trashgod Mar 06 '13 at 15:17
  • I'm not a GridBagLayout expert but I tried your suggestion and couldn't get it to work. The problem is that the panel seems to increase in size since it has no maximum. I ended up trying a panel with a BorderLayout and added the text field to the EAST. This worked, but the problem is the menubar "gap" now paints like a panel – camickr Mar 06 '13 at 17:01
  • I like your 2c and totally agree. The only consequence I'm aware of would be if, in the future, you add the ability to dynamically change the LAF you would have problems. The main point of my answer was to show the the problem was in containing the maximum size. – camickr Mar 06 '13 at 17:03
  • @kleopatra, I guess we agree to disagree :). Once again you support a solution that breaks the LAF of the component. I believe applications are about users. It should work and look like the user expects. Using this approach it will alway look wrong no matter what LAF you use. Using the simple approach it will only potentially break if there is a change in user requirements. – camickr Mar 07 '13 at 16:48
  • @camickr seems we disagree a lot recently :-) Anyway, **the** solution to layout problems is a suitable LayoutManager vs. tweaking layout hints on the component level. Using the former will not even show any of the problems so often seen, doing the latter approach you get the worst of all worlds, most probably even violating the pref <= max if the columns are reset and the text grows. – kleopatra Mar 07 '13 at 16:53
  • 1
    @kleopatra, I don't disagree technically with anything you say. The menubar already uses a custom layout maanger so you would need to customize a custom layout manager. Most people asking questions like this are not working on large projects (or they would ask people on the project for help). Most are students learning the language independently. It would be a daunting task for them to continually rewrite Swing base classes and they would be turned off using Swing. When I don't have a perfect solution, I try to suggest reasonable approaches that allows them to learn and explore. – camickr Mar 07 '13 at 17:42