Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Eric Sosman Newsgroups: comp.lang.java.programmer Subject: Re: UIDefaults key? Date: Wed, 06 Aug 2014 16:52:09 -0400 Organization: A noiseless patient Spider Lines: 149 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Wed, 6 Aug 2014 20:52:12 +0000 (UTC) Injection-Info: mx05.eternal-september.org; posting-host="bd4e1cba8d8592bec5d5ed9e4537fbfd"; logging-data="23168"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX196mDOP41ONiNyrZKUQLeGB" User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.0 In-Reply-To: Cancel-Lock: sha1:TPioRLFOn7AT4GZ0H3uIc18OMyc= Xref: csiph.com comp.lang.java.programmer:29581 On 8/6/2014 4:00 PM, Knute Johnson wrote: > On 8/6/2014 11:38, Eric Sosman wrote: >> On 8/6/2014 2:17 PM, Knute Johnson wrote: >>> On 8/6/2014 10:31, Eric Sosman wrote: >>>> On 8/6/2014 12:25 PM, Knute Johnson wrote: >>>>> JComponent has a method, getUIClassID(), to return the UIDefaults key >>>>> for the ComponentUI subclass. A JTextField returns a key of >>>>> TextFieldUI. A typical subclass is >>>>> javax.swing.plaf.metal.MetalTextFieldUI. >>>>> >>>>> All the interesting details in the UIDefaults however use keys such as >>>>> TextField.foreground, TextField.border, TextField.margin etc. Is >>>>> there >>>>> any way to get the prefix, TextField, from the component other than >>>>> stripping the UI off the end of the UIClassID? >>>> >>>> Climbing the class hierarchy from MetalTextFieldUI up to >>>> BasicTextFieldUI, I find the method >>>> >>>> /** >>>> * Fetches the name used as a key to lookup properties through the >>>> * UIManager. This is used as a prefix to all the standard >>>> * text properties. >>>> * >>>> * @return the name ("TextField") >>>> */ >>>> protected String getPropertyPrefix() { >>>> return "TextField"; >>>> } >>>> >>>> ... which sort of looks like what you're after. (But I haven't >>>> researched any other delegate classes, so it's possible they're >>>> different.) >>>> >>> >>> I think that is the answer Eric but I just not sure how to get there >>> from here yet :-). >> >> Sorry: I somehow thought you already had your hands on an instance >> of the ComponentUI subclass -- But now I think you've got nothing but a >> JComponent object. Also, I see that the method I stumbled upon is >> defined for some ComponentUI subclasses, but not for all. >> >> Perhaps it's time to take a step back and think about the eventual >> goal rather than about one particular (and possibly unworkable) route >> toward it. What problem are you trying to solve? >> > > I'm trying to find one of the properties, ???.background, for several > different components. Currently, I get the UIClassID from the component > and lop of the UI at the end and use that as a key to get the value from > UIDefaults. I was hoping to find a way to get the UIDefaults key > directly from the JComponent but I'm not having much luck. > > That method you found is the way to go but I don't know how to get > there. I've got the name of the class, I just need to create an > instance and call the getPropertyPrefix() method. ... which (as I failed to notice), is `protected'. Also, it's not a ComponentUI method, but a method that some (most?) subclasses happen to provide, independently of each other. > import java.awt.*; > import java.awt.event.*; > import javax.swing.*; > import javax.swing.plaf.*; > import javax.swing.plaf.basic.*; > > public class test9 { > public static void main(String... args) { > EventQueue.invokeLater(new Runnable() { > public void run() { > JTextField tf = new JTextField(); > String key = tf.getUIClassID(); > System.out.println(key); > UIDefaults defaults = UIManager.getDefaults(); > Class clazz = > defaults.getUIClass(key); > System.out.println(clazz.getName()); > } > }); > } > } Here's a horrible hack that works for me, but it looks awfully shaky (and shakily awful): import java.awt.*; import java.awt.event.*; import java.awt.event.*; import java.lang.reflect.*; import java.util.logging.Level; import javax.swing.*; import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; public class test10 { public static void main(String... args) { EventQueue.invokeLater(new Runnable() { public void run() { JTextField tf = new JTextField(); String key = tf.getUIClassID(); System.out.println(key); UIDefaults defaults = UIManager.getDefaults(); Class clazz = defaults.getUIClass(key); System.out.println(clazz.getName()); Method method = findIt(clazz); System.out.println(method.getName()); method.setAccessible(true); try { Constructor ctor = clazz.getConstructor(null); System.out.println(ctor.getName()); ComponentUI instance = (ComponentUI) ctor.newInstance(null); System.out.println(instance); String prefix = (String) method.invoke(instance, null); System.out.println("prefix = \"" + prefix + "\"! Huzzah!"); } catch (Exception ex) { ex.printStackTrace(); } } }); } private static Method findIt(Class clazz) { while (ComponentUI.class.isAssignableFrom(clazz)) { for (Method meth : clazz.getDeclaredMethods()) { if (meth.getName().equals("getPropertyPrefix")) { return meth; } } clazz = clazz.getSuperclass(); } throw new IllegalStateException("no getPropertyPrefix!"); } } Filthy and fragile, no? Hmmm: If you're looking for the default background of a JDoodad in the prevailing look and feel, how about constructing a JDoodad, doing nothing special to it, and calling getBackground()? -- esosman@comcast-dot-net.invalid