How to set the line spacing in a JtextPane? - java

First of all, i set the JTextPane like this:
HTMLEditorKit editorKit = new HTMLEditorKit();
HTMLDocument document = (HTMLDocument) editorKit.createDefaultDocument();
JTextPane textPane = new JTextPane();
textPane.setContentType("text/html");
textPane.setDocument(document);
and i want to set the line spacing in the JtextPane , this is my idea,but it can't work:
SimpleAttributeSet aSet = new SimpleAttributeSet();
StyleConstants.setLineSpacing(aSet, 50);
textPane.setParagraphAttributes(aSet, false);
i was wrong?

When you call textPane.setParagraphAttributes(aSet, false);
it tries to apply line spacing to selection but nothing is selected
Call it another way
document.setParagraphAttributes(0, document.getLength(), attr, replace);

To style JTextPane you could use Stylesheets: Look for HtmlEditorKit#setStyleSheet
StyleSheet sh = editorKit.getStyleSheet();
sh.addRule("body {line-height: 50px}");

I was struggling with this problem and then in the API of the method public void setParagraphAttributes(AttributeSet attr, boolean replace), I found this:
If there is a selection, the attributes are applied to the paragraphs that intersect the selection. If there is no selection, the attributes are applied to the paragraph at the current caret position.
So the approach of OP will work, but you must apply textPane.selectAll() before setting the line spacing. You only have to do it once, and all the text appended to this JTextPane will have the same line space, even though you may have no text in the pane when you set the line spacing. I do it when it's instantiated.
Thus the code working for me is:
/**
* Select all the text of a <code>JTextPane</code> first and then set the line spacing.
* #param the <code>JTextPane</code> to apply the change
* #param factor the factor of line spacing. For example, <code>1.0f</code>.
* #param replace whether the new <code>AttributeSet</code> should replace the old set. If set to <code>false</code>, will merge with the old one.
*/
private void changeLineSpacing(JTextPane pane, float factor, boolean replace) {
pane.selectAll();
MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes());
StyleConstants.setLineSpacing(set, factor);
txtAtributosImpresora.setParagraphAttributes(set, replace);
}
Note: it will replace the current line spacing with factor*(line height of text), not factor * original line spacing. Strange enough.
If the JTextPane is in a JScrollPane and the length of text is too long, it will scroll to the very bottom. Usually we want to see the top part. To reset the position of the scroll, at last you can add:
pane.setCaretPosition(0); //scroll to the top at last.
P.S.: To set the paragraph margin, we have:
textPane.setMargin(new Insets(10, 5, 10, 5)); //top, left, bottom, right

Related

Java - getting/setting line height of JTextPane with content type "text/html"

I have a JTextPane with content type "text/html". It is integrated in a JScrollPane.
The user can scroll down in this JTextPane and hits a button. At this moment I want to compute the topmost actual visible line of the JTextPane!
What I found in another post here where these lines:
public Integer getActualDisplayedRows() {
int y1 = jtextpane.getVisibleRect().y;
int lineHeight = jtextpane.getFontMetrics(jtextpane.getFont()).getHeight();
int topMostRow = (int) Math.ceil((double) y1 / lineHeight);
return topMostRow;
}
But this does not compute correct.. The number in lineHeight is too small. So, if I scroll to the 20th row -for example- the method returns more then 20..
I tried to set the height of the line via stylesheet (like here):
StyleSheet sh = editorKit.getStyleSheet();
sh.addRule("body {line-height: 50px}");
But doesn't matter what pixel number I set there, the resulting JTextPane has always the same height (and I am using the body tag)..
Do you have any suggestions??
Thank you very much for your help!
If I understand your requirement you just want to know the line number at the top of the viewport?
Here is some code for getting the line at the caret position:
public static int getLineAtCaret(JTextComponent component)
{
int caretPosition = component.getCaretPosition();
Element root = component.getDocument().getDefaultRootElement();
return root.getElementIndex( caretPosition ) + 1;
}
Don't know if this will work for HTML with all kinds of weird tags with images and tables etc. In this case I'm not sure what the meaning of "line" would be.
Now obviously the caret will not be at the top of the viewport, so you need to modify the logic to get an "offset" of the text at the top of the viewport.
So you should be able to use the viewToModel(...) method of the text pane. Something like:
int y = textPane.getVisibleRect().y;
Point p = new Point(5, y);
int offset = textPane.viewToModel( p );

