1

I'm not sure how I would fix the errors in my program and how I would highlight the option the user is hovering on. I want it to highlight the code for each position, i.e position 1 would be highlighted(as a different color) to start game,etc. and up/down would change position and I would change the position with up ,down, left, right. This is what I have so far. At the moment its bugged and when compiled with my window it comes out as:

enter image description here

Which works for the main game and altered for this titleboard, what am I doing wrong and how do I fix it?

TitleBoard class

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;

//sound + file opening
import java.io.*;
import javax.sound.sampled.*;
public class TitleBoard extends JPanel implements ActionListener{

    private ArrayList<String> OptionList;
    private Image background;
    private ImageIcon bgImageIcon;
    private String cheatString;
    private int position;
    private Timer timer;

    public TitleBoard(){

    setFocusable(true);
    addKeyListener(new TAdapter());
    bgImageIcon = new ImageIcon("");
    background = bgImageIcon.getImage();
    String[] options = {"Start Game","Options","Quit"};
    OptionList = new ArrayList<String>();
    optionSetup(options);
    position = 1;
    timer = new Timer(8, this);
    timer.start();
    /*
      1 mod 3 =>1 highlight on start
      2 mod 3 =>2 highlight on options
      3 mod 3 =>0 highlight on quit
    */

    try{
        Font numFont = Font.createFont(Font.TRUETYPE_FONT,new File("TwistedStallions.ttf"));
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        ge.registerFont(numFont);
        setFont(numFont.deriveFont(24f)); //adjusthislater
    }catch(IOException|FontFormatException e){
        e.printStackTrace();
    }

    }
    private void optionSetup(String[] s){
    for(int i=0; i<s.length;i++) {
        OptionList.add(s[i]);
    }
    }



    public void paint(Graphics g){
    super.paint(g);
    Graphics g2d = (Graphics2D)g;

    g2d.drawImage(background,0,0,this);
    for (int i=0;i<OptionList.size();i++){
        g2d.drawString(OptionList.get(i),200,120+120*i);
    }/*
    g2d.drawString(OptionList.get(1),400,240);
    g2d.drawString(OptionList.get(2),400,360);
    //instructions on start screen maybe??
    //800x500
    //highlighting*/
    Toolkit.getDefaultToolkit().sync();
    g.dispose();
    }

    public void actionPerformed(ActionEvent e){
    repaint();
    }



    public class TAdapter extends KeyAdapter {
    public void keyPressed(KeyEvent e){
        if(e.getKeyCode() == KeyEvent.VK_UP||
           e.getKeyCode() == KeyEvent.VK_RIGHT){
        position++;
        }
        if(e.getKeyCode() == KeyEvent.VK_DOWN||
           e.getKeyCode() == KeyEvent.VK_LEFT){
        position--;
        }
    }
    }

}

Window Class

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

public class Window extends JFrame{
    public Window(){
    int width = 800, height = 600;
    //TO DO: make a panel in TITLE MODE
    ///////////////////////////////////
    //panel in GAME MODE.
    add(new TitleBoard());
    //set default close
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(width,height);
    //centers window
    setLocationRelativeTo(null);
    setTitle("Title");
    setResizable(false);
    setVisible(true);   
    }
    public static void main(String[] args){
    new Window();
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
user3213648
  • 11
  • 1
  • 3
  • 1) Always copy/paste error & exception output. 2) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve). – Andrew Thompson Jan 20 '14 at 03:29
  • Sorry I just updated the puush for it :S – user3213648 Jan 20 '14 at 03:30
  • An MCVE should have just one source file where possible (but it can contain multiple classes, only 1 **`public`** class). Further, an MCVE should not require anything that will not be available for others. Do you really think I have a `TwistedStallions.ttf` font here? Try testing the code you think is an MCVE on another computer before posting it. – Andrew Thompson Jan 20 '14 at 05:09

2 Answers2

9

There are any number of ways you might achieve this, for example, you could use some kind of delegation model.

