Get Only MonoSpaced Fonts?

Hi,

I’m loading the names of the fonts installed into a popup menu and is there a way to just get the monospaced fonts ?

Thanks.

You’d need system calls or a plugin.

Ah I see. Ok no probs. I was just curious.

Thanks.

How about using Graphics.StringWidth to measure two different characters?

Dim fonts() As String
Dim tmp As New Picture(64, 64, 24)
For i As Integer = FontCount - 1 DownTo 0
  Dim fontname As String = Font(i)
  tmp.Graphics.TextFont = fontname
  Dim a, b As Double
  a = tmp.Graphics.StringWidth("i")
  b = tmp.Graphics.StringWidth("A")
  If a = b Then
    fonts.Append(fontname)
  End If
Next
1 Like

Not a bad suggestion. I would refine it to make the comparison more dramatic: perhaps a capital W compared with a period.

Ah, I didn’t even think of that. Very cool thanks! :sunglasses:

I have never found that to be reliable, myself. Some fonts/characters report a width at variance with what the eye sees.

If anyone likes to use MBS Xojo Plugins to solve this, you would use code like this using NSFontDescriptorMBS and NSFontManagerMBS classes:

// ask for monospace font trait
Dim traitsAttributes As New Dictionary
traitsAttributes.Value(NSFontDescriptorMBS.NSFontSymbolicTrait) = NSFontDescriptorMBS.NSFontMonoSpaceTrait

// ask for traits
Dim fontAttributes As New Dictionary
fontAttributes.Value(NSFontDescriptorMBS.NSFontTraitsAttribute) = traitsAttributes

// now make a font descriptor for this
Dim fd As NSFontDescriptorMBS = NSFontDescriptorMBS.fontDescriptorWithFontAttributes(fontAttributes)

// and ask font manager for matching fonts
Dim fontManager As New NSFontManagerMBS
Dim fonts() As String = fontManager.availableFontNamesMatchingFontDescriptor(fd)

// finds e.g. AndaleMono, CourierNewPSMT, CourierNewPS-ItalicMT, CourierNewPS-BoldMT, CourierNewPS-BoldItalicMT, 
// FZLTXHB--B51-0, FZLTZHB--B51-0, FZLTTHB--B51-0, Menlo-Regular, Menlo-Italic, Menlo-Bold, Menlo-BoldItalic, 
// Monaco, Osaka-Mono, JCsmPC, PTMono-Regular, PTMono-Bold

But this you now have the list, you could even hard code it :slight_smile:

I needed too to list monospaced fonts, I compare those strings:

Const CstTxtTextLwL as String = "abcempqw" ' LowerCase Large
Const CstTxtTextUpL as String = "ABCEMPQW" ' UpperCase Large
Const CstTxtTextLwN as String = "dfijlstu" ' LowerCase Narrow
Const CstTxtTextUpN as String = "DFIJLSTU" ' UpperCase Narrow
Const CstTxtNbrL as String = "023456789" ' Number Large
Const CstTxtNbrN as String = "111111111" ' Number Narrow

and I do

TpImg.Graphics.FontName = TampText
If TpImg.Graphics.TextWidth(CstTxtNbrL) = TpImg.Graphics.TextWidth(CstTxtNbrN) Then
  If (TpImg.Graphics.TextWidth(CstTxtTextLwL) = TpImg.Graphics.TextWidth(CstTxtTextLwN)) and (TpImg.Graphics.TextWidth(CstTxtTextUpL) = TpImg.Graphics.TextWidth(CstTxtTextUpN)) Then
    ' MonoSpaced Font
  Else
    ' MonoSpaced Numbers Font
  End If
Else
  ' Normal Font
End If

I saw that some fonts were monospaced for numbers only, then I made a group for them too.
But it’s long, then I save my font list (in the same place than my PrefFile) and I load it at launch. I put a button in my pref panel so the user can click it to rebuild the Fonts array (Fonts menu).
I didn’t test if it was very quicker to get TextWidth of one character instead of 10 characters.

1 Like

Obviously, none of this string width comparison works with Fonts that only support other typefaces, for example:

  • Hebrew
  • Japanese
  • Chinese
  • Cyrillic
  • Symbols

and a whole slew of others. If the font doesn’t support the characters you are using the system will attempt to use a fallback font with similar properties. It won’t always be able to be successful.