Java JTextPane changes line height when UTF8 character is added

I am using Java JDK 1.6 and have a problem using JTextPane to show text with a monospaced font. As soon as I add a UTF8-character like 😂, the line height in the textpane is reduced (for all the text already in the pane and also all text added later). How can I avoid this? I would like to have the normal line height.
Here is some sample code:
class AttributedTextPane extends JTextPane
{
private DefaultStyledDocument defaultStyledDocument;
protected AttributedTextPane()
{
this.defaultStyledDocument = new DefaultStyledDocument();
this.setDocument(defaultStyledDocument);
this.setContentType("text/plain");
...
}
}
...
This pane is integrated into an JInternalFrame. Creating the panel and setting the desired monospaced font:
Font font = new Font("DejaVu Sans Mono", Font.PLAIN, 11);
AttributedTextPane pane = new AttributedTextPane();
pane.setFont(font);
To display the desired text, I call pane.setText(...); As soon as I add the UTF8 character, the line height changes, see screenshot at http://i.imgur.com/Fq7XBJB.png. Is there a way to avoid that the line height is changed?
Thanks, Deejay
You could try setting/forcing a line height like so:
MutableAttributeSet jTextPaneSet = new SimpleAttributeSet(pane.getParagraphAttributes());
StyleConstants.setLineSpacing(jTextPaneSet, 1.5f); //replace float 1.5f with your desired line spacing/height
Source:
http://docs.oracle.com/javase/8/docs/api/javax/swing/JTextPane.html#setParagraphAttributes(javax.swing.text.AttributeSet,%20boolean)
https://docs.oracle.com/javase/7/docs/api/javax/swing/text/StyleConstants.html#setLineSpacing(javax.swing.text.MutableAttributeSet,%20float)
Old question but I have been struggling with it for some time, though with a JTextArea. The solution is to have either a VM param -Di18n=true or put the i18n property in the document.
My test code:
import javax.swing.JTextArea;
public class Test {
public static void main(String[] argv) {
JTextArea ta = new JTextArea();
//ta.getDocument().putProperty("i18n", Boolean.TRUE);
ta.setText("A");
System.out.println(ta.getPreferredSize()); // - height 16 without i18n and using default font, 15 with i18n
ta.setText("\ud8ff\udc05"); // surrogate pair
System.out.println(ta.getPreferredSize()); // - height 15
ta.setText("A");
System.out.println(ta.getPreferredSize()); // - height 15
}
}
When i18n is not enabled and the document is appended, the elements that are created are PlainView/WrappedPlainView that return the height based on the FontMetrics height.
When i18n is enabled the elements are PlainParagraph that contain GlyphView that calculates the height differently.
When i18n is not enabled and the document is appended with a surrogate pair then due to SwingUtilities2.isComplexLayout returning true, the i18n property is automatically set to true for the document and then all elements are created as PlainParagraph containing GlyphView that return the different (always smaller?) height.

How to change the color of text between two positions?

I want to change the color of my text for my Swing app (JTextPane) from two points, when highlighted. If the user highlights a phrase from, say, index 4 to 9, then only those characters will change their colors, permanently. I say permanently because I already know there is a setSelectionColor() option, but that is only temporary. I have managed to get the starting and ending points of the highlighted text, but I've reached a dead end.
Here is what I have so far:
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet attributes = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, color);
if(tp.getSelectedText() != null){//tp is a jtextpane. text is highlighted. change highlighted text color
int start = tp.getSelectionStart();
int end = tp.getSelectionEnd();
//update the color of the text within start and end
}
tp.setCharacterAttributes(attributes, false);//update the color for the new text
I have managed to get the starting and ending points of the highlighted text,
You can set the attributes of the text with something like:
// Define a keyword attribute
SimpleAttributeSet keyWord = new SimpleAttributeSet();
StyleConstants.setForeground(keyWord, Color.RED);
StyleConstants.setBackground(keyWord, Color.YELLOW);
StyleConstants.setUnderline(keyWord, Boolean.TRUE );
StyleConstants.setBold(keyWord, true);
// Change attributes on some text
StyledDocument doc = textPane.getStyledDocument();
doc.setCharacterAttributes(start, end - start, keyWord, false);
You can also use a StyledEditorKit Action to stylize text (bold, italic, color...). Read the section from the Swing tutorial on Text Component Features for more information and working examples.