That is, rather then trying to mange each element in a single method (or methods), you could devise a delegate which provide a simple interface method that the paint method would call and it would know how to do the rest.

For example, Swing uses this type of concept with it's cell renderers for JList, JTable and JTree.

For example...

Menu

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MyAwesomeMenu {

    public static void main(String[] args) {
        new MyAwesomeMenu();
    }

    public MyAwesomeMenu() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private List<String> menuItems;
        private String selectMenuItem;
        private String focusedItem;

        private MenuItemPainter painter;
        private Map<String, Rectangle> menuBounds;

        public TestPane() {
            setBackground(Color.BLACK);
            painter = new SimpleMenuItemPainter();
            menuItems = new ArrayList<>(25);
            menuItems.add("Start Game");
            menuItems.add("Options");
            menuItems.add("Exit");
            selectMenuItem = menuItems.get(0);

            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    String newItem = null;
                    for (String text : menuItems) {
                        Rectangle bounds = menuBounds.get(text);
                        if (bounds.contains(e.getPoint())) {
                            newItem = text;
                            break;
                        }
                    }
                    if (newItem != null && !newItem.equals(selectMenuItem)) {
                        selectMenuItem = newItem;
                        repaint();
                    }
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                    focusedItem = null;
                    for (String text : menuItems) {
                        Rectangle bounds = menuBounds.get(text);
                        if (bounds.contains(e.getPoint())) {
                            focusedItem = text;
                            repaint();
                            break;
                        }
                    }
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();
        
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "arrowDown");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "arrowUp");
        
            am.put("arrowDown", new MenuAction(1));
            am.put("arrowUp", new MenuAction(-1));

        }

        @Override
        public void invalidate() {
            menuBounds = null;
            super.invalidate();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (menuBounds == null) {
                menuBounds = new HashMap<>(menuItems.size());
                int width = 0;
                int height = 0;
                for (String text : menuItems) {
                    Dimension dim = painter.getPreferredSize(g2d, text);
                    width = Math.max(width, dim.width);
                    height = Math.max(height, dim.height);
                }

                int x = (getWidth() - (width + 10)) / 2;

                int totalHeight = (height + 10) * menuItems.size();
                totalHeight += 5 * (menuItems.size() - 1);

                int y = (getHeight() - totalHeight) / 2;

                for (String text : menuItems) {
                    menuBounds.put(text, new Rectangle(x, y, width + 10, height + 10));
                    y += height + 10 + 5;
                }

            }
            for (String text : menuItems) {
                Rectangle bounds = menuBounds.get(text);
                boolean isSelected = text.equals(selectMenuItem);
                boolean isFocused = text.equals(focusedItem);
                painter.paint(g2d, text, bounds, isSelected, isFocused);
            }
            g2d.dispose();
        }
    
        public class MenuAction extends AbstractAction {

            private final int delta;
        
            public MenuAction(int delta) {
                this.delta = delta;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                int index = menuItems.indexOf(selectMenuItem);
                if (index < 0) {
                    selectMenuItem = menuItems.get(0);
                }
                index += delta;
                if (index < 0) {
                    selectMenuItem = menuItems.get(menuItems.size() - 1);
                } else if (index >= menuItems.size()) {
                    selectMenuItem = menuItems.get(0);
                } else {
                    selectMenuItem = menuItems.get(index);
                }
                repaint();
            }
        
        }

    }

    public interface MenuItemPainter {

        public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused);

        public Dimension getPreferredSize(Graphics2D g2d, String text);

    }

    public class SimpleMenuItemPainter implements MenuItemPainter {

        public Dimension getPreferredSize(Graphics2D g2d, String text) {
            return g2d.getFontMetrics().getStringBounds(text, g2d).getBounds().getSize();
        }

        @Override
        public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused) {
            FontMetrics fm = g2d.getFontMetrics();
            if (isSelected) {
                paintBackground(g2d, bounds, Color.BLUE, Color.WHITE);
            } else if (isFocused) {
                paintBackground(g2d, bounds, Color.MAGENTA, Color.BLACK);
            } else {
                paintBackground(g2d, bounds, Color.DARK_GRAY, Color.LIGHT_GRAY);
            }
            int x = bounds.x + ((bounds.width - fm.stringWidth(text)) / 2);
            int y = bounds.y + ((bounds.height - fm.getHeight()) / 2) + fm.getAscent();
            g2d.setColor(isSelected ? Color.WHITE : Color.LIGHT_GRAY);
            g2d.drawString(text, x, y);
        }

        protected void paintBackground(Graphics2D g2d, Rectangle bounds, Color background, Color foreground) {
            g2d.setColor(background);
            g2d.fill(bounds);
            g2d.setColor(foreground);
            g2d.draw(bounds);
        }

    }

}

From here, you could add ActionListener

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
3

When a GUI needs a button, use a JButton! The JButton API allows the possibility to add icons for many different circumstances. This example shows different icons for the standard icon, the hover icon, and the pressed icon. Your GUI would obviously use icons with text on them for the required effect.

The icons are pulled directly (hot-linked) from Example images for code and mark-up Q&As.

Standard

enter image description here

Hover over triangle

enter image description here

Press triangle

enter image description here

Code

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;

public class IconHoverFocusIndication {

    // the GUI as seen by the user (without frame)
    // swap the 1 and 0 for single column
    JPanel gui = new JPanel(new GridLayout(1,0,50,50));
    public static final int GREEN = 0, YELLOW = 1, RED = 2;
    String[][] urls = {
        {
            "https://i.stack.imgur.com/T5uTa.png",
            "https://i.stack.imgur.com/IHARa.png",
            "https://i.stack.imgur.com/wCF8S.png"
        },
        {
            "https://i.stack.imgur.com/gYxHm.png",
            "https://i.stack.imgur.com/8BGfi.png",
            "https://i.stack.imgur.com/5v2TX.png"
        },
        {
            "https://i.stack.imgur.com/1lgtq.png",
            "https://i.stack.imgur.com/6ZXhi.png",
            "https://i.stack.imgur.com/F0JHK.png"
        }
    };

    IconHoverFocusIndication() throws Exception {
        // adjust to requirement..
        gui.setBorder(new EmptyBorder(15, 30, 15, 30));
        gui.setBackground(Color.BLACK);
        Insets zeroMargin = new Insets(0,0,0,0);
        for (int ii = 0; ii < 3; ii++) {
            JButton b = new JButton();
            b.setBorderPainted(false);
            b.setMargin(zeroMargin);
            b.setContentAreaFilled(false);
            gui.add(b);

            URL url1 = new URL(urls[ii][GREEN]);
            BufferedImage bi1 = ImageIO.read(url1);
            b.setIcon(new ImageIcon(bi1));

            URL url2 = new URL(urls[ii][YELLOW]);
            BufferedImage bi2 = ImageIO.read(url2);
            b.setRolloverIcon(new ImageIcon(bi2));

            URL url3 = new URL(urls[ii][RED]);
            BufferedImage bi3 = ImageIO.read(url3);
            b.setPressedIcon(new ImageIcon(bi3));
        }
    }

    public JComponent getGUI() {
        return gui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                try {
                    IconHoverFocusIndication ihfi =
                            new IconHoverFocusIndication();
                    JFrame f = new JFrame("Button Icons");
                    f.add(ihfi.getGUI());
                    // Ensures JVM closes after frame(s) closed and
                    // all non-daemon threads are finished
                    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    // See https://stackoverflow.com/a/7143398/418556 for demo.
                    f.setLocationByPlatform(true);

                    // ensures the frame is the minimum size it needs to be
                    // in order display the components within it
                    f.pack();
                    // should be done last, to avoid flickering, moving,
                    // resizing artifacts.
                    f.setVisible(true);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}
Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433