问题描述
我一直在寻找解决方案,我认为这是 Java Swing 非常常见的问题,但找不到具体的答案。
我有这个 Swing JPanel
,顶部有一个可滚动的 JPanel
,显示文档的图像。
下面有更多的 Swing 组件,例如另一个面板中的 JTable
和一些文本框、JButton
控件等。 (同一个 JWindow
中有更多面板。)
当用户在下面的框中编辑数据等时,这些当然会获得应有的关注。现在,当用户想要滚动文档中的某些特定数据时,他/她需要先将焦点(使用鼠标/选项卡)设置在其上,然后再滚动。
所以用户想使用例如向上/向下箭头键盘,而不会离开他正在使用的其他组件的焦点。
我已经尝试设置键盘处理程序,但如果不将焦点移到顶部就无法使其工作。
如果没有这个组件(和另一个)有焦点,就没有办法滚动可滚动的 Swing 组件吗?
解决方法
如果组件是滚动窗格中的文本字段,似乎 Page Down 可以在(至少第一个)文本字段获得焦点时起作用。这是运行此类代码并多次点击 Page Down 的结果。
如果在聚焦滚动窗格外部的组件时需要此行为,请查看key bindings。
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class KeyboardScroll {
private JComponent ui = null;
KeyboardScroll() {
initUI();
}
public void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4,4));
ui.setBorder(new EmptyBorder(4,4,4));
JPanel textPanel = new JPanel(new GridLayout(0,1));
for (int ii = 1; ii < 101; ii++) {
textPanel.add(new JTextField("Field " + ii,30));
}
JScrollPane scrollPane = new JScrollPane(textPanel,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
ui.add(scrollPane);
Dimension d = textPanel.getPreferredSize();
scrollPane.getViewport().setPreferredSize(
new Dimension((int)d.getWidth(),100));
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
KeyboardScroll o = new KeyboardScroll();
JFrame f = new JFrame("Use 'Page Down'");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
,
如果没有这个组件(和另一个)有焦点,就没有办法滚动可滚动的 Swing 组件吗?
那么一般的解决方案是使用Key Bindings。
然而,问题在于每个组件都可以为 up/down 事件实现 Key Bindings 本身,在这种情况下,会调用该组件的相关 Action
。
本教程演示了如何从组件中删除键绑定。
一个 JTable 和一些文本框
所以这些是实现向上/向下键绑定的组件示例。
JButton 控件
是没有默认向上/向下键绑定的组件的示例。
因此您可以使用如下代码添加自己的代码:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
setLayout( new BorderLayout() );
JPanel top = new JPanel();
top.add( new JTextField(10) );
top.add( new JButton("Button") );
add(top,BorderLayout.PAGE_START);
JLabel label = new JLabel( new ImageIcon("mong.jpg") );
JScrollPane scrollPane = new JScrollPane( label );
add(scrollPane,BorderLayout.CENTER);
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
InputMap im = getInputMap(JScrollBar.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke("pressed UP"),"up");
am.put("up",new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
scrollBar.setValue(scrollBar.getValue() - scrollBar.getUnitIncrement(-1));
}
});
im.put(KeyStroke.getKeyStroke("pressed DOWN"),"down");
am.put("down",new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
scrollBar.setValue(scrollBar.getValue() + scrollBar.getUnitIncrement(1));
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
在上面的例子中,当焦点在按钮上时图像会滚动,而不是在文本字段上。