How to use scroll keys, such as up, down, on the keyboard to navigate a list of buttons?

1

I have these buttons implemented with a click of the mouse, but I wanted the following: I could navigate through the direction keys up and down and enter through enter . Does anyone know how to implement it? They are the buttons: btStart, btAbout and btSair .

I know the right thing is for me to have something made for you to help, but I've only done ActionListener of the buttons. The keyboard actions I really do not know how to use.

Here is the code I have:

package ju;

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Botoes extends JFrame {

private JPanel contentPane;
private JButton btIniciar;
private JButton btSobre;
private JButton btSair;

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Botoes frame = new Botoes();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public Botoes() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    btIniciar = new JButton("Iniciar");
    btIniciar.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            System.out.println("foi clicado");
        }
    });
    btIniciar.setBounds(146, 101, 125, 37);
    contentPane.add(btIniciar);

    btSobre = new JButton("Sobre");
    btSobre.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("foi clicado");
        }
    });
    btSobre.setBounds(146, 156, 125, 37);
    contentPane.add(btSobre);

    btSair = new JButton("Sair");
    btSair.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    });
    btSair.setBounds(145, 213, 126, 37);
    contentPane.add(btSair);
}
}

I put it in my code, but it did not work (I circled the one you sent and it worked, but I only sent one sketch). Is it because of the way my buttons are? take a look at what my code really is.

package visao;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import controle.Constantes;


public class TelaInicial extends JFrame {

    private JPanel painelTI;
    private boolean seJogando;
    private JButton btIniciarTI;
    private JButton btSobreTI;
    private JButton btSairTI;

    private JLabel lblImgTelaInicialTI;
    private JLabel lblTextNomeDoJogo;
    public static int coluna=0;
    JPanel p1;

    public TelaInicial() {

        setFocusable(true);
        setUndecorated(true);   
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize( Constantes.ALTURA, Constantes.LARGURA);
        setLocationRelativeTo(null);
        painelTI = new JPanel();
        painelTI.setLayout(null);
        setContentPane(painelTI);

        lblTextNomeDoJogo = new JLabel("");
        lblTextNomeDoJogo.setForeground(Color.WHITE);
        lblTextNomeDoJogo.setFont(GerenciarFonte.FontePlain(47));
        lblTextNomeDoJogo.setBounds(242, 250, 633, 46);
        painelTI.add(lblTextNomeDoJogo);

        btIniciarTI = new JButton("Iniciar");
        btIniciarTI.setFont(GerenciarFonte.FontePlain(44));
        btIniciarTI.setForeground(Color.WHITE);
        btIniciarTI.setFocusable(false);
        btIniciarTI.setContentAreaFilled(false);
        btIniciarTI.setFocusPainted(true);
        btIniciarTI.setBounds(445, 350, 185, 47);
        painelTI.add(btIniciarTI);


        btSobreTI = new JButton("Sobre");
        btSobreTI.setFont(GerenciarFonte.FontePlain(42));
        btSobreTI.setForeground(Color.WHITE);//laranja 255 69 0
        btSobreTI.setFocusable(false);
        btSobreTI.setBorderPainted(true);
        btSobreTI.setContentAreaFilled(false);
        btSobreTI.setFocusPainted(true);
        btSobreTI.setBounds(461, 414, 156, 41);
        painelTI.add(btSobreTI);

        btSairTI = new JButton("Sair");
        btSairTI.setFont(GerenciarFonte.FontePlain(42));//RockoUltraFLF
        btSairTI.setForeground(Color.WHITE);
        btSairTI.setFocusable(false);
        btSairTI.setBorderPainted(true);
        btSairTI.setContentAreaFilled(false);
        btSairTI.setFocusPainted(true);
        btSairTI.setBounds(471, 472, 131, 37);
        painelTI.add(btSairTI);

        OrdenadorDeFoco of = new OrdenadorDeFoco(this);
        of.configurarOrdem(btIniciarTI, btSobreTI, btSairTI);

        lblImgTelaInicialTI = new JLabel();
        lblImgTelaInicialTI.setIcon(new ImageIcon(getClass().getResource("/imagem/11.jpg")));
        lblImgTelaInicialTI.setBounds(0, 0,Constantes.ALTURA, Constantes.LARGURA);
        painelTI.add(lblImgTelaInicialTI);
        setResizable(false);
        setVisible(true);

    }

    public void paint(Graphics g){
        super.paint(g);
        g.setColor(Color.WHITE);
        g.drawRect(436, 341, 201, 58);
        g.drawRect(436, 408, 201, 47);
        g.drawRect(436, 463, 201, 47);
    }


