Skip to main content

JXLayer with JScrollPane and JTextPane

10 replies [Last post]
hervea
Offline
Joined: 2008-11-05

First, I had a JTextPane in a JScrollPane. The JTextPane had the with of the JScrollPane, and a height as it want. It was good.

Now, I have put the JTextPane in a JXLayer, and the JXlayer in the JScrollPane

But now the with of JTextPane is not the same as JScrollPane. If the text is short, the width of JTextPane is smaller than the scroller. If the text is long, the width JTextPane is larger than JScrollPane, there is no wrap.

How is it possible to solve that ?

Thank you for your help.

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

Hello Hervea

The following code works fine for me, let me know if you see any problems

[code]
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.ext.LockableUI;
import javax.swing.*;

public class TextTest {

private static void createGui() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JTextPane pane = new JTextPane();

JXLayer l = new JXLayer(pane, new LockableUI() {

@Override
public boolean getScrollableTracksViewportWidth(JXLayer l) {
return l.getParent().getWidth() > l.getView().getPreferredSize().width;
}

@Override
public boolean getScrollableTracksViewportHeight(JXLayer l) {
return l.getParent().getHeight() > l.getView().getPreferredSize().height;
}
});

frame.add(new JScrollPane(l));

frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TextTest.createGui();
}
});
}
}
[/code]

Thanks
alexp

hervea
Offline
Joined: 2008-11-05

Thank you plainty of much for your implcation and your JXLayer.

[b]Yes[/b], I see a problem : if you tape some text in the JTextPane with the JXLayer, the text doesn't wrap ; if you tape some text in a JTextPane without the JXLayer, the text wraps.

(and I should want wrap).

Here is your code with a very little modif :

[code]
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.ext.LockableUI;
import javax.swing.*;

public class TextTest {

private static void createGui() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JTextPane pane = new JTextPane();

JXLayer l = new JXLayer(pane, new LockableUI() {

@Override
public boolean getScrollableTracksViewportWidth(JXLayer l) {
return l.getParent().getWidth() > l.getView().getPreferredSize().width;
}

@Override
public boolean getScrollableTracksViewportHeight(JXLayer l) {
return l.getParent().getHeight() > l.getView().getPreferredSize().height;
}
});

// frame.add(new JScrollPane(l));
frame.add(new JScrollPane(pane)); // with JTextPane direct

frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TextTest.createGui();
}
});
}
}
[/code]
Tape "And One And Two And Three And Four" : the text wraps. How is it possible to get same with JXLayer ?

alexfromsun
Offline
Joined: 2005-09-05

Hello Hervea

This problem with scrolling is bigger than I expected, thanks for letting me know
Unfortunately JEditorPane.getPreferredSize() also does the following check:
[code]
if (getParent() instanceof JViewport)
[/code]

and I will be able to reliably fix only if JXLayer is integrated to JDK 7

Meanwhile I updated JXLayer bits to make possible the following workaround:
(download the latest jxlayer.jar from http://jxlayer.dev.java.net, the Maven rep will also be updated)

[code]
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.ext.LockableUI;
import org.jdesktop.jxlayer.plaf.item.LayerItemChangeEvent;

import javax.swing.*;
import javax.swing.plaf.TextUI;
import java.awt.*;

public class TextTest {

private static void createGui() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JTextPane pane = new JTextPane();

JXLayer l = new JXLayer(pane, new LockableUI() {

@Override
public boolean getScrollableTracksViewportWidth(JXLayer l) {
// copied from JEditorPane.getScrollableTracksViewportWidth
if (l.getParent() instanceof JViewport) {
JViewport port = (JViewport)l.getParent();
JTextPane textPane = ((JTextPane) l.getView());
TextUI ui = textPane.getUI();
int w = port.getWidth();
Dimension min = ui.getMinimumSize(textPane);
Dimension max = ui.getMaximumSize(textPane);
if ((w >= min.width) && (w <= max.width)) {
return true;
}
}
return false;
}

@Override
public boolean getScrollableTracksViewportHeight(JXLayer l) {
// copied from JEditorPane.getScrollableTracksViewportHeight
if (l.getParent() instanceof JViewport) {
JViewport port = (JViewport)l.getParent();
JTextPane textPane = ((JTextPane) l.getView());
TextUI ui = textPane.getUI();
int h = port.getHeight();
Dimension min = ui.getMinimumSize(textPane);
if (h >= min.height) {
Dimension max = ui.getMaximumSize(textPane);
if (h <= max.height) {
return true;
}
}
}
return false;
}

public Dimension getPreferredSize(JComponent c) {
JXLayer l = (JXLayer) c;

// copied from JEditorPane.getPreferredSize
Dimension d = l.getView().getPreferredSize();
if (c.getParent() instanceof JViewport) {
JViewport port = (JViewport)c.getParent();
TextUI ui = l.getView().getUI();
int prefWidth = d.width;
int prefHeight = d.height;
if (! l.getView().getScrollableTracksViewportWidth()) {
int w = port.getWidth();
Dimension min = ui.getMinimumSize(l.getView());
if (w != 0 && w < min.width) {
// Only adjust to min if we have a valid size
prefWidth = min.width;
}
}
if (! l.getView().getScrollableTracksViewportHeight()) {
int h = port.getHeight();
Dimension min = ui.getMinimumSize(l.getView());
if (h != 0 && h < min.height) {
// Only adjust to min if we have a valid size
prefHeight = min.height;
}
}
if (prefWidth != d.width || prefHeight != d.height) {
d = new Dimension(prefWidth, prefHeight);
}
}
return d;
}
});

frame.add(new JScrollPane(l));
// frame.add(new JScrollPane(pane)); // with JTextPane direct

frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TextTest.createGui();
}
});
}
}[/code]

