Menu Scrolling with JScrollPane and the Keyboard

Hello,

I am a computer science student, and I'm currently writing a DDR(Dance Dance Revolution) clone, and I can't figure out how to make my menus scroll with the keyboard.

The menu is composed of JLabels placed on a JPanel, which is set as the content pane when it is needed to be displayed. For this menu I created a JScrollPane with the JPanel in the viewport. The menu scrolls fine with the knob, but not with the keyboard. From what I understand the scroll pane has its own listeners which I need to replace with my own and then scroll the panel, but I haven't been able to figure out how to do it.

I did find the exapmle code snippet given in the javadocs to implement panel scrolling withmouseDragged events and using thescrollRectToVisible method, but I have not had any success with scrolling my menu with the keyboard.

I have tried searching for answers, but both me and my teacher are unexperienced in making GUIs and have been unable to figure out how to accomplish this. Any suggestions or direction would be greatly appreciated.

Thanks.

[1108 byte] By [jamlub1a] at [2007-11-26 16:22:22]
# 1

> I did find the exapmle code snippet given in the

> javadocs to implement panel scrolling with

> mouseDragged events and using the

> scrollRectToVisible method, but I have not had

> any success with scrolling my menu with the

> keyboard.

So do the exact same thing, except with keyPressed events instead of mouseDragged.

CaptainMorgan08a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 2

I did that, but the scrolling didn't work. The code in the doc is:

MouseMotionListener doScrollRectToVisible = new MouseMotionAdapter() {

public void mouseDragged(MouseEvent e) {

Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);

((JPanel)e.getSource()).scrollRectToVisible(r);

}

};

songPane.addMouseMotionListener(doScrollRectToVisible);

I think that I know what to look into now. scrollRectToVisible is a method of JComponent, but it is overridden in JViewport. I think that I can access the JViewport in JScrollPanel and then scroll it with the key events. Thanks CaptainMorgain! =D

jamlub1a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 3

Look at the code you made. It's basically showing a certain area of the JPanel (depicted by the Rectangle r), which follows the location of the mouse. Instead of using e.getX() and e.getY() as the coordinates of the Rectangle, use your own variables and adjust them based on what button on the KeyBoard was pressed. Does that make sense?

CaptainMorgan08a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 4

Yes, I do understand, and it does make sense. I tried using my own coordinates, but the panel didn't scroll. Is there anything wrong with replacing the content pane with my current menu's JPanel when I want it to be displayed? I think that there might be a conflict with the size of the JPanel that shrinks it and causes it not to scroll, but I don't know. I'm also not sure if my method of creating navigable menus by making a JPanel, laying everything out, and then pasting the correct panel on the applet is the best method. Is there a better way to create menus?

Thanks again CaptainMorgan.

jamlub1a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 5
Try posting some of your code. You need to make sure the JPanel has focus, or it won't work. Try placing some System.out.println()'s in your keyPressed() method to see if it is even being reached.
CaptainMorgan08a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 6

> Try placing some System.out.println()'s in your keyPressed()

> method to see if it is even being reached.

My keyPressed events work fine - the game already works.

> You need to make sure

> the JPanel has focus, or it won't work.

How do I do that?

Also, I played around with the setAlignmentX method to line components up on the panel, but I couldn't get them to line up correctly. What components should I be aligning? The panel? The labels? Currently if there is a menu option that is too long, that menu will be aligned wrong. How can I align the labels so that all my menus look the same? Should I create a separate class to handle the menus?

> Try posting some of your code.

/*

Menu Initialization

*/

public void menuInit() {

isMainMenu = true;

isMenu = true;

options = new String[] {"Main Menu", "Start Game", "Instructions",

"Options","Quit"};

menuOption = 1;

numberOfOptions = 4;

mainMenuPane = new JPanel();

mainMenuPane = createMenu(mainMenuPane, options, SIZE30);

this.setContentPane(mainMenuPane);

repaint();

}

