JEditorPane and line-wrapping plus validate-problem

[nobr]Hi!

I have two questions: The first is about line wrapping in JEditorPane and the second is a validate problem.

I have a JPanel in a JScrollPane. And to this panel are added and removed some TextBlocks which contain a JEditorPane. I want that scrolling vertical is possible when needed, and that the lines are wrapped so that the JEditorPane's width is the same as the width of the Viewport of the Scrollpane.

Here is my code to demonstrate my problem.

/*

* ScrollTest.java

*

* Created on 12. Dezember 2006, 11:28

*

* To change this template, choose Tools | Options and locate the template under

* the Source Creation and Management node. Right-click the template and choose

* Open. You can then make changes to the template in the Source Editor.

*/

import javax.swing.*;

import javax.swing.text.html.*;

import java.awt.*;

import java.awt.event.*;

/**

*

* @author Annette

*/

publicclass ScrollTestextends JFrame{

JPanel mainPanel;

GridBagLayout layout;

GridBagConstraints constr;

JScrollPane mainScroller;

JCheckBox sizeOfTextBlockIsViewPortSize;

/** Creates a new instance of ScrollTest */

public ScrollTest(){

this.mainPanel =new JPanel();

this.layout =new GridBagLayout();

this.constr =new GridBagConstraints();

this.constr.gridy = 0;

this.constr.weightx = 1.0;

this.constr.weighty = 1.0;

this.constr.fill = GridBagConstraints.BOTH;

this.constr.anchor = GridBagConstraints.NORTHWEST;

mainPanel.setLayout(layout);

mainScroller =new JScrollPane(mainPanel);

this.getContentPane().add(mainScroller, BorderLayout.CENTER);

JPanel buttonPanel =new JPanel();

JButton addButton =new JButton("Add TextBlock");

addButton.addActionListener(new ActionListener(){

publicvoid actionPerformed(ActionEvent e){

TextBlock tb =new TextBlock();

layout.setConstraints(tb, constr);

mainPanel.add(tb);

constr.gridy++;

validate();

}

});

buttonPanel.add(addButton);

JButton removeButton =new JButton("Remove last TextBlock");

removeButton.addActionListener(new ActionListener(){

publicvoid actionPerformed(ActionEvent e){

if (mainPanel.getComponentCount() > 0){

mainPanel.remove(mainPanel.getComponentCount()-1);

constr.gridy--;

validate();

}

}

});

buttonPanel.add(removeButton);

this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);

sizeOfTextBlockIsViewPortSize =

new JCheckBox("preferred size of TextBlock = size of Viewport");

this.getContentPane().add(sizeOfTextBlockIsViewPortSize, BorderLayout.NORTH);

this.setPreferredSize(new Dimension(600,400));

this.pack();

this.setVisible(true);

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

publicstaticvoid main(String[] args){

ScrollTest st =new ScrollTest();

}

class TextBlockextends JPanel{

public TextBlock(){

JEditorPane p =new JEditorPane("text/html","");

p.setEditorKit(new HTMLEditorKit());

p.setText("<html> <head> </head> <body>" + constr.gridy +

"How to Use Scroll Panes<br>" +

"A JScrollPane provides a scrollable view of a component. " +

"When screen real estate is limited, use a scroll pane to " +

"display a component that is large or one whose size can " +

"change dynamically. Other containers used to save screen " +

"space include split panes and tabbed panes. <br>" +

"The code to create a scroll pane can be minimal. For " +

"example, here's a picture of a demo program that puts a " +

"text area in a scroll pane because the text area's size " +

"grows dynamically as text is appended to it:</body></html>");

p.setEditable(false);

this.setBorder(BorderFactory.createEtchedBorder());

this.setLayout(new BorderLayout());

this.add(p, BorderLayout.CENTER);

}

public Dimension getPreferredSize(){

if (sizeOfTextBlockIsViewPortSize.isSelected())return mainScroller.getViewport().getSize();

elsereturn super.getPreferredSize();

}

}

}

I wonder how I can force the width of the TextBlock be the width of the Viewport and the height as needed? Because when you make the window rather small parts of the text are not displayed, because I forced the size of the panel to be like the viewport size.

And there is one strange thing:

When you select the option preferred size of TextBlock = size of Viewport and you remove all TextBlocks the panel is not painted in the correct way. When you do not select this option everything is fine and you can see the empty panel when removing all TextBlocks.

Thank you very much in advance!

Best regards,

Annette[/nobr]

[7513 byte] By [Annette] at [2007-11-26 12:18:07]
# 1

Hi!

Is there no one out there who can help me? Or was it some kind of stupid question? I have always had some problems to understand the layout-management in java and how the components get rendered and which size they have.....

I would very much appreciate every answer!

Thanks!

Annette

Annette at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 2
I observe that you use GridBagLayout. Even the engineers at Sun recommend avoiding it (I remember reading this somewhere on one of the interviews).Perhaps you can look at Box Layout?Just my 2 cents.-Anil Philip
anilp1 at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 3

