0

In some cases, the title of my JDialog is too long to fit within the title bar. The preferred size of the dialog is therefore set according to the length of the title.
I used the accepted answer of the question How to set dialog's width relative to the width of its title? but it does not solve my problem.

When running this code:

package test;

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

@SuppressWarnings("serial")
public class DialogTitleSize extends JDialog
{
  public DialogTitleSize()
  {
    setModal(true);
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    setLayout(new BorderLayout());
    setTitle("This is a very long title. Enough for the preferred size to be extended");
    JLabel label;
    label = new JLabel("Look and feel: " + UIManager.getLookAndFeel().getClass().getSimpleName());
    add(label, BorderLayout.NORTH);
    label = new JLabel("Label font: " + UIManager.getDefaults().getFont("Label.font").getSize());
    add(label, BorderLayout.SOUTH);
  }

  @Override
  public Dimension getPreferredSize()
  {
    Dimension result;
    result = super.getPreferredSize();
    if (getTitle() != null)
    {
      Font font;
      int  titleStringWidth;
      font = UIManager.getDefaults().getFont("Label.font");
      titleStringWidth = SwingUtilities.computeStringWidth(new JLabel().getFontMetrics(font), getTitle());
      titleStringWidth += 135;
      if (titleStringWidth > result.width)
        result.width = titleStringWidth;
    }
    return (result);

  } // getPreferredSize

  public static void main(String[] args)
  {
    try
    {
      UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
      DialogTitleSize dialog;
      dialog = new DialogTitleSize();
      dialog.pack();
      dialog.setVisible(true);
    }
    catch (Exception exception)
    {
      exception.printStackTrace();
    }
  }

} // class DialogTitleSize

I get different results on different environments.

When running directly from within Eclipse 2022-03 on my Windows 10 PC, I get this: enter image description here

Running the very same code directly from the command line on my Windows 10 PC, the output is as follows:
enter image description here

Finally, when running the code from the command line on a Windows Server 2012 R2, I get this: enter image description here

I tried adding JDialog.setDefaultLookAndFeelDecorated(true); before creating the dialog, as suggested within the accepted answer of Font size of JDialog title, but the result doesn't change.

Both my PC and the Windows Server have Java 8 while Eclipse runs Java 18.

Any idea how to solve this problem?

Robert Kock
  • 5,795
  • 1
  • 12
  • 20
  • 2
    I’m not surprised that this approach doesn’t work. There is no reason to assume that a window title uses `Label.font` rather than something like `Title.font` or `Frame.font`. However, this would only apply to Look&Feel-decorated frames anyway but the Windows Look&Feel doesn’t support window decorations. The title is therefore provided by the native window manager and may have an entirely different font, rendered with entirely different spacing/ kerning/ anti-alias/ DPI scaling as Swing labels. – Holger Aug 23 '23 at 09:16
  • Basic ergonomic rules state that you must not use too long titles. – Jean-Baptiste Yunès Aug 29 '23 at 08:17

1 Answers1

0

I figured it out myself:

It seems that within a Windows environment, the window decorations are always delegated to the OS, independently of the L&F. I tried them all (Motif, Metal, Nimbus) and everytime I get the same layout for the title bar and its buttons.
Thank you Holger for you valuable comment.

The font used within the Window title is stored in some very cryptical format in the Windows registry underneath the key HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\CaptionFont.
The name and size of the font can be extracted from its binary value.
I got the corresponding algorithm from here.

So instead of font = UIManager.getDefaults().getFont("Label.font"), I pass the font extracted from the registry to SwingUtilities.computeStringWidth(...).

UPDATE
Again thanks to Holger and the answer to this question, I improved the solution as follows:

// ---------------------------------
// Determine font used for the title
// ---------------------------------
Font titleFont;
if (OsUtils.getOperatingSystem() == OperatingSystem.WINDOWS)
  titleFont = (Font)Toolkit.getDefaultToolkit().getDesktopProperty("win.frame.captionFont");
else
{
  Component titleBar;
  titleBar = getLayeredPane().getComponents()[1];
  titleFont = titleBar.getFont();
}

The method OsUtils.getOperatingSystem() is not standard. I wrote it for other purposes and appears very useful in thas case. Its implementation goes beyond the scope of this question.

I didn't test it in a non-windows environment.

Robert Kock
  • 5,795
  • 1
  • 12
  • 20
  • 2
    That’s just an educated guess but is it the same font you get when calling `.getToolkit().getDesktopProperty("win.frame.captionFont")` on your Window? Btw, as far as I know, the Metal Look&Feel does support `setDefaultLookAndFeelDecorated(true)` (as the only one of the pre-installed L&Fs). – Holger Aug 24 '23 at 09:09
  • @Holger Thanks again. That property is exactly what I was looking for. As far as you know, this property is available on other OSs as well? I got unix here but I access it by means of PuTTY and in that case the property returns NULL. Maybe because of the lack of a GUI. – Robert Kock Aug 24 '23 at 10:20
  • 1
    Unfortunately, these things are badly (or not at all) documented. I can see this property handled by the Windows specific toolkit implementation, but I can’t check whether other toolkits have support for the same property (name). All I can say, is that it is not in the base class. – Holger Aug 24 '23 at 10:37