Skip to main content

JEditorPane not editable seems to disable the LayerUI

2 replies [Last post]
pietblok
Offline
Joined: 2003-07-17
Points: 0

Hi Alex,

I don't know if this is a bug or feature, but when a JEditorPane is wrapped in a JXLayer, setting editable to false seems to disable (partly) the applied LayerUI.

Below the code to demonstrate. It is almost a verbatim copy of your MouseDrawingDemo. But I added a JEditorPane and a menu to set it editable.

What I see is that, when the editor pane is not editable, an attempt to draw that starts over the editor pane is not honoured. If you start the drawing over the other components however, the drawing is honoured, even over the editor pane.

Thanks
Piet

<br />
import org.jdesktop.jxlayer.JXLayer;<br />
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;</p>
<p>import javax.swing.*;</p>
<p>import java.awt.*;<br />
import java.awt.event.*;<br />
import java.util.ArrayList;<br />
import java.util.List;</p>
<p>/**<br />
 * For 95 percent a copy of MouseDrawingDemo.<br />
 * Added a JEditorPane that can be set editable / not editable<br />
 * to demonstrate that, when the JEditorPane is not editable,<br />
 * drawing that starts above the JEditorPane is disabled.<br />
 */<br />
public class MouseDrawingDemoPB {</p>
<p>    // UI which allows to paint on top of the components<br />
    public static class MouseDrawingUI extends<br />
	    AbstractLayerUI {<br />
	private List> pathList = new ArrayList>();<br />
	private List currentPath;</p>
<p>	// clear overlay painting<br />
	public void clear() {<br />
	    pathList.clear();<br />
	    // mark the ui as dirty and needed to be repainted<br />
	    setDirty(true);<br />
	}</p>
<p>	// override paintLayer(), not paint()<br />
	protected void paintLayer(Graphics2D g2, JXLayer l) {<br />
	    // this paints layer as is<br />
	    super.paintLayer(g2, l);<br />
	    // custom painting is here<br />
	    g2.setColor(Color.RED);<br />
	    g2.setStroke(new BasicStroke(2f));<br />
	    for (java.util.List points : pathList) {<br />
		Point oldPoint = null;<br />
		for (Point point : points) {<br />
		    if (oldPoint != null) {<br />
			g2.drawLine(oldPoint.x, oldPoint.y, point.x, point.y);<br />
		    }<br />
		    oldPoint = point;<br />
		}<br />
	    }<br />
	}</p>
<p>	// catch MouseEvent.MOUSE_RELEASED<br />
	@Override<br />
	protected void processMouseEvent(MouseEvent e, JXLayer l) {<br />
	    if (e.getID() == MouseEvent.MOUSE_RELEASED) {<br />
		currentPath = null;<br />
		// mark the ui as dirty and needed to be repainted<br />
		setDirty(true);<br />
	    }<br />
	}</p>
<p>	// catch drag events<br />
	@Override<br />
	protected void processMouseMotionEvent(MouseEvent e, JXLayer l) {<br />
	    if (e.getID() == MouseEvent.MOUSE_DRAGGED) {<br />
		Point point = SwingUtilities.convertPoint(e.getComponent(), e<br />
			.getPoint(), l);<br />
		if (currentPath == null) {<br />
		    currentPath = new ArrayList();<br />
		    pathList.add(currentPath);<br />
		}<br />
		currentPath.add(point);<br />
		// mark the ui as dirty and needed to be repainted<br />
		setDirty(true);<br />
	    }<br />
	}<br />
    }</p>
<p>    public static void main(String[] args) throws Exception {<br />
	SwingUtilities.invokeLater(new Runnable() {<br />
	    public void run() {<br />
		createGui();<br />
	    }<br />
	});<br />
    }</p>
<p>    private static void createGui() {<br />
	final JFrame frame = new JFrame("MouseDrawingDemo");<br />
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);</p>
<p>	JPanel panel = new JPanel();<br />
	for (int i = 0; i < 3; i++) {<br />
	    panel.add(new JButton("JButton"));<br />
	    panel.add(new JCheckBox("JCheckBox"));<br />
	    panel.add(new JTextField("JTextField"));<br />
	}</p>
<p>	final JEditorPane editor = new JEditorPane("text/plain",<br />
		"This is a JEditorPane\nThis is a JEditorPane\nThis is a JEditorPane");</p>
<p>	JPanel mainPanel = new JPanel(new BorderLayout());<br />
	mainPanel.add(panel, BorderLayout.CENTER);<br />
	mainPanel.add(editor, BorderLayout.PAGE_END);</p>
<p>	JXLayer jXLayer = new JXLayer(mainPanel);</p>
<p>	final MouseDrawingUI mouseDrawingUI = new MouseDrawingUI();<br />
	jXLayer.setUI(mouseDrawingUI);<br />
	frame.add(jXLayer);</p>
<p>	JMenuBar bar = new JMenuBar();<br />
	JMenu options = new JMenu("Options");<br />
	JMenuItem clearMenu = new JMenuItem("Clear");<br />
	clearMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,<br />
		InputEvent.ALT_MASK));<br />
	clearMenu.addActionListener(new ActionListener() {<br />
	    public void actionPerformed(ActionEvent e) {<br />
		mouseDrawingUI.clear();<br />
	    }<br />
	});<br />
	options.add(clearMenu);<br />
	JCheckBoxMenuItem disableItem = new JCheckBoxMenuItem("Disable LayerUI");<br />
	disableItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D,<br />
		InputEvent.ALT_MASK));<br />
	disableItem.addItemListener(new ItemListener() {<br />
	    public void itemStateChanged(ItemEvent e) {<br />
		mouseDrawingUI<br />
			.setEnabled(e.getStateChange() != ItemEvent.SELECTED);<br />
	    }<br />
	});<br />
	options.add(disableItem);</p>
