【问题标题】:Default button input map in a synth look and feel?合成器外观中的默认按钮输入映射?
【发布时间】:2012-09-17 17:19:27
【问题描述】:

我正在尝试使用 UIManager 来获取和清除一些默认键绑定,以便空格键不会激活我的 JButton,如 here 所述。问题是,可能由于我的合成器外观和感觉,(InputMap)UIManager.get("Button.focusInputMap"); 返回一个null。有谁知道以其他方式轻松清除组件输入映射的方法,或者为什么 UIManager 在这种情况下返回 null ?任何提示都表示赞赏,在此先感谢。

【问题讨论】:

  • workforme (nimbus, jdk6/7) - 那么你的 LAF 是什么?看起来有什么问题..
  • paddle back: 不起作用 ;-) inputMap 不为空,但替换其中按下/释放的绑定不会阻止空间触发按钮Nimbus(就像在胜利和金属中一样)

标签: java swing look-and-feel key-bindings synth


【解决方案1】:

首先:我喜欢 @David 在另一个答案中建议的装饰 StyleFactory 的想法 :-) - 所以如果可行,建议使用这个方向。

无论如何,忍不住尝试一下:看起来 Nimbus(可能还有其他基于 Synth 的 LAF)需要在生命周期的早期非常覆盖这些默认值:只有在完成后才会接受它们在任何组件实际创建之前

// setting LAF
InteractiveTestCase.setLAF("Nimbus");
// tweak inputMap, immediately after setting the ui is fine
// uncomment the following line and it doesn't work
// new JPanel();
InputMap inputMap = (InputMap) UIManager.get("Button.focusInputMap");
inputMap.put(KeyStroke.getKeyStroke("SPACE"), "do-nothing");

如果此时 UIManager 没有返回 inputMap,我会认为这是您的自定义 LAF 的不当行为,并会尝试进一步挖掘为什么会发生这种情况。您可以尝试的另一件事是设置一个全新的 inputMap(这将具有在 LAF 切换中幸存的优势,因为它不是 UIResource,例如:

// setting LAF
InteractiveTestCase.setLAF("Nimbus");
// tweak inputMap, immediately after setting the ui is fine
InputMap inputMap = (InputMap) UIManager.get("Button.focusInputMap");
InputMap custom = new InputMap();
if (inputMap != null) {
    // copy all bindings to custom
    ...
} else {
    // add the binding we know of (as implementation detail)
    custom.put(KeyStroke.getKeyStroke("released SPACE"), "released");
}
// overwrite the binding you want to change
custom.put(KeyStroke.getKeyStroke("SPACE"), "do-nothing");
// set the custom map
UIManager.put("Button.focusInputMap", custom);

【讨论】:

  • +1 奇怪的是,我的 previous look at this 在 Mac OS X 上与 com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel 一起工作。
  • +1, 1. UIManager.getLookAndFeelDefaults().put("Xxx", "Xxx"), 2. 不确定JButton 因为我尝试使用JMenu(Item) 并且仅在Nimbus L&Fuinstalled 的情况下才有效..., 3 . 在这种情况下,我使用putClientProperty("Xxx", "Xxx")ButtonModel
  • @mKorbel 1) 没有任何区别 2) 好吧,我尝试了很多排列 - 这是唯一有效的排列 :-) 3) 不明白,ButtonModel 与它
  • @trashgod oioioioi ... 又一个 write-once-debug-everywhere 的案例 ;-) 实际上,我认为 Nimbus 行为(如在此处看到的 win)是一个错误:看起来它没有不听 - 或听不够 - 经理属性的变化。
【解决方案2】:

我没有靠近计算机来尝试这个,但是查看 openjdk 7 源代码here,默认情况下映射看起来是固定的。

一个可能的,但有点老套的解决方案可能是创建并安装一个装饰器SynthStyleFactory,它会在返回之前修改样式。

编辑: 我已经更新了下面的代码示例,因为我有机会对此进行测试。它不能以原始形式工作,但更新后的代码对我有用。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.synth.Region;
import javax.swing.plaf.synth.SynthLookAndFeel;
import javax.swing.plaf.synth.SynthStyle;
import javax.swing.plaf.synth.SynthStyleFactory;

import sun.swing.plaf.synth.DefaultSynthStyle;

public class LnFTest {

    public static void main(String[] args) throws UnsupportedLookAndFeelException{

        SynthLookAndFeel laf = new SynthLookAndFeel();
        laf.load(LnFTest.class.getResourceAsStream("laf.xml"), LnFTest.class);
        UIManager.setLookAndFeel(laf);
        SynthLookAndFeel.setStyleFactory(new MyStyleFactory(SynthLookAndFeel.getStyleFactory()));


        JButton button = new JButton("Test");
        button.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                System.out.println("Action Performed");
            }
        });

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(button, BorderLayout.CENTER);
        frame.pack();

        frame.setVisible(true);

    }



}

class MyStyleFactory extends SynthStyleFactory {

    private SynthStyleFactory delegate;
    private Map overrides;

     public MyStyleFactory(SynthStyleFactory delegate){
         this.delegate = delegate;

         overrides = new HashMap();
         overrides.put("Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[0]));
     }

     public SynthStyle getStyle(JComponent c, Region id) {
         SynthStyle style = delegate.getStyle(c, id);

         System.out.println("Style is a: " + style);

         if(style instanceof DefaultSynthStyle){
             ((DefaultSynthStyle)style).setData(overrides);
         }

         return style;

     }
}

编辑: 我似乎无法在原始帖子中添加评论,所以 澄清一下,在创建任何组件之前,我已经确认 UIManager.get("Button.focusInputMap") 仅使用普通 Synth 返回 null。可能 Nimbus 正在覆盖此行为。

 SynthLookAndFeel laf = new SynthLookAndFeel();
 UIManager.setLookAndFeel(laf);
 System.out.println(UIManager.get("Button.focusInputMap") == null); 

【讨论】:

  • getDefaultValue() 在 SynthStyle 中是静态和私有的,关于如何获取输入映射还有其他想法吗?
  • 糟糕,我的错。通过我发布的 openJDK 7 链接,SynthStyle 有一个方法public Object get(SynthContext context, Object key),它只是调用该私有静态方法。它只使用密钥。
  • 嗯,好吧,我一直在尝试这个,但我不知道用什么作为上下文:S 调用 (InputMap)style.get(null, "Button.focusInputMap") 给了我一个空指针异常,即使上下文不是用过...
  • @SuperTron,我在测试后更新了代码示例,并找到了一种至少对我有用的方法。我不知道你是否会收到修改答案的通知。
  • 我知道。看看 API,它似乎是一个奇怪的类。在原始帖子中,由于它是一个解析的 LNF,它可能不使用该类并使用它的子类(ParsedSynthStyle),它不在 sun 包中。
猜你喜欢
  • 2012-08-21
  • 1970-01-01
  • 1970-01-01
  • 2020-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-21
相关资源
最近更新 更多