Libgdx Label multiline text height

i have done a small test on LibGdx, on Multi-line Label, it seems that i cant get the wrapped line's height. Following is the code. Theoretically, height for aLebel should be > bLabel. But the result appear the same.
code:
aLabel.setText("this is a super long long long text that need wrapping."); // line wrapped into 3 lines
aLabel.setWrap(true);
aLabel.setWidth(470);
doLog("aLabel.getHeight(): " + aLabel.getHeight());
bLabel.setText("this is short."); // unwrapped line
bLabel.setWrap(true);
bLabel.setWidth(470);
doLog("bLabel.getHeight(): " + bLabel.getHeight());
result:
aLabel.getHeight(): 45.0
bLabel.getHeight(): 45.0
Do anyone have any idea how to get the actual multi-line height in LibGdx? Thanks in advance.
I had this issue for years and accidentally solved it by setting the width and packing the label twice. Note that multiline labels were never intended to figure out their own width, so you have to set them externally, preferably from it's parent.
public Label createLabel() {
// Create label and set wrap
Label label = new Label("Some long string here...", skin);
label.setWrap(true);
// Pack label
label.pack(); // This might not be necessary, unless you're changing other attributes such as font scale.
// Manual sizing
label.setWidth(textWidth); // Set the width directly
label.pack(); // Label calculates it's height here, but resets width to 0 (bug?)
label.setWidth(textWidth); // Set width again
return label;
}
LibGDX version used: 1.6.4
Pack sizes the widget to its pref size, nothing more. Pref width of a label with wrapping is 0.
Label label = new Label(...);
label.setWrap(true);
label.setWidth(123);
label.setHeight(label.getPrefHeight());
I had the same issue and it seems there doesn't exist a method in Label class to solve this. Also, I agree with you, the getHeight() method should return the real height of the Actor, so I don't know if that's a bug or there is a reasoning behind that behaviour.
Anyways, how I solved the issue is by using BitmapFont's getWrappedBounds method. It's not short, but for your example it would be the following:
doLog("aLabel.getHeight(): " + aLabel.getStyle().font.getWrappedBounds(aLabel.getText(), aLabel.getWidth()).height);
This could be done by adding a restriction to the cell that contains the Label in the Table:
Label label = new Label("Example", new Label.LabelStyle(font, Color.WHITE));
label.setWrap(true);
Table table = new Table();
table.add(label).width(WITH);
For more information about how to use Table go to: https://github.com/libgdx/libgdx/wiki/Table

Text widget with self-adjusting height based on interactively entered text?

Using SWT and Java, I have a Text widget defined which is set for multi-line and wrap properties. I added a listener which will monitor any changes to the text inside this text widget, and I want the height of the widget to automatically change if the user adds a new line of text, or if the text wraps around to the next line. So, I want all of the text visible in the text widget if the user adds new text, or deletes text. Here's a sample of what I'm trying to do:
mTextValue = new Text(compositeEditor, SWT.BORDER | SWT.WRAP | SWT.MULTI);
mTextValue.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
mTextValue.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
mTextValue.addListener(SWT.Modify,new Listener()
{
protected int lines=1;
public void handleEvent(Event e)
{
Text text = (Text) e.widget;
int newlines = text.getLineCount();
if (newlines!=lines)
{
lines=newlines;
height = lines*16;
width = 240;
text.setSize(width,height);
text.getShell().pack(true);
}
}
});
Now, this seems to work ok if I add a single line of text and press the return key to add the next line. The text widget grows in height when I add lines of text, and shrinks in height when I remove lines. Just as I want. But, when I have text that wraps around and I try to add a new line, the text widget is resized in width also. I want to keep the width fixed, and only self adjust the height.
Can anyone offer a suggestion to how I can have the text widget self adjust its height to fit all of the entered text, but keep the width of the text widget always fixed at a prescribed value?
Thanks.
It may be because pack() re-computes the preferred size. I don't see any direct way to set the prefered width to constant. But you may try overriding computeSize method so that you pass fixed width as hint to super class.
i.e
public Point computeSize(int wHint,
int hHint,
boolean changed)
{
return super.computeSize(240, hHint, changed);
}

Categories

Resources