public void songSelectMenuInit() {

songTitles = new String[] {"Song Selection", "Down",

"Boulevard of Broken Dreams", "Stacy's Mom",

"Empty Level", "DURDRDR", "You're Beautiful", "Sexy Back",

"Temperature", "Everytime we touch", "Shoulder Lean",

"Me and my red corvette",

"System of a Down", "Hey Mama", "Polaroid", "Seven Years",

"Fantasy", "Wasn't me"};

//songtitles = danceLevel.getSongTitles();

if(!isSongSelectMenu){

isSongSelectMenu = true;

menuOption = 1;

numberOfOptions = songTitles.length - 1;

//songtitles.length -1

}

else{

String[] displayedTitles = new String[9];

displayedTitles[0] = "Song Selection";

int firstSongIndex = 0;

for (int i = 1; i < displayedTitles.length; i++){

if ((firstSongIndex = menuOption - 1) + i > numberOfOptions)

break;

displayedTitles[i] = songTitles[firstSongIndex + i];

}

songPane = new JPanel();

songPane = createMenu(songPane, displayedTitles, SIZE24);

this.setContentPane(songPane);

repaint();

return;

}

songPane = new JPanel();

songPane = createMenu(songPane, songTitles, SIZE24);

this.setContentPane(songPane);

repaint();

/*

songPanel = new JPanel();

songPanel = createMenu(songPane, songTitles, SIZE24);

songScroller = new JScrollPane(songPanel);

songScroller.setBackground(Color.black);

songScroller.setSize(GAMEWIDTH, GAMEHEIGHT);

//songScroller.setPreferredSize(new Dimension(GAMEWIDTH, GAMEHEIGHT));

songPane = new JPanel(null);

songPane.setSize(GAMEWIDTH,GAMEHEIGHT);

//songPane.add(songScroller);

songPane = songPanel;

//songScroller.getVerticalScrollBar().removeKeyListener();

//songScroller.getVerticalScrollBar().addKeyListener(new DanceGame_this_keyAdapter(this));

//this.addKeyListener(songScroller.getKeyListeners()[0]);

//this.addKeyListener((KeyListener)songScroller.set

MouseMotionListener doScrollRectToVisible = new MouseMotionAdapter() {

public void mouseDragged(MouseEvent e) {

Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);

System.out.println("x: " + e.getX());

System.out.println("y : " + e.getY());

((JPanel)e.getSource()).scrollRectToVisible(r);

System.out.println("drag");

}

};

songPane.addMouseMotionListener(doScrollRectToVisible);

//this.addMouseMotionListener(doScrollRectToVisible);

this.setContentPane(songPane);

repaint();

*/

}

/*

Menu Creation

*/

public JPanel createMenu(JPanel menuPanel, String[] menuOptions, Font font) {

//format panel

JPanel panel = menuPanel;

panel.setBackground(Color.black);

panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

panel.setPreferredSize(new Dimension(GAMEWIDTH,GAMEHEIGHT));

panel.setBorder(null);

//MENU TITLE

Box title = new Box(BoxLayout.X_AXIS);

title.setBounds(0, 0, GAMEWIDTH, 30);

title.setBorder(null);

//format title label

JLabel label = new JLabel();

label.setText(menuOptions[0]);

label.setForeground(Color.blue);

label.setFont(SIZE36);

//add title panel

title.add(label);

title.add(title.createHorizontalGlue());

panel.add(title);

//blank label

label = new JLabel();

label.setText(" ");

panel.add(label);

//MENU OPTIONS

Box options = new Box(BoxLayout.Y_AXIS);

for (int i = 1; i < menuOptions.length; i++) {

label = new JLabel();

label.setForeground(Color.blue);

label.setFont(font);

label.setText(menuOptions[i]);

if (isGameOver) {

switch (i) {

case 1:

label.setText(menuOptions[i] + "" + letterGrade);

break;

case 2:

label.setText(menuOptions[i] + "" + perfectCount);

break;

case 3:

label.setText(menuOptions[i] + "" + goodCount);

break;

case 4

label.setText(menuOptions[i] + "" + averageCount);

break;

case 5:

label.setText(menuOptions[i] + "" + maxCombo);

break;

case 6:

label.setText(menuOptions[i] + "" + score);

break;

}

Box option = new Box(BoxLayout.X_AXIS);

option.setAlignmentX(JComponent.LEFT_ALIGNMENT);

}

options.add(label);

}

options.setAlignmentX(JComponent.LEFT_ALIGNMENT);

panel.add(options);

return panel;

}

