Creating a custom swing component from existing

So, I have this JTexrtArea, which is almost perfect for my needs. The only thing that’s wrong with him is the line spacing. I can’t install it. (Why not JTextPane? Since the CAN interval can be changed in JTextArea, and JTextArea is much easier than JTextPane, and I have a group of them in my program).

I already asked about this question , and this is the answer I received from user StanislavL:


To override the JTextArea line spacing, look at PlainView (used to render PLainDocument).

The following lines exist in the public void paint method (Graphics g, Shape a)

drawLine(line, g, x, y); y += fontHeight; 

This way you can adapt the y rendering correction y.

In the BasicTextAreaUI method to create a view. Replace it with your own implementation of PlainView

 public View create(Element elem) { Document doc = elem.getDocument(); Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/); if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) { // build a view that support bidi return createI18N(elem); } else { JTextComponent c = getComponent(); if (c instanceof JTextArea) { JTextArea area = (JTextArea) c; View v; if (area.getLineWrap()) { v = new WrappedPlainView(elem, area.getWrapStyleWord()); } else { v = new PlainView(elem); } return v; } } return null; } 

I understand the general idea of ​​what he tells me to do, but I don’t know how to do it. In addition, I would not want to override the default JTextArea property, I would like to have a choice - use default or use custom.

Only a JTextArea code change would be from

y += fontHeight ,

to

y+= (fontHeight +(or -) additionalSpacing) .

How do I achieve this? What classes do I use / copy? Where do I put them? How to make them usable? How can I make it all work?

If you think this is too specific to be useful, maybe someone can write a general tutorial on how to create your own swing component based on 100% on the existing one. Then, someone could easily change some values ​​to better adapt them to the needs.

+4
source share
2 answers

I'm just going to copy-paste my answer from your other question .

I would like to change the line spacing of JTextArea

My first thought was that overriding javax.swing.JTextArea#getRowHeight would be enough. Javadoc clearly states

Defines the height value of the string. This default value corresponds to the font height.

Therefore, I hoped that by overriding this method, you would edit the definition and you would get a greater line spacing. Bammer did not work. A quick search about using this method in the JDK showed the same thing. It is mainly used to calculate some sizes, but, of course, is not used when drawing text inside a component.

Having examined the source code of the javax.swing.text.PlainView#paint method, I saw that FontMetrics used, and those that you can easily override in JTextArea . So the second approach was to extend JTextArea (bwah extending Swing components, but to prove the concept)

  private static class JTextAreaWithExtendedRowHeight extends JTextArea{ private JTextAreaWithExtendedRowHeight( int rows, int columns ) { super( rows, columns ); } @Override public FontMetrics getFontMetrics( Font font ) { FontMetrics fontMetrics = super.getFontMetrics( font ); return new FontMetricsWrapper( font, fontMetrics ); } } 

The FontMetricsWrapper class basically delegates everything except the getHeight method. In this method, I added 10 to the delegate result

 @Override public int getHeight() { //use +10 to make the difference obvious return delegate.getHeight() + 10; } 

And this leads to more spacing between lines (and a carriage too long, but this can probably be adjusted).

A small screenshot to illustrate this (not as good as some others, but it shows that this approach may work):

Difference between regular text area and extended one

A small disclaimer: this seems like an ugly hack and can lead to unexpected problems. I hope someone comes up with a better solution.

I personally prefer the solution suggested by StanislavL, but it gives you an alternative

+10
source

This is a piece of code. It is not finished. Line spacing between wrapped lines is not implemented. You can get the full source of a WrappedPlainView or PlainView and add your code there to achieve your desired line spacing

 import javax.swing.*; import javax.swing.plaf.basic.BasicTextAreaUI; import javax.swing.text.*; public class LineSpacingTextArea { public static void main(String[] args) { JTextArea ta=new JTextArea(); JFrame fr=new JFrame("Custom line spacing in JTextArea"); fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ta.setText("Line 1\nLine 2\nLong text to show how line spacing works"); ta.setLineWrap(true); ta.setWrapStyleWord(true); ta.setUI(new CustomTextAreaUI()); fr.add(new JScrollPane(ta)); fr.setSize(100,200); fr.setLocationRelativeTo(null); fr.setVisible(true); } static class CustomTextAreaUI extends BasicTextAreaUI { public View create(Element elem) { Document doc = elem.getDocument(); Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/); if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) { // build a view that support bidi return super.create(elem); } else { JTextComponent c = getComponent(); if (c instanceof JTextArea) { JTextArea area = (JTextArea) c; View v; if (area.getLineWrap()) { v = new CustomWrappedPlainView(elem, area.getWrapStyleWord()); } else { v = new PlainView(elem); } return v; } } return null; } } static class CustomWrappedPlainView extends WrappedPlainView { public CustomWrappedPlainView(Element elem, boolean wordWrap) { super(elem, wordWrap); } protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { super.layoutMajorAxis(targetSpan, axis, offsets, spans); int ls=spans[0]; for (int i=0; i<offsets.length; i++) { offsets[i]+=i*ls; } } } } 
+6
source

Source: https://habr.com/ru/post/1441138/


All Articles