    public class Panel extends JGradientPanel {

        private static final long serialVersionUID = 1L;

        public void paintComponent(Graphics g) {
            super.paintComponent(g);


            g.setColor(new Color(255,69,0));
            g.draw3DRect( 414, 273, 180, 37, true );

            g.draw3DRect( 414, 363, 180, 37, true );

            g.draw3DRect( 414, 453, 180, 37, true ); 
        }


        public Panel(Color initialColor, Color finalColor) {
            super(initialColor, finalColor);
        }
    }

    public JButton getBtIniciarTI() {
        return btIniciarTI;
    }

    public JButton getBtSairTI() {
        return btSairTI;
    }

    public JButton getBtSobreTI() {
        return btSobreTI;
    }

    public boolean isSeJogando() {
        return seJogando;
    }

    public void setSeJogando(boolean seJogando) {
        this.seJogando = seJogando;
    }

}
package visao;

import java.awt.Font;
import java.awt.FontFormatException;
import java.io.IOException;

public class GerenciarFonte {

public Font carregarFonte(String caminho, int tipo, int tamanho) {
    Font minhaFonte = null;

    try {

        minhaFonte = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream(caminho)).deriveFont(tipo,
                tamanho);

    } catch (IOException e) {
        // TODO: handle exception
    } catch (FontFormatException e) {
        // TODO: handle exception
    }

    return minhaFonte;
}

public static Font FontePlain(int tamanho){
    GerenciarFonte f = new GerenciarFonte();
    Font cooper = f.carregarFonte("/fonte/cooper-black.ttf", Font.PLAIN, tamanho);
    return cooper;
}

public static Font FonteBold(int tamanho){
    GerenciarFonte f = new GerenciarFonte();
    Font cooper = f.carregarFonte("/fonte/cooper-black.ttf", Font.BOLD, tamanho);
    return cooper;
}

public static Font FontePlainListen(int tamanho){
    GerenciarFonte f = new GerenciarFonte();
    Font cooper = f.carregarFonte("/fonte/TypoSlabserif-Light.ttf", Font.BOLD, tamanho);
    return cooper;
}

}
package visao;

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import javax.swing.JPanel;

public class JGradientPanel extends JPanel {
    private Color finalColor;
    private Color initialColor;

public JGradientPanel(Color initialColor, Color finalColor) {
    if (initialColor == null)
        throw new IllegalArgumentException("Invalid initial color!");
    if (finalColor == null)
        throw new IllegalArgumentException("Invalid final color!");
    this.initialColor = initialColor;
    this.finalColor = finalColor;
}

public void setInitialColor(Color color) {
    this.initialColor = color;
    invalidate();
}

public void setFinalColor(Color color) {
    this.finalColor = color;
    invalidate();
}

public Color getInitialColor() {
    return initialColor;
}

public Color getFinalColor() {
    return finalColor;
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    if (!isOpaque()) {
        return;
    }
    GradientPaint paint = new GradientPaint(new Point2D.Float(getWidth() / 2, 0), initialColor,
            new Point2D.Float(getWidth() / 2, getHeight()), finalColor);
    g2d.setPaint(paint);
    g2d.fillRect(0, 0, getWidth(), getHeight());
    g2d.dispose();
}
}
public abstract class Constantes {

public static final int ALTURA = 1000;
public static final int LARGURA = 700;


}

This class focus computer , using MVC, should it stay on which layer?

    
asked by anonymous 11.01.2018 / 04:23

1 answer

3

I think it would be something like this (version 2.0):

import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Map;
import java.util.WeakHashMap;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JWindow;
import javax.swing.KeyStroke;

public class OrdenadorDeFoco {

    private static final String UP = "up";
    private static final String DOWN = "down";
    private static final String ENTER = "enter";

    private final Map<Component, Component> upMap = new WeakHashMap<>(20);
    private final Map<Component, Component> downMap = new WeakHashMap<>(20);

    private Component primeiro;

    public OrdenadorDeFoco(JFrame window) {
        this(window, (JComponent) window.getContentPane());
    }

    public OrdenadorDeFoco(JDialog window) {
        this(window, (JComponent) window.getContentPane());
    }

    public OrdenadorDeFoco(JWindow window) {
        this(window, (JComponent) window.getContentPane());
    }