public void this_keyPressed(KeyEvent e) {

int key = e.getKeyCode();

if (displayKey)

System.out.println(key);

/*

Menu Navigation

*/

if (!isPlaying) {

switch (key) {

//K

case 75:

repaint();

break;

//C -> Create Steps

case 67:

if(isDifficultyMenu){

createSteps = !createSteps;

repaint();

}

break;

case 78:

noMusic = !noMusic;

repaint();

break;

//UP

case 38:

if (menuOption <= 1)

menuOption = numberOfOptions;

else

menuOption--;

if(isSongSelectMenu){

songSelectMenuInit();

//Rectangle r = new Rectangle(0,50 + 25,1,1);

//((JScrollPane)this.getContentPane().getComponent(0)).

//songScroller.scrollRectToVisible(r);

}

repaint();

break;

//DOWN

case 40:

if (menuOption >= numberOfOptions)

menuOption = 1;

else

menuOption++;

//if(isSongSelectMenu){

// songSelectMenuInit();

//}

repaint();

break;

//ESC

case 27:

if (isMainMenu)

System.exit(0);

else

//return to main menu

if (isInstructionMenu ||

isSongSelectMenu ||

isOptionMenu ){

isInstructionMenu = false;

isSongSelectMenu = false;

isOptionMenu = false;

isMainMenu = true;

menuInit();

}

else if(isDifficultyMenu){

isDifficultyMenu = false;

songSelectMenuInit();

}

else if(isBPMPane){

isBPMPane = false;

difficultyMenuInit();

}

break;

//ENTER

case 10:

if(isMenu){

//Main Menu

if (isMainMenu) {

isMainMenu = false;

switch (menuOption) {

//start

case 1:

songSelectMenuInit();

//JPanel contentPane = new JPanel();

//contentPane.add(songPane);

//contentPane.setPreferredSize(new Dimension(GAMEWIDTH,GAMEHEIGHT));

//this.setContentPane(contentPane);

//repaint();

break;

//instructions

case 2:

instructionMenuInit();

break;

//options

case 3:

optionMenuInit();

this.setContentPane(optionPane);

break;

//quit

case 4:

System.exit(0);

break;

}

}

else

//Song Select Menu

if (isSongSelectMenu) {

isSongSelectMenu = false;

switch (menuOption) {

//"Down" Rakim y ken

case 1:

level = 1;

break;

//"Boulevard of Broken Dreams"

case 2:

level = 2;

break;

//Stacy's Mom

case 3:

level = 3;

break;

//Empty Level

case 4:

level = 0;

BPMStr= new String[]{"BPM",JOptionPane.showInputDialog(this,"Enter BPM")};

//BPMPaneInit();

createSteps = true;

noMusic = true;

isBPMPane = false;

repaint();

break;

}

difficultyMenuInit();

}

else

if(isBPMPane){

isBPMPane = false;

System.out.println(((JTextField)BPMPane.getComponent(0)).getText());

}

else

//Difficulty Menu

if (isDifficultyMenu) {

isDifficultyMenu = false;

switch (menuOption) {

//beginner

case 1:

difficulty = 1;

break;

//light

case 2:

difficulty = 2;

break;

//standard

case 3:

difficulty = 3;

break;

//heavy

case 4:

difficulty = 4;

break;

}

isLoading = true;

t.start();

System.out.println("animation timer started");

gameInit();

gameStart();

}

}

//enter pressed & not a menu

else if(isGameOver){

isGameOver = false;

menuInit();

}

}

//...

}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Menu Navigation

*/

Thanks.

jamlub1a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 7

> > Try placing some System.out.println()'s in your

> keyPressed()

> > method to see if it is even being reached.

>

> My keyPressed events work fine - the game already

> works.

Are the menus scrolling by the KeyBoard? If not, then you can use these two methods to try and give the JPanel focus:

[url=http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Component.html#setFocusable(boolean)]JPanel.setFocusable(boolean)[/url]

[url=http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Component.html#requestFocusInWindow()]JPanel.requestFocusInWindow()[/url]

CaptainMorgan08a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 8
> Are the menus scrolling by the KeyBoard? Yes they are scrolling with the keyboard.
jamlub1a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 9
> Yes they are scrolling with the keyboard.Cool. Now to the other problem: what LayoutManager are you using? You can use the setPreferredSize() method (not sure if I spelled it right) to make the Component smaller so it is not out of line.
CaptainMorgan08a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 10

> Cool. Now to the other problem: what LayoutManager

> are you using?

BoxLayout. I wanted my menu options to be stacked vertically, and aligned horizontally.

> You can use the setPreferredSize()

> method (not sure if I spelled it right) to make the

> Component smaller so it is not out of line.

And that would prevent it from shifting everything?

Because this is what happens:

|Menu Title

|_option

|_2nd option

|Menu Title

|__option

|__option with long name

Oh, and how do you align them to exactly where you want left and right like above? Do I need to use glues and struts?

I tried calilng the setAlignmentX(JComponent_LEFT) method on the labels and align center on the jpanel, and lots of different combinations, but I just ended up settling with where it was.

jamlub1a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 11

Alright, just to clarify, what do you want it to look like?

Left Justified:

option1

option123

option12345

Or Center Justified:

option1

option123

option12345

If you are using JLabels, try using this constructor:

[url]http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JLabel.html#JLabel(java.lang.String,%20int)[/url]

For example:

JLabel label = new JLabel("Option1", SwingConstants.LEFT);

Hope that helps.

CaptainMorgan08a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...
# 12
> Alright, just to clarify, what do you want it to look> like?Left Justified, but in the center of the applet.> If you are using JLabels, try using this> constructor:> Hope that helps.It does, thanks.
jamlub1a at 2007-7-8 22:46:10 > top of Java-index,Other Topics,Java Game Development...