[nobr]class TextBlock extends JPanel {

public TextBlock() {

JEditorPane p = new JEditorPane("text/html", "");

p.setEditorKit(new HTMLEditorKit());

p.setText("<html> <head> </head> <body>" + constr.gridy +

"How to Use Scroll Panes<br>" +

"A JScrollPane provides a scrollable view of a component. " +

"When screen real estate is limited, use a scroll pane to " +

"display a component that is large or one whose size can " +

"change dynamically. Other containers used to save screen " +

"space include split panes and tabbed panes. <br>" +

"The code to create a scroll pane can be minimal. For " +

"example, here's a picture of a demo program that puts a " +

"text area in a scroll pane because the text area's size " +

"grows dynamically as text is appended to it:</body></html>");

p.setEditable(false);

this.setBorder(BorderFactory.createEtchedBorder());

this.setLayout(new BorderLayout());

this.add(p, BorderLayout.CENTER);

Dimension size=mainScroller.getViewport().getSize();

size.width-=20; //a constant for scroll bar. don't know proper value

p.setPreferredSize(size);

}

}

regards,

Stas[/nobr]

StanislavL at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 4

Anil and Stas, thanks for your answers.

I tried BoxLayout and but this does not change anything.... Nevertheless thank you for your hint not to use GridBagLayout. I always struggled a lot with it. This topic was discussed also here:

http://forum.java.sun.com/thread.jspa?threadID=5114605

And this does not solve the problem either

Dimension size=mainScroller.getViewport().getSize();

size.width-=20; //a constant for scroll bar. don't know proper value

p.setPreferredSize(size);

Because if I set thte preferred size of TextBlock = mainScroller.getViewport().getSize(); I do not have to worry about the width of the scrollbar, like I do with this

public Dimension getPreferredSize() {

if (sizeOfTextBlockIsViewPortSize.isSelected()) return mainScroller.getViewport().getSize();

else return super.getPreferredSize();

}

But I guess I did not make clear my problem so I try again.....

I have that class TextBlock which contains a JEditorPane, but in the real application may contain other stuff like buttons etc. The user adds those TextBlocks to the ScrollPane. And I struggle with the size of that TextBlock.

When I just add the new TextBlock, the lines do not get wrapped, so that I get a horizontal scrollbar and the width of the EditorPane is getting very big depending on the width of the line in the text, because JEditorPane does not wrap the lines. I think only JTextPane offers the possibility of line wrapping, but I have to use JEditorPane. And JEditorPane CAN do line wrapping, too. I do not know how?

When I add the method

public Dimension getPreferredSize() {

return mainScroller.getViewport().getSize();

}

tp the class TextBlock, JEditorPane DOES line-wrapping. But there I run into another problem: When there is not much text in the TextBlock, the height of JEditorPane is too big, if there is a lot of text in it, it is too small and some text is just cut off........

So how can I solve this? Can I force JEditorPane to do the lineWrapping? Or can I set the width of TextBlock and let the JEditorPane decide which height would be right to display all of the text, and not to have too much empty space?

Or is there a completely different way to approach the problem? Some genius way?

Thank you a lot for helping me!

Annette

Annette at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 5

Let me explain what happens.

validate() asks GridBagLayout children fro their preferences. JEditorPane returns preference (line wrp happens if preference > available space).

Then panel returns JEditorPane's prefs to Gridbaglayout and it pass the size to JScrollPane.

That's why scroller appear. Preferences are bigger than available width.

What you should do is to get real size of JEditorpane. For this do following.

int width=sizeofViewport;

p.setText();

p.setSize(width,Integer.MAX_VALUE);

int height=p.getPreferredSize().height;

so set panel's size to th width and height.

hope this helps,

Stas

StanislavL at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 6

[nobr]Great, Stas!

That was it! Thank you very much!!!!!

class TextBlock extends JPanel {

JEditorPane p;

public TextBlock() {

p = new JEditorPane("text/html", "");

p.setEditorKit(new HTMLEditorKit());

p.setText("<html> <head> </head> <body>" +

"START Block " + index + "<br>How to Use Scroll Panes<br>" +

"A JScrollPane provides a scrollable view of a component. " +

"When screen real estate is limited, use a scroll pane to " +

"display a component that is large or one whose size can " +

"change dynamically. Other containers used to save screen " +

"space include split panes and tabbed panes. <br>" +

"grows dynamically as text is appended to it: END OF BLOCK</body></html>");

p.setEditable(false);

this.setBorder(BorderFactory.createEtchedBorder());

this.setLayout(new BorderLayout());

this.add(p, BorderLayout.CENTER);

}

public Dimension getPreferredSize() {

int width=new Double(mainScroller.getViewport().getSize().getWidth()).intValue();

p.setSize(width,Integer.MAX_VALUE);

int height=p.getPreferredSize().height;

return new Dimension(width, height);

}

I changed getPreferredSize to what you wrote and it works fine! I think I understand a little bit more about the size, validate and layout-stuff, now!

Your answer came just in time before I have to go to Kindergarten and pick up me eldest daughter! So I solved THIS problem this morning! Great!

But unfortunately the validate problem stays.....

This the the code now:

/*

* ScrollTest.java

*

* Created on 12. Dezember 2006, 11:28

*

* To change this template, choose Tools | Options and locate the template under

* the Source Creation and Management node. Right-click the template and choose

* Open. You can then make changes to the template in the Source Editor.

*/

import javax.swing.*;

import javax.swing.text.html.*;

import java.awt.*;

import java.awt.event.*;

/**

*

* @author Annette

*/

public class ScrollTest extends JFrame {

JPanel mainPanel;

BoxLayout layout;

JScrollPane mainScroller;

int index = 0;

/** Creates a new instance of ScrollTest */

public ScrollTest() {

this.mainPanel = new JPanel();

this.layout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);

mainPanel.setLayout(layout);

mainScroller = new JScrollPane(mainPanel);

this.getContentPane().add(mainScroller, BorderLayout.CENTER);

JPanel buttonPanel = new JPanel();

JButton addButton = new JButton("Add TextBlock");

addButton.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

TextBlock tb = new TextBlock();

mainPanel.add(tb);

index++;

validate();

}

});

