当前位置: 首页 > 知识库问答 >
问题:

Java Nimbus每个组件的外观定制(“Nimbus.Overrides”)——其他实例也受到影响

禄星腾
2023-03-14

我不熟悉Java Nimbus的外观和感觉。我正在尝试使用Nimbus的功能,使用putClientProperty(“Nimbus.Overrides”,Overrides)定制单个组件实例:https://docs.oracle.com/javase/8/docs/api/javax/swing/plaf/nimbus/package-summary.html

我遇到了以下问题(bug?):

不幸的是,“Nimbus.Overrides”值显然不仅会影响它被明确设置的组件对象,还会影响其他对象。

定制属性似乎是以某种方式“继承”到同一类型的其他实例(后来是“样式化的”,显然以前不是)。我需要确保只对一个实例进行更改(不影响任何其他对象)。示例-JButton已使用,但与例如JTabbedPane和自定义画师遇到的问题相同:

>

import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIDefaults;


public class NimbusPerComponentTest extends JFrame {

public NimbusPerComponentTest()  {
    super("Test");
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setLayout(new FlowLayout());

    // 4 buttons to test
    JButton button1 = new JButton("Button 1");
    JButton button2 = new JButton("Button 2");
    JButton button3 = new JButton("Button 3");
    JButton button4 = new JButton("Button 4");
    add(button1);
    add(button2);
    add(button3);
    add(button4);
    pack();

    // style        
    // button 1
    UIDefaults overrides1 = new UIDefaults();
    overrides1.put("Button.contentMargins", new Insets(10,10,10,10));        
    button1.putClientProperty("Nimbus.Overrides", overrides1);
    // button 2
    UIDefaults overrides2 = new UIDefaults();        
    overrides2.put("Button.font", new Font("Sans Serif", Font.BOLD, 15));
    button2.putClientProperty("Nimbus.Overrides", overrides2);
    // button 3
    UIDefaults overrides3 = new UIDefaults();
        // nothing = left empty
    button3.putClientProperty("Nimbus.Overrides", overrides3);
    // button 4
    // no styling        

}

public static void main(String args[]) {        
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(NimbusPerComponentTest.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }       
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new NimbusPerComponentTest().setVisible(true);
        }
    });
}
}            

知道为什么吗?我错过了什么?有什么优雅的变通方法吗?(Java8,视窗10)

编辑

经过一些答案的启发:

尝试在我的原始代码末尾重置lookandfeel(设置为null并再次返回Nimbus,包括SwingUtilities.updateComponentTreeUI),唯一的结果是:

现在甚至连按钮4都画错了(边距和字体都变了),尽管通用默认值从未被触及...奇怪。

编辑2

我设法找到了一条单行线的解决方法。看看我自己对我的问题的回答。。。

共有3个答案

慕飞章
2023-03-14

我怀疑这是由于javax的shouldUpdateStyleOneEvent方法中的一个错误造成的。摆动普拉夫。光轮。NimbusLookAndFeel。来源:

protected boolean shouldUpdateStyleOnEvent(PropertyChangeEvent ev) {
    String eName = ev.getPropertyName();

    // These properties affect style cached inside NimbusDefaults (6860433)
    if ("name" == eName ||
        "ancestor" == eName ||
        "Nimbus.Overrides" == eName ||
        "Nimbus.Overrides.InheritDefaults" == eName ||
        "JComponent.sizeVariant" == eName) {

        JComponent c = (JComponent) ev.getSource();
        defaults.clearOverridesCache(c);
        return true;
    }

    return super.shouldUpdateStyleOnEvent(ev);
}

不用说,这不是比较字符串的有效方法。我在bug数据库中找不到任何与此相关的信息;也许等我有时间的时候,我会提交一份bug报告。

景令秋
2023-03-14

经过相当长时间的调试,我似乎已经找到了一个单行的解决方法/破解方法,这可能也表明了问题的原因:

使用putClientProperty("Nimbus. Overrides", overrides)对每个组件进行样式化后,您可以通过此代码阻止将属性“继承”到后续样式化的组件:

button1.putClientProperty("Nimbus.Overrides", overrides1);
UIManager.getDefaults().putDefaults(new Object[0]); 
  // add after each "styling"
  // - clears the compiledDefaults in NimbusLookAndFeel

它有什么作用?

功能上讲,没有什么(empy array=nothing put),但它会触发PropertyChange事件(请参见此处的源代码),在NimbusLookAndFeel类(请参见此处的源代码)的DefaultsListener私有类中监听该事件,这是我设法找到的清除compiledDefaults缓存(?)在NimbusLookAndFeel中,在我看来,这是导致问题的原因:

