Is there a way to prevent arrow keys from scrolling a ScrollPanel unnecessarily?

316 views
Skip to first unread message

tacitus

unread,
Feb 21, 2008, 2:22:54 PM2/21/08
to Google Web Toolkit
The basic problem is that if the keyboard focus is somewhere within a
ScrollPanel, when a user presses the UP, DOWN, PAGEUP, PAGEDOWN, etc,
arrow keys the ScrollPanel widget scrolls the panel whether you want
it to or not. I'm looking for a way to prevent the ScrollPanel from
doing this. I only want the panel to scroll when I decide it's really
necessary!

I have attached a working example of the problem. It is a simpler
version of the table widget I am playing with, where the keyboard can
be used to scroll through a long list of items.

The code inserts 100 HorizontalPanels into a VerticalPanel which has
been subclassed to add a KeyboadListener so that the user can scroll
through the items using the UP and DOWN arrow keys. The VerticalPanel
is placed inside a ScrollPanel, hence the scrollbar on the right of
the table.

If you run the example and click on the body of the panel to give it
the input focus, you can use the up and down arrow keys to change the
current selection (indicated by the "------>" text). First press the
up arrow a few times. You will see the selected item change as the
selection moves up towards the top of the panel. Nothing scrolls,
only the selection changes, which is as it should be.

Now press the down arrow key. The selection will change, moving down
the list, *but* the scrollbar will also move, scrolling the whole
window upwards. If the selected item is near the top of the window,
it will scroll off the top of the panel. Obviously the keystrokes are
being intercepted by the ScrollPanel and being used to scroll the
window. In this case, it is not necessary because I don't want the
window to scroll upwards until the currently selected item is right at
the bottom of the window. This is how MS Excel and countless other
applications scroll tables, and if you look at the Table examples in
the MyGWT widget, it can be done in GWT too, but I have no idea how.

What I want is for the ScrollPanel to ignore any keystrokes being sent
to the widgets contained within it, and then I can tell it to scroll
when I decide it is necessary. Does anyone know how to do this or
know how the MyGWT
does it? The answer seems to be buried deep in the GWT implementation
since I don't believe there is a simple subclass or override that can
do it, or am I missing a trick?

Thanks for any assistance or pointers!

Mike

--------------------------------------
Here's the code:

public void onModuleLoad() {
ScrollPanel scroll = new ScrollPanel();
scroll.setSize("80%", "30em");
VP panel = new VP();
panel.setWidth("95%");
for (int i = 0; i < 100; i++) {
addItem(panel, i);
}
scroll.add(panel);
RootPanel.get().add(scroll);
panel.selectItem(15);
}

private void addItem(VerticalPanel panel, int i) {
HorizontalPanel item = new HorizontalPanel();
item.add(new Label("Item number " + i));
panel.add(item);
}

private class VP extends VerticalPanel implements
SourcesKeyboardEvents {
KeyboardListenerCollection listeners = new
KeyboardListenerCollection();
int item = 0;

KeyboardListenerAdapter keyListener = new
KeyboardListenerAdapter() {
public void onKeyDown(Widget sender, char keyCode, int
modifiers) {
switch (keyCode) {
case KeyboardListener.KEY_DOWN:
if (item < VP.this.getWidgetCount() - 1) {
selectItem(item + 1);
}
break;
case KeyboardListener.KEY_UP:
if (item > 0) {
selectItem(item - 1);
}
break;
}
}
};

VP() {
sinkEvents(Event.KEYEVENTS);
addKeyboardListener(keyListener);
}

public void selectItem(int index) {
if (((HorizontalPanel)getWidget(item)).getWidgetCount() >
1) {
((HorizontalPanel)getWidget(item)).remove(0);
}
item = index;
((HorizontalPanel)getWidget(item)).insert(new Label("---
>"), 0);
}

public void addKeyboardListener(KeyboardListener listener) {
listeners.add(listener);
}

public void removeKeyboardListener(KeyboardListener listener)
{
listeners.remove(listener);
}

public void onBrowserEvent(Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONKEYDOWN:
case Event.ONKEYUP:
case Event.ONKEYPRESS:
if (listeners != null) {
listeners.fireKeyboardEvent(this, event);
}
break;
}
}
}
}

Axel Kittenberger

unread,
Feb 21, 2008, 2:32:27 PM2/21/08
to Google Web Toolkit
Call DOM.eventPreventDefault() in the OnKeyPress handler, to prevent
scrolling.

tacitus

unread,
Feb 21, 2008, 3:00:08 PM2/21/08
to Google Web Toolkit
Oh, my, a one line solution!

Many thanks Axel, so it appears there was a trick that I completely
missed. I don't know how many times I scanned through the DOM methods
without noticing the method and connecting the dots.

Cheers,

Mike
Reply all
Reply to author
Forward
0 new messages