    private OrdenadorDeFoco(Window window, JComponent contentPane) {
        InputMap im = contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, 0), UP);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, 0), DOWN);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ENTER);

        contentPane.getActionMap().put(UP, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Component este = window.getFocusOwner();
                Component depois = este == null ? null : upMap.get(este);
                if (depois == null) depois = primeiro;
                depois.requestFocusInWindow();
            }
        });

        contentPane.getActionMap().put(DOWN, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Component este = window.getFocusOwner();
                Component depois = este == null ? null : downMap.get(este);
                if (depois == null) depois = primeiro;
                depois.requestFocusInWindow();
            }
        });

        contentPane.getActionMap().put(ENTER, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Component este = window.getFocusOwner();
                if (!(este instanceof AbstractButton)) return;
                ((AbstractButton) este).doClick();
            }
        });

        window.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                int k = e.getKeyCode();
                if (k == KeyEvent.VK_UP || k == KeyEvent.VK_KP_UP || k == KeyEvent.VK_DOWN || k == KeyEvent.VK_KP_DOWN) {
                    Component agora = window.getFocusOwner();
                    if (agora == null) primeiro.requestFocusInWindow();
                }
            }
        });
    }

    public void configurarOrdem(Component... elementos) {
        int n = elementos.length;
        if (primeiro == null && n > 0) primeiro = elementos[0];

        for (int i = 0; i < n; i++) {
            Component antes = elementos[(i + n - 1) % n]; 
            Component este = elementos[i];
            Component depois = elementos[(i + n + 1) % n];
            upMap.put(este, antes);
            downMap.put(este, depois);
        }
    }
}

This OrdenadorDeFoco class is responsible for doing the magic. In the constructor, it gets the JFrame , JDialog or JWindow with which it will work. The trick is the two Map s mapping which button is above and which button is below each other button (actually, not necessarily button, it can be any component).

The InputMap and contentPane.getActionMap() are used to hijack the default behavior of the up and down arrow keys (including the numeric keypad) and the two enter keys to take custom actions with it .

After constructing an instance of OrdenadorDeFoco , the configurarOrdem method is used to sort the buttons. You can call it multiple times with the same instance of a mapper to apply the sequence to various groups of buttons.

The KeyAdapter is used in case the focus is with the screen without being any of its components, in which case the first element added with configurarOrdem will receive the focus.

WeakHashMap is used for which components to be Map can be collected as junk even if they are in Map . This is to avoid the bug that would occur from OrdenadorDeFoco to prevent garbage collection from components that are no longer anywhere.

OrdenadorDeFoco is a component in the MVC view layer. The reason for this is that it deals directly with the components of the GUI, but it does not worry at all about what happens when you click on one of them.

Here's a way to use this (version 2.0 also):

import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class TesteBotoes {

    private static final Color VERDE_FOLHA = new Color(47, 126, 95);

    public static void main(String[] args) {
        EventQueue.invokeLater(TesteBotoes::criarTela);
    }

    private static void criarTela() {
        JFrame jf = new JFrame("Teste");
        jf.setFocusable(true);
        jf.setUndecorated(true);
        jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        JPanel jp = new JPanel();
        jp.setBorder(new EmptyBorder(5, 5, 5, 5));
        jp.setBackground(VERDE_FOLHA);
        GridLayout g = new GridLayout(3, 1);
        g.setVgap(10);
        jp.setLayout(g);
        JButton btIniciar = criarBotao(jp, "Iniciar", e -> System.out.println("Iniciar"));
        JButton btSobre = criarBotao(jp, "Sobre", e -> System.out.println("Sobre"));
        JButton btSair = criarBotao(jp, "Sair", e -> jf.dispose());
        jf.setContentPane(jp);

        OrdenadorDeFoco of = new OrdenadorDeFoco(jf);
        of.configurarOrdem(btIniciar, btSobre, btSair);

        jf.setLocationRelativeTo(null);
        jf.setSize(145, 151);
        jf.setVisible(true);
    }

    private static JButton criarBotao(Container pai, String titulo, ActionListener acao) {
        JButton botao = new JButton(titulo);
        botao.setBackground(VERDE_FOLHA);
        botao.setForeground(Color.WHITE);
        botao.setBorder(new LineBorder(Color.WHITE));
        botao.addActionListener(acao);
        pai.add(botao);
        return botao;
    }
}

You can use the criarBotao method to configure the buttons, including changing the font, color, etc. I decided to use GridLayout instead of null layout.

If you use algumBotao.setFocusable(false); , probably bad or strange things will happen.

This OrdenadorDeFoco code should solve your problem for now, although I personally did not like it very much and I think it can create other problems later.

    
11.01.2018 / 17:21