if ("UIDefaults".equals(key)) {
    compiledDefaults = null;
}

我注意到在NimbusLookAnd感到类中的getDefaultsForPrefix方法(使用compiledDefault)调试期间存在问题-请参阅此处的源代码。对于更高版本的组件,它不仅返回“真正的默认值”,而且由于某种原因还返回设置为前一个组件的自定义属性。

明确地说:我完全是个业余爱好者,对Nimbus课程的细节或架构没有详细的知识或理解。我可能错了,但解决方案对我来说是有效的。。。

它是否因某种原因不适合?有风险吗?它真的是一个错误吗?

一个问题:

我注意到,如果在使用putClientProperty设置组件的样式之前(就像我在问题中的代码中那样),但在之后,我pack()my frame,那么解决方案就不起作用了(没有任何帮助)。。。

戎俊
2023-03-14

如果我更改UIDefault的创建,它对我有用。而不是

UIDefaults overrides1 = new UIDefaults();

我曾经

UIDefaults overrides1 = (UIDefaults) UIManager.getLookAndFeelDefaults().clone();

overrides2overrides3也执行此操作:

    // style
    // button 1
    UIDefaults overrides1 = (UIDefaults) UIManager.getLookAndFeelDefaults().clone();
    overrides1.put("Button.contentMargins", new Insets(10, 10, 10, 10));
    button1.putClientProperty("Nimbus.Overrides", overrides1);
    // button 2
    UIDefaults overrides2 = (UIDefaults) UIManager.getLookAndFeelDefaults().clone();
    overrides2.put("Button.font", new Font("Sans Serif", Font.BOLD, 15));
    button2.putClientProperty("Nimbus.Overrides", overrides2);
    // button 3
    UIDefaults overrides3 = (UIDefaults) UIManager.getLookAndFeelDefaults().clone();
    // nothing = left empty
    button3.putClientProperty("Nimbus.Overrides", overrides3);
    // button 4
    // no styling

这会在我的机器上产生以下输出:

请注意,以这种方式创建的UIDefaults的大小可能相当大。

 类似资料:
  • 我有n个服务器线程,每个线程都听1个客户端。 当一个服务器线程从其客户端接收到消息时,它需要通知其他“n-1”客户端,这就是为什么我在服务器线程之间保留一个共享对象(包含一个“n”套接字数组,每个客户端一个)。 此外,在持有的主服务器线程中,每次我接受与客户端的新连接时,我都会打开一个,使用从返回的新套接字向他给出第一个答案。 在回答“OK”的情况下,我打开一个新线程,将新套接字传递给它,以便监听

  • 我试图通过名为LoginController的控制器获取客户端IP,但错误仍然存在。 传递给App\Http\Controller\Auth\LoginController的参数1::a的验证()必须是App\Http\Controller\Auth\Request的实例,给定Illumate\Http\Request的实例 我已经跟随这个SO问题,但仍然得到相同的错误。 所以,我刚刚发现了Aut

  • 问题内容: 我负责四种不同的Jenkins安装-两台测试服务器和两台生产服务器。 在Jenkins中,我有哪些选择可以使我更清楚地知道连接到哪台计算机? 我想做的是能够将屏幕顶部的Jenkins文本更改为“ Jenkins Department 1 Test”-这可能吗?还有其他选项,例如更改颜色等吗? 问题答案: 我认为最简单的方法是使用“ 简单主题插件”。 Jenkins的插件,支持自定义CS

  • DocBook 输出为 Html 时,如果不使用 CSS 控制,那么它的外观将比较“朴素” 如果自己写一个 CSS 未免太麻烦,可以随便找一个 DocBook 写的文档,将里面的 CSS 文件拿来修改[58] 通过例子简单介绍下 CSS body { font-family: verdana, tahoma, helvetica, arial, sans-serif; text-alig

  • 我使用的是ListView,每个列表元素上都有几个按钮。 单击行上的按钮时,该按钮应消失。单击按钮时,单击的按钮会消失,这没关系。问题是其他一些列表元素按钮也不见了。 例如,当我点击第一元素按钮时,它也会影响第六、第十一、第十六元素中的按钮。 原因是适配器没有为数据中的所有元素创建列表元素。它只创建了几个足以在屏幕上显示的对象。如图所示,在列表中向下移动时,top元素成为最后一个元素,其值也发生了

  • JavaScript对象Module控制了运行时相关的很多行为。在之前的章节中,我们尝试了: 使用Module.onRuntimeInitialized回调在运行时准备就绪后执行测试代码。 通过更改Module.TOTAL_MEMORY设置内存容量。 我们可以使用类似的方法更改Module的标准输出行为,例如: <!--custom_print.html--> <script> Module