Skip to main content

A key capturing label.

4 replies [Last post]
i30817
Offline
Joined: 2006-05-02
Points: 0

Well if a color button can be proposed, i expect this can too...

There is a weird double selection problem, it probably won't work with keyboard navigation, if i remember correctly not all key combinations worked and i had to filter some, and there are probably better ways of doing this (ie: the netbeans way that allows multiple keystrokes per action).

The color used is SystemColor.controlShadow since this is used as a lighter shade than text in all operating systems.

I'd just like to start a discussion, since i think its a reinventing the wheel thing, that probably gets done a lot.

I'm a terrible coder though, don't expect brilliant insights here.

<br />
/*<br />
 * KeyCapturer.java<br />
 *<br />
 * Created on 24 de Fevereiro de 2007, 19:36<br />
 *<br />
 * To change this template, choose Tools | Template Manager<br />
 * and open the template in the editor.<br />
 */<br />
package ui.components;</p>
<p>import java.awt.AWTEvent;<br />
import java.awt.Color;<br />
import java.awt.SystemColor;<br />
import java.awt.Toolkit;<br />
import java.awt.event.AWTEventListener;<br />
import java.awt.event.FocusAdapter;<br />
import java.awt.event.FocusEvent;<br />
import java.awt.event.FocusListener;<br />
import java.awt.event.KeyAdapter;<br />
import java.awt.event.KeyEvent;<br />
import java.awt.event.KeyListener;<br />
import java.awt.event.MouseAdapter;<br />
import java.awt.event.MouseEvent;<br />
import java.awt.event.MouseListener;<br />
import javax.swing.Icon;<br />
import javax.swing.JLabel;<br />
import javax.swing.KeyStroke;</p>
<p>/**<br />
 *<br />
 * @author i30817<br />
 */<br />
public class KeyCapturer extends JLabel {</p>
<p>    /**<br />
     * Field used to listen to property changed events refering to changed<br />
     * captured keys.<br />
     **/<br />
    public static final String CAPTURED_KEYSTROKE = "Captured a keyStroke";<br />
    private KeyStroke capturedKeyStroke;<br />
    private boolean capturing = false;</p>
<p>    public KeyCapturer(String text, Icon icon, int horizontalAlignment) {<br />
        super(text, icon, horizontalAlignment);<br />
        setup();<br />
    }</p>
<p>    public KeyCapturer(String text, int horizontalAlignment) {<br />
        super(text, horizontalAlignment);<br />
        setup();<br />
    }</p>
<p>    public KeyCapturer(String text) {<br />
        super(text);<br />
        setup();<br />
    }</p>
<p>    public KeyCapturer(Icon image, int horizontalAlignment) {<br />
        super(image, horizontalAlignment);<br />
        setup();<br />
    }</p>
<p>    public KeyCapturer(Icon image) {<br />
        super(image);<br />
        setup();<br />
    }</p>
<p>    public KeyCapturer() {<br />
        super();<br />
        setup();<br />
    }<br />
    private AWTEventListener mouseTrick = new AWTEventListener() {</p>
<p>        public void eventDispatched(AWTEvent e) {<br />
            if (e instanceof MouseEvent && capturing) {<br />
                MouseEvent me = (MouseEvent) e;<br />
                if (me.getClickCount() > 0) {<br />
                    getParent().requestFocus();<br />
                }<br />
            }<br />
        }<br />
    };<br />
    private static FocusListener focus = new FocusAdapter() {</p>
<p>        Color c = SystemColor.controlShadow;</p>
<p>        public void focusGained(FocusEvent e) {<br />
            if (!e.isTemporary()) {<br />
                KeyCapturer thisOne = (KeyCapturer) e.getComponent();<br />
                thisOne.capturing = true;<br />
                thisOne.setBackground(c);<br />
                Toolkit.getDefaultToolkit().addAWTEventListener(thisOne.mouseTrick, AWTEvent.MOUSE_EVENT_MASK);<br />
            }<br />
        }</p>
<p>        public void focusLost(FocusEvent e) {<br />
            if (!e.isTemporary()) {<br />
                KeyCapturer thisOne = (KeyCapturer) e.getComponent();<br />
                Toolkit.getDefaultToolkit().removeAWTEventListener(thisOne.mouseTrick);<br />
                thisOne.capturing = false;<br />
                thisOne.setBackground(null);<br />
            }<br />
        }<br />
    };<br />
    private static MouseListener mouse = new MouseAdapter() {</p>
<p>        public void mouseClicked(MouseEvent e) {<br />
            KeyCapturer thisOne = (KeyCapturer) e.getComponent();<br />
            thisOne.requestFocusInWindow();<br />
        }<br />
    };<br />
    private KeyListener keyRecorder = new KeyAdapter() {</p>
<p>        public void keyPressed(KeyEvent arg0) {</p>
<p>            if (capturing) {<br />
                KeyStroke key = KeyStroke.getKeyStrokeForEvent(arg0);<br />
                setKeyStroke(key);<br />
            }<br />
        }<br />
    };</p>
<p>    public void setKeyStroke(KeyStroke k) {</p>
<p>        if (k.getKeyCode() != KeyEvent.VK_UNDEFINED) {<br />
            KeyStroke old = capturedKeyStroke;<br />
            capturedKeyStroke = k;<br />
            setText(toString());<br />
            firePropertyChange(CAPTURED_KEYSTROKE, old, capturedKeyStroke);<br />
        }<br />
    }</p>
<p>    public KeyStroke getKeyStroke() {<br />
        return capturedKeyStroke;<br />
    }</p>
<p>    public String toString() {<br />
        int code = capturedKeyStroke.getKeyCode();<br />
        char charCode = capturedKeyStroke.getKeyChar();<br />
        int modifier = capturedKeyStroke.getModifiers();<br />
        String mod = KeyEvent.getKeyModifiersText(modifier);<br />
        String key;</p>
<p>        if (KeyEvent.CHAR_UNDEFINED == charCode) {<br />
            //Default locale seems correct here, since this is for display...<br />
            key = KeyEvent.getKeyText(code).toLowerCase();<br />
        } else {<br />
            key = String.valueOf(charCode).toLowerCase();<br />
        }</p>
<p>        return (mod.equalsIgnoreCase(key)) ? mod : mod + " " + key;<br />
    }</p>
<p>    private void setup() {<br />
        addKeyListener(keyRecorder);<br />
        addFocusListener(focus);<br />
        addMouseListener(mouse);<br />
        setOpaque(true);<br />
    }<br />
}</p>
<p>

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Kleopatra

jdnc-interest@javadesktop.org schrieb:
> Well if a color button can be proposed, i expect this can too...
>
>

hmm ... you see me confused: what exactly is a "color button" and which
problem do you suggest to solve with your code? Looks like a no-no to me
because a JLabel is not meant for user-interaction ;-)

CU
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

kschaefe
Offline
Joined: 2006-06-08
Points: 0

> Looks
> like a no-no to me
> because a JLabel is not meant for user-interaction
> ;-)
To clarify, this is not 100% accurate. JLabel will give focus to a component if the label has a mnemonic and the a non-null component was assigned via setLabelFor(Component).

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
>> Looks
>> like a no-no to me
>> because a JLabel is not meant for user-interaction
>> ;-)
>>
> To clarify, this is not 100% accurate. JLabel will give focus to a component if the label has a mnemonic and the a non-null component was assigned via setLabelFor(Component).
>
>

weeeell .. I would regard that behaviour as an implementation trick ;-)
Doesn't change its basic non-interactive nature, IMO.

BTW, the labelFor property is one of more unfortuate early design
decisions in Swing: it had soon be supplemented by a client property in
the "for" component. And it's not very rich: mnemonics set in a "for"
component's action aren't supported, enabled state isn't synched, the
intermediate focus is confusing for custom focus traversals ... could go
on, but have to admit that I didn't look into it in the recent past, so
some of those could be fixed by now, so should stop ranting right now .

Cheers
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

i30817
Offline
Joined: 2006-05-02
Points: 0

So what would you suggest instead of a JLabel?

Anyway i started this thread because any non-trivial program [b]will[/b] want to customize their action shortcuts. There is the infrastructure to set up the action on KeyStroke in JComponent, but there is no simple way for the user to set with (without a small programming effort as above).

Even this is not a solution because it won't scale well (only one keystroke at a time, only one keystroke displayed) and because the binding of the actions to the bindings still has to be done manually.
My code now looks like:
select action -> update label with existing KeyStroke (if any) -> wait for user to register a keystroke -> save in the event.

This pattern will repeat for many things, some with more than one level for example:
select font configuration action -> update property list -> select italic -> select italic off -> save in the event.

It's vastly messy.