Thanks
alexp

hervea
Offline
Joined: 2008-11-05

OK that's work for me too. Thank you. I'm going to integrate JXLayer in my application.

Do you think JXLayer will be in Java 7 ?

alexfromsun
Offline
Joined: 2005-09-05

Hello Hervea

> Do you think JXLayer will be in Java 7 ?

It's not decided yet,
but if it will I'll be able to fix all that mess with scrolling
:-)

Thanks
alexp

alexfromsun
Offline
Joined: 2005-09-05

Hello Hervea

This is the same problem as it was mentioned about JList here

For some reason core Swing components uses a strange instanceof check in methods from Scrollable interface, e.g. the code from JTextComponent

[code]
public boolean getScrollableTracksViewportWidth() {
if (getParent() instanceof JViewport) {
return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
}
return false;
}
[/code]

in my opinion this instanceof check doesn't have any sense and I will probably remove it for JDK 7
the workaround is simple - override getScrollableTracksViewportWidth() and getScrollableTracksViewportHeight() in your LayerUI and make them return the value under instanceof check

see this thread for more examples

I am going to update those methods in the nearest future to correctly process Swing core components

Thanks

alexp

hervea
Offline
Joined: 2008-11-05

I don't understand something. I've put that in my "MyClass extends JTextPane" :

@Override
public boolean getScrollableTracksViewportWidth()
{
return getParent().getWidth() > getPreferredSize().width;
}

@Override
public boolean getScrollableTracksViewportHeight()
{
return getParent().getHeight() > getPreferredSize().height;
}

... and that does'nt work. It's the same than before.

Thank for your help.

alexfromsun
Offline
Joined: 2005-09-05

Hello Hervea

You should put them in your "MyLayerUI extends (AbstractLayerUI or whatever)"
make sure that the methods signature are correct (methods are introduced in the LayerUI class)

[code]
public boolean getScrollableTracksViewportWidth(JXLayer l)

public boolean getScrollableTracksViewportHeight(JXLayer l)
[/code]

Thanks
alexp

hervea
Offline
Joined: 2008-11-05

I progress, thank you very much : it's ok with heigh, but no with width.

i write that (sorry, I don't understand how to put a text in a source style) :
[code]
private class LockableUIWithNoBug extends
org.jdesktop.jxlayer.plaf.ext.LockableUI
{
LockableUIWithNoBug(AbstractLayerEffect effect)
{
super(effect);
}

@Override
public boolean getScrollableTracksViewportWidth(JXLayer l)
{
return l.getParent().getWidth() > l.getView().getPreferredSize().width;
}

@Override
public boolean getScrollableTracksViewportHeight(JXLayer l)
{
return l.getParent().getHeight() > l.getView().getPreferredSize().height;
}

}
[/code]

Perhaps the problem : I don't set a preferred size to the getView panel, I set preferredSize on the container of the JScrollPane ?

(thanks to pietblok for the "code" tips)

Message was edited by: hervea

pietblok
Offline
Joined: 2003-07-17

Hi,

"Perhaps the problem : I don't set a preferred size to the getView panel, I set preferredSize on the container of the JScrollPane ? "

Yes, that makes sense to me. After all, in the getScrollableTracksXXX methods you use the getPreferredSize of the view.

When you paste code between [ CODE ] and [ /CODE ] tags (without the spaces) the code will be formatted.

Piet