<p>	JCheckBoxMenuItem editableItem = new JCheckBoxMenuItem(<br />
		"Set JEditorPane editable");<br />
	editableItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,<br />
		InputEvent.ALT_MASK));<br />
	editableItem.addItemListener(new ItemListener() {<br />
	    public void itemStateChanged(ItemEvent e) {<br />
		editor.setEditable(e.getStateChange() == ItemEvent.SELECTED);<br />
	    }<br />
	});<br />
	editor.setEditable(editableItem.isSelected());<br />
	options.add(editableItem);</p>
<p>	bar.add(options);<br />
	frame.setJMenuBar(bar);<br />
	frame.setSize(300, 300);<br />
	frame.setLocationRelativeTo(null);<br />
	frame.setVisible(true);<br />
    }<br />
}<br />

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

It turned out that read-only text component disables their input methods support,
in the JTextComponent.setEditable() method you can find:

[code]
enableInputMethods(editable);
[/code]
JXLayer uses public API of input method to catch input events
http://weblogs.java.net/blog/alexfromsun/archive/2008/07/jxlayer_30_even...

Unfortunately that means that you've found a JXLayer limitation
and I can't do anything about it in my code....
:-\

The workaround is to manually enable inputEvents for the read-only text components
or add a mouseListeners to them in the installUI() method

Looks like AwtEventListener is the only way to catch events for all components
I didn't want to use because it didn't work for unsigned applets

I might add it later

Thanks
alexp

pietblok
Offline
Joined: 2003-07-17
Points: 0

Thanks Alex,

I just stumbled into it when exploring what happens when I wrap a JXLayer into another JXLayer, in order to apply more than one LayerUI onto the same component. For demonstration purposes I used a JEditorPane that displayed some html text that explains the test. More or less as follows:

[code]
JComponent target = new JComponent() ; // in my test a JEditorPane
JXLayer layer = new JXLayer(target, new MouseDrawingUI());
layer = new JXLayer(layer, new DisapperingCursorUI(1000));
[/code]

To my surprise this seems to work!

Have a nice weekend

Piet