Results 1 to 6 of 6
  1. #1
    diggitydoggz is offline Member
    Join Date
    Dec 2008
    Posts
    55
    Rep Power
    0

    Default drawing char by char with Graphics

    Hey guys... I just started brainstorming for my hangman project today. The exercise which I'm basing the project on shows the game as a GUI with a big white area with the picture taking the top 2/3 and below it is the chosen word which gradually appears with each correctly guessed letter, and below that is the entire alphabet. Each guessed letter in the displayed alphabet turns grey upon being guessed.

    At first, I had thought of a way to do this - I wanted to use a JLabel to display the word and the alphabet. I planned to set the word's color to white, and change the font of each correctly guessed letter to black, thus slowly displaying them.

    I also was gonna do the same for the alphabet, changing each guessed letter to grey.

    However, I've been looking through all the API's and I don't see how I could change the font color in JLabel, let alone that of a single character in the label. The image on the exercise of the completed program shows the letter and alphabet in the same white square as the picture of the hangman, so I thought perhaps I'd draw the letters onto the image panel. But the only methods for drawing letters that I saw were the one that drew the character array and the one that drew a string. Using these methods, I could update an array of chars based on whether or not each char was chosen and go through this array and redraw and use an if statement for each value in the array to determine the color. But I've been reading about program efficiency and it seems a lot more efficient to simply develop a method to locate the single letter that was chosen and change that one's color, rather than redraw every single one after every guessed letter.

    So my two questions are as follows:

    1) Just for future reference - how can I change the font color for a JLabel? I looked through the API's for font AND JLabel and I couldn't find anything color-related.

    2) It looks like the drawChar method draws everything in a single go and doesn't allow you to change the color of individual chars, or the spacing between the letters. This is what it looks like from the API anyway. Is there anyway to use Graphics to draw text char by char? I can't seem to find it... If I can do this, I don't think I'd have much trouble finishing the rest of my program.

    Thanks

  2. #2
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    As you use Swing more, you'll get more and more familiar with its inheritance hierarchy. For instance you'll learn that most visible components inherit from JComponent. So knowing that JLabel is derived from JComponent, if when you search the API you don't find a way to set a property you're interested in setting, then your next step is to check the API for the ancestor -- the JComponent. If you do this, you'll find the method setForeground(Color fg) which will allow you to change the color of all the text on that JLabel. Now to change the individual text on a JLabel, I think that you may need to use HTML. Another way to solve this is to use an array of JLabel, each holding exactly one letter, and then changing the foreground on the individual label corresponding to your letter (a Map<String, JLabel> comes to mind here).

  3. #3
    diggitydoggz is offline Member
    Join Date
    Dec 2008
    Posts
    55
    Rep Power
    0

    Default

    Wow man that is a genius idea. I learned about maps/sets/linkedlists two chapters ago but I never would've remembered to use it for this problem. I'm definitely going to do that. Thanks. What's your background in programming? Seems like you know everything there is to know about java.

  4. #4
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    I'm a physician and a programming hobbiest who knows everything there is to know about introductory Java. ;)

  5. #5
    hardwired's Avatar
    hardwired is offline Senior Member
    Join Date
    Jul 2007
    Posts
    1,576
    Rep Power
    9

    Default

    Is there anyway to use Graphics to draw text char by char?
    Yes, probably a lot of ways. You can have a lot more control/subtlety with graphics but it means more work/details to look after. The main advantages are in layout/placement and behavior. There are a few tricks that can ease the way but these usually seem to come with experience or example. Such as the hit–testing for the letters in this:
    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.font.*;
    import java.awt.geom.Rectangle2D;
    import javax.swing.*;
    
    public class ColorDraw extends JPanel {
        String alpha = "abcdefghijkl";
        Rectangle2D.Float[] rects;
        boolean[] selected;
    
        public ColorDraw() {
            rects = new Rectangle2D.Float[alpha.length()];
            selected = new boolean[rects.length];
            for(int i = 0; i < rects.length; i++) {
                rects[i] = new Rectangle2D.Float();
                selected[i] = false;
            }
            addMouseListener(ml);
        }
    
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D)g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
            int w = getWidth();
            int h = getHeight();
            Font font = g2.getFont().deriveFont(36f);
            g2.setFont(font);
            FontRenderContext frc = g2.getFontRenderContext();
            float totalWidth = (float)font.getStringBounds(alpha, frc).getWidth();
            float x0 = (w - (totalWidth + 10*alpha.length()))/2f;
            LineMetrics lm = font.getLineMetrics("0", frc);
            float height = lm.getAscent() + lm.getDescent();
            String[] letters = alpha.split("(?<=[\\w])");
            float x = x0;
            for(int i = 0; i < letters.length; i++) {
                String s = letters[i];
                float width = (float)font.getStringBounds(s, frc).getWidth();
                float y = (h + height)/2f - lm.getDescent();
                rects[i].setRect(x, y-lm.getAscent(), width, height);
                Color color = selected[i] ? Color.gray : Color.blue;
                g2.setPaint(color);
                g2.drawString(s, x, y);
                x += width + 10f;
            }
            //g2.setPaint(Color.red);
            //for(int i = 0; i < rects.length; i++) {
            //    g2.draw(rects[i]);
            //}
        }
    
        public static void main(String[] args) {
            ColorDraw test = new ColorDraw();
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(test);
            f.setSize(500,200);
            f.setLocation(200,200);
            f.setVisible(true);
        }
    
        private MouseListener ml = new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                Point p = e.getPoint();
                for(int i = 0; i < rects.length; i++) {
                    if(rects[i].contains(p)) {
                        selected[i] = true;
                        repaint();
                        break;
                    }
                }
            }
        };
    }

  6. #6
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    HardWired code is pretty slick. And as he mentioned, there are many ways to solve this problem, but just for comparison, here's a way to do the same thing without using Graphics but instead using an array of JLabels, each holding a different letter and each accepting a mouse press.
    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class LetterLabelArray2
    {
      private static final String ALPHABET1 = "abcdefghijklmnopqrstuvwxyz";
      private static final Dimension LABEL_SIZE = new Dimension(40, 40);
      private static final Font LABEL_FONT = new Font(Font.DIALOG, Font.BOLD, 32);
      private static final Color ACTIVE_COLOR = Color.blue;
      protected static final Color INACTIVE_COLOR = Color.lightGray;
      private JPanel mainPanel = new JPanel();
      private JLabel[] letterLabels = new JLabel[ALPHABET1.length()];
    
      public LetterLabelArray2()
      {
        int ebGap = 35;
        mainPanel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
        mainPanel.setLayout(new GridLayout(2, 0));
        for (int i = 0; i < ALPHABET1.length(); i++)
        {
          char c = ALPHABET1.charAt(i);
          final JLabel label = new JLabel(String.valueOf(c));
          letterLabels[i] = label;
          label.setForeground(ACTIVE_COLOR);
          label.setPreferredSize(LABEL_SIZE);
          label.setFont(LABEL_FONT);
          label.setHorizontalAlignment(SwingConstants.CENTER);
          mainPanel.add(label);
          label.addMouseListener(new MouseAdapter()
          {
            public void mousePressed(MouseEvent e)
            {
              if (label.isEnabled())
              {
                System.out.println(label.getText());
                label.setForeground(INACTIVE_COLOR);
                label.setEnabled(false);
                if (areAllPressed())
                {
                  reset();
                }
              }
            }
          });
        }
      }
    
      public JComponent getComponent()
      {
        return mainPanel;
      }
      
      public void reset()
      {
        for (JLabel label : letterLabels)
        {
          label.setEnabled(true);
          label.setForeground(ACTIVE_COLOR);
        }
      }
      
      private boolean areAllPressed()
      {
        for (JLabel label : letterLabels)
        {
          if (label.isEnabled())
          {
            return false;
          }
        }
        return true;
      }
    
      private static void createAndShowUI()
      {
        JFrame frame = new JFrame("Letter Label Array");
        frame.getContentPane().add(new LetterLabelArray2().getComponent());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    
      public static void main(String[] args)
      {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
          public void run()
          {
            createAndShowUI();
          }
        });
      }
    }
    Last edited by Fubarable; 12-27-2008 at 04:10 PM.

Similar Threads

  1. How can i insert a char into a string
    By Jamie in forum New To Java
    Replies: 8
    Last Post: 02-17-2011, 08:59 PM
  2. pop from stack and store to char?
    By viligante8 in forum New To Java
    Replies: 13
    Last Post: 11-02-2008, 02:00 PM
  3. char to string
    By kian_hong2000 in forum New To Java
    Replies: 2
    Last Post: 08-25-2008, 01:51 PM
  4. Casting an int value into a char
    By kurtulas in forum New To Java
    Replies: 2
    Last Post: 02-16-2008, 08:03 PM
  5. Help with, String, Char
    By lenny in forum New To Java
    Replies: 1
    Last Post: 07-25-2007, 02:58 PM

Posting Permissions

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