Results 1 to 7 of 7
  1. #1
    johnrdorazio is offline Member
    Join Date
    Sep 2014
    Posts
    4
    Rep Power
    0

    Question Pre-render a JComboBox list

    I am trying to make somewhat of a "Font Chooser" Combobox.
    I created a custom ListCellRenderer that will set the font for each cell to the listed font name:

    import java.awt.Component;
    import java.awt.Font;
    import javax.swing.DefaultListCellRenderer;
    import javax.swing.JList;
    import javax.swing.UIManager;

    Java Code:
    /**
     *
     * @author Lwangaman
     */
    public class FontFamilyListCellRenderer extends DefaultListCellRenderer{    
    
        public FontFamilyListCellRenderer()
        {
            // Set opaque for the background to be visible
            setOpaque(true);
        }
    
        @Override
        public Component getListCellRendererComponent(JList list,Object val,int idx,boolean isSelected,boolean cellHasFocus)
        {
            // Set text (mandatory)
            setText(val.toString());
    
            // Set the font according to the selected index
            setFont(new Font(val.toString(),Font.PLAIN,18));
    
            if(isSelected){
                setBackground(list.getSelectionBackground());
                setForeground(list.getSelectionForeground());
            }
            else{
                setBackground(list.getBackground());
                setForeground(list.getForeground());
            }
            
            if(cellHasFocus){
                setBorder(UIManager.getBorder("List.focusCellHighlightBorder"));
            }
            else{
                setBorder(noFocusBorder);
            }
    
            return this;
        }
    
    }
    I use this to render my JComboBox:

    Java Code:
    private final FontFamilyListCellRenderer FFLCRenderer = new FontFamilyListCellRenderer();
    private jComboBox1 = new javax.swing.JComboBox();
    private final paragraphFontFamily = "Garamond";
    private final fontfamilies = getFonts();
    
            jComboBox1.setFont(new java.awt.Font(paragraphFontFamily, java.awt.Font.PLAIN, 18));
            jComboBox1.setMaximumRowCount(6);
            jComboBox1.setModel(fontFamilies);
            jComboBox1.setSelectedItem(paragraphFontFamily);
            jComboBox1.setRenderer(FFLCRenderer);
            jToolBar1.add(jComboBox1);
    It works, but it is very very slow to load when I click on the ComboBox for the first time. Once it has loaded the first time, the list opens immediately on any successive clicks.

    So I am wondering if there is any way to pre-load or pre-render the list so it doesn't take so long the first time.

  2. #2
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    12,059
    Rep Power
    25

    Default Re: Pre-render a JComboBox list

    Quote Originally Posted by johnrdorazio View Post
    Java Code:
    private jComboBox1 = new javax.swing.JComboBox();
    private final paragraphFontFamily = "Garamond";
    private final fontfamilies = getFonts();
    That's not valid Java code. Be more careful in future.

    Instead of populating the combo with the default fonts and creating a new Font every time through the renderer, populate the combo with an array of Fonts that can directly be used for rendering.

    Download the code at Visual Font Designer Java Tips Weblog and take a look at VisualFontDesigner.java around lines 512-519 (line numbers may have changes slightly since the code was uploaded). The JWS demo doesn't seem to work any more after the introduction of new security features in Java, so if you want to give it a trial run you'll have to download all 4 related classes and compile it yourself.

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  3. #3
    johnrdorazio is offline Member
    Join Date
    Sep 2014
    Posts
    4
    Rep Power
    0

    Default Re: Pre-render a JComboBox list

    Thanks for the reply, that looks like it could be just what I was looking for, I'll look into it.

    I would however like to understand what you mean by this not being "valid java code", what is it that is not valid? If you refer to the "getFonts()" method, this is a method I have written to populate with an array of system fonts, it returns a DefaultComboBoxModel object.

    And what exactly do you mean by "rather than populate with default fonts, populate with an array of fonts that can directly be used for rendering". I don't understand, can't all the fonts installed on any user's system be "directly used for rendering"?

    As for the JWS demo it did work for me, I see that in the demo however there are a few problems that I was having myself i.e. some fonts not rendering correctly, leaving big empty spaces in the Combox's ListCells (maybe that's what you were referring to?).

    UPDATE:
    I've taken a look at the VisualFontDesigner.java code, and I see they are implementing a custom class that extends the JComboBox, and the fonts are being created directly in this model instead of being created afterwards in the renderer. That makes sense and I think I can implement this extended model. Anyways they are creating the list of fonts exactly the same way I was, by getting an array of fonts / font-family names installed on the user's system.
    Last edited by johnrdorazio; 09-28-2014 at 12:09 AM.

  4. #4
    johnrdorazio is offline Member
    Join Date
    Sep 2014
    Posts
    4
    Rep Power
    0

    Default Re: Pre-render a JComboBox list

    In the meantime, I have implemented the code from VisualFontDesigner, but for some reason it is still very slow opening the ComboBox the first time round. The fonts are being created outside of the renderer, but I guess for some reason are not loaded in memory? Here is my implementation, based on their code:

    Java Code:
    /**
     *
     * @author Lwangaman
     */
    public class OptionsFrame extends javax.swing.JFrame {
    
        private Font comboFont = UIManager.getFont("ComboBox.font");
        private Font[] fonts;
        private final String[] families;
        private static final Font DEFAULT_FONT = new Font(Font.DIALOG, Font.PLAIN, 12);
        private FontModel fontModel = new FontModel(DEFAULT_FONT);
        private TextAttributeComboBox textAttributeComboBox1;
    
        /**
         * Creates new form OptionsFrame
         */
        public OptionsFrame() {
    
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            families = ge.getAvailableFontFamilyNames();
            fonts = new Font[families.length];
            int comboFontSize = comboFont.getSize();
            for (int i = 0; i < fonts.length; i++) {
              fonts[i] = new Font(families[i], Font.PLAIN, comboFontSize);
            }
    
            textAttributeComboBox1 = new de.bibleget.TextAttributeComboBox(fonts);
            textAttributeComboBox1.setToolTipText("Font family");
            String family = fontModel.getFamily();
            for (int i = 0; i < fonts.length; i++) {
              if (fonts[i].getName().equals(family)) {
                textAttributeComboBox1.setSelectedIndex(i);
                break;
              }
            }
    
            textAttributeComboBox1.setRenderer(new FontListCellRenderer());
            textAttributeComboBox1.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    textAttributeComboBox1ActionPerformed(evt);
                }
            });
            
        }
    
        private void textAttributeComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {                                                       
            // TODO add your handling code here:
            Font font = (Font) textAttributeComboBox1.getSelectedItem();
            textAttributeComboBox1.setFont(font.canDisplayUpTo(font.getName()) == -1 ? font : comboFont);
            fontModel.setFamily(families[textAttributeComboBox1.getSelectedIndex()]);
    
        }                                                      
    
    }
    Within the code the TextAttributeComboBox is being added to a panel in my JFrame (for simplicity's sake I haven't included all of that code).
    I have extracted a couple of the private classes in the VirtualFontDesigner and made them separate public classes (i.e. FontListCellRenderer, FontModel, TextAttributeConstants, and TextAttributeComboBox).

    The fonts listed in the combobox are rendered in their own fonts, it's just still slow opening the first time round.

  5. #5
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    12,059
    Rep Power
    25

    Default Re: Pre-render a JComboBox list

    My implementation doesn't suffer from any noticeable lag. Are you still constructing a new Font(...) in the getListCellRendererComponent(...) method of your renderer?

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  6. #6
    johnrdorazio is offline Member
    Join Date
    Sep 2014
    Posts
    4
    Rep Power
    0

    Default Re: Pre-render a JComboBox list

    No I'm not, as I said I'm using their implementation where the fonts are being constructed outside of the renderer (see my code above).

    The renderer just uses the already created fonts that are being passed into it:

    Java Code:
      /**
       * A ListCellRenderer that displays font names in their own font if possible.  The list's
       * model must contain objects of type Font, or a ClassCastException will be thrown.
       * <P>
       * A font that lacks the glyphs to display its own name is rendered with the default font,
       * in red or a specified color.
       */
      public class FontListCellRenderer extends DefaultListCellRenderer {
    
        private final Font defaultFont = super.getFont();
        private final Color symbolColor;
    
        /**
         * Constructs a <CODE>FontListCellRenderer</CODE>.  Any font that lacks the glyphs to display
         * its own name is rendered in red with the default Font of a {@link DefaultListCellRenderer}.
         */
        public FontListCellRenderer() {
          this(Color.RED);
        }
    
        /**
         * Constructs a <CODE>FontListCellRenderer</CODE> with a custom color for symbolic fonts.
         * Any font that lacks the glyphs to display its own name is rendered in the passed in color
         * with the default Font of a {@link DefaultListCellRenderer}.
         *
         * @param symbolColor the color is which to render a font which is unable to display its name
         */
        public FontListCellRenderer(Color symbolColor) {
          if (symbolColor == null) {
            this.symbolColor = Color.RED;
          } else {
            this.symbolColor = symbolColor;
          }
        }
    
        /**
         * Return a component that has been configured to display a font name.  Any font that
         * lacks the glyphs to display its own name is rendered with the default Font of a
         * DefaultListCellRenderer in red or a custom color passed to the constructor.
         *
         * @param list the JList to which to render
         * @param value the value returned by list.getModel().getElementAt(index)
         * @param index the cell's index
         * @param isSelected true if the specified cell was selected
         * @param cellHasFocus true if the specified cell has the focus.
         *
         * @return a component whose paint() method will render the specified value.
         *
         * @see ListCellRenderer#getListCellRendererComponent(javax.swing.JList,
         * java.lang.Object, int, boolean, boolean)
         */
        @Override
        public Component getListCellRendererComponent(JList list,
                Object value, int index,
                boolean isSelected, boolean cellHasFocus) {
          Font font = (Font) value;
          setText(font.getName());
          if (isSelected) {
            setForeground(list.getSelectionForeground());
            setBackground(list.getSelectionBackground());
          } else {
            setForeground(list.getForeground());
            setBackground(list.getBackground());
          }
          if (font.canDisplayUpTo(font.getName()) == -1) {
            setFont(font);
          } else {
            setForeground(symbolColor);
            setFont(defaultFont);
          }
          return this;
        }
      }

  7. #7
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    12,059
    Rep Power
    25

    Default Re: Pre-render a JComboBox list

    Quote Originally Posted by johnrdorazio View Post
    No I'm not, as I said I'm using their implementation
    :ahem:

    If you use the classes exactly as posted on the page I linked earlier, do you still get the same sluggishness?

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

Similar Threads

  1. Jcombobox filter list
    By the reporter in forum AWT / Swing
    Replies: 3
    Last Post: 07-28-2010, 11:45 AM
  2. JComboBox search for match list
    By mine0926 in forum New To Java
    Replies: 3
    Last Post: 07-08-2010, 08:48 AM
  3. Replies: 2
    Last Post: 12-10-2009, 01:58 PM
  4. How at save list in Jcombobox...
    By pra.deep in forum AWT / Swing
    Replies: 1
    Last Post: 10-29-2009, 05:57 AM
  5. JComboBox and drop-down list.....HELP!!!!!
    By Anna in forum AWT / Swing
    Replies: 1
    Last Post: 06-18-2008, 05:16 AM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •