Tomáš Zato
Tomáš Zato

Reputation: 53190

Tell Swing to recalculate JMenu width when I change text contents of JMenuItem

I've been a little lazy and instead of making another window, I created single menu for my update manager. I plan on making the window, but there are more important tasks to attend, so this must just do for now:

image description

Clicking on that last menu item dynamically changes the text when there's an update. If the user is viewing the menu item at that moment, the size of the JMenu doesn't change:

image description

If I move mouse away and navigate back to the menu, the size is correct:

image description

I need to tell Swing to update size of the JMenuItem when I change the text. I have a class called UpdateMenuItem which extends the JMenuItem with functions like this:

  public void setDownloadAvailable(final VersionId version) {
    // Checking if the code runs in correct thread
    // this should probably also raise a warning if not in the swing thread
    if(!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(()->setDownloadAvailable(version));
      return;
    }
    // this is how the menu text changes
    setText("Click to download: "+version);
    setBackground(Color.ORANGE);
  }

I need to add appropriate code after the setText call to have the size of the item correctly updated. What method should I call?

Upvotes: 1

Views: 1286

Answers (1)

aterai
aterai

Reputation: 9818

JMenu#getPopupMenu() and JPopupMenu#pack() works fine for me:

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

public class JMenuItemPackTest {
  public JMenuBar makeMenuBar() {
    JMenuItem label = new JMenuItem("Up to date: 3.5-beta");
    label.setBackground(Color.GREEN);
//     UpdateMenuItem label = new UpdateMenuItem("Up to date: 3.5-beta") {
//       @Override public void setDownloadAvailable(final VersionId version) {
//         super.setDownloadAvailable(version);
//         Container c = SwingUtilities.getUnwrappedParent(this);
//         if (c instanceof JPopupMenu) {
//           ((JPopupMenu) c).pack();
//         }
//       }
//     };

    JMenu update = new JMenu("Updates");
    update.add(new JCheckBoxMenuItem("Auto-check for updates"));
    update.add(new JCheckBoxMenuItem("Auto-download"));
    update.add(label);

    JMenu menu = new JMenu("Help");
    menu.add(update);

    (new Timer(5000, e -> {
      //...
      label.setText("Click to download: 3.5-beta");
      label.setBackground(Color.ORANGE);
      update.getPopupMenu().pack();
      //or:
      //Container c = SwingUtilities.getUnwrappedParent(label);
      //if (c instanceof JPopupMenu) {
      //  ((JPopupMenu) c).pack();
      //}
    })).start();

    JMenuBar menubar = new JMenuBar();
    menubar.add(menu);
    return menubar;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.setJMenuBar(new JMenuItemPackTest().makeMenuBar());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

Upvotes: 1

Related Questions