buttonPanel.add(addButton);

JButton removeButton = new JButton("Remove last TextBlock");

removeButton.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

if (mainPanel.getComponentCount() > 0) {

mainPanel.remove(mainPanel.getComponentCount()-1);

index--;

validate();

}

}

});

buttonPanel.add(removeButton);

this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);

this.setPreferredSize(new Dimension(600,400));

this.pack();

this.setVisible(true);

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

public static void main(String[] args) {

ScrollTest st = new ScrollTest();

}

class TextBlock extends JPanel {

JEditorPane p;

public TextBlock() {

p = new JEditorPane("text/html", "");

p.setEditorKit(new HTMLEditorKit());

p.setText("<html> <head> </head> <body>" +

"START Block " + index + "<br>How to Use Scroll Panes<br>" +

"A JScrollPane provides a scrollable view of a component. " +

"When screen real estate is limited, use a scroll pane to " +

"display a component that is large or one whose size can " +

"change dynamically. Other containers used to save screen " +

"space include split panes and tabbed panes. <br>" +

"A JScrollPane provides a scrollable view of a component. " +

"When screen real estate is limited, use a scroll pane to " +

"display a component that is large or one whose size can " +

"change dynamically. Other containers used to save screen " +

"space include split panes and tabbed panes. <br>" +

"A JScrollPane provides a scrollable view of a component. " +

"When screen real estate is limited, use a scroll pane to " +

"display a component that is large or one whose size can " +

"change dynamically. Other containers used to save screen " +

"space include split panes and tabbed panes. <br>" +

"grows dynamically as text is appended to it: END OF BLOCK</body></html>");

p.setEditable(false);

this.setBorder(BorderFactory.createEtchedBorder());

this.setLayout(new BorderLayout());

this.add(p, BorderLayout.CENTER);

}

public Dimension getPreferredSize() {

int width=new Double(mainScroller.getViewport().getSize().getWidth()).intValue();

p.setSize(width,Integer.MAX_VALUE);

int height=p.getPreferredSize().height;

return new Dimension(width, height);

}

}

}

Try it and add just one or more TextBlocks and remove then. If the last one is removed, validate does not paint the empty panel..... If I iconified the frame and then deinconify it, it is painted correctly. So what about that? I have also tried invalidate and validateTree. I do not know the differende but it does not work either.....

Annette[/nobr]

Annette at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 7

I worked a little bit on that and I found this Topic (http://forum.java.sun.com/thread.jspa?threadID=5114605) and at its end the hint of Mr. Hellbinder that BorderLayout has some validate problems. So I tried it and with another layout-Manager I do not have the problem with the empty panel not being painted correctly. So I added this method

private void clearMainPanel() {

this.getContentPane().remove(this.mainPanel);

this.getContentPane().add(this.mainPanel, BorderLayout.CENTER);

validate();

}

which is called like that

if (mainPanel.getComponentCount() == 0) clearMainPanel();

So this works but is not really elegant and I am a bit worried if I will not have other problems with the BoderLayout and its validation......... So does anyone know anything about this problem? Or I will try and search the Forum.... Later, when we are back from walking the dog and going to the playground.....

Bye-Bye!

Annette

Annette at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 8
See your other thread. BorderLayout is fine, your code is not ;o)
itchyscratchy at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 9
Sorry, posted something else which may not have been relevant ;o)Message was edited by: itchyscratchy
itchyscratchy at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 10
I searched the Forum before going out (thought I would be more comfortable to do this first) and found that it is really easy:mainPanel.validate();mainPanel.repaint();cheers and see you!Annette
Annette at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 11
As pointed out half an hour previously on your other thread.
itchyscratchy at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...
# 12
> mainPanel.validate();> mainPanel.repaint();In Swing you should be using jcomponent.revalidate();// jcomponent.repaint(); // sometimes this is also required
camickr at 2007-7-7 14:56:41 > top of Java-index,Archived Forums,Socket Programming...