从现有创建自定义swing组件

Kar*_*120 4 java swing jtextarea

所以,我有这个JTexrtArea几乎完全满足我的需求.唯一不对的是线间距.我无法设置它.(为什么不使用JTextPane?因为在JTextArea中可以更改间距,而JTextArea比JTextPane更轻,我的程序中有很多这样的东西).

我之前已经问过这个问题,这是我从用户StanislavL得到的答案:


要覆盖JTextArea的行间距,请查看PlainView(用于呈现PLainDocument).

public void paint(Graphics g,Shape a)方法中有以下几行

    drawLine(line, g, x, y);
    y += fontHeight;
Run Code Online (Sandbox Code Playgroud)

因此,您可以调整渲染固定y偏移.

在BasicTextAreaUI方法中创建视图.将其替换为您自己的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;
}
Run Code Online (Sandbox Code Playgroud)

我掌握了他告诉我要做的一般想法,但我不知道该怎么做.此外,我不想覆盖默认的JTextArea"属性",我想有一个选择 - 使用默认的或使用自定义的.

只有JTextArea代码中的更改才会来自

y += fontHeight,

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

我该如何实现这一目标?我使用/复制哪些课程?我把它放在哪里?我如何使它们可用?我如何让整个工作起作用?

如果您认为这太具体而无法使用,也许有人可以编写一个关于如何在现有的基础上100%创建自定义swing组件的一般教程.然后有人可以轻松地改变一些值,以更好地调整它的需要.

Rob*_*bin 10

我只想从你的另一个问题中复制粘贴我的答案.

我想改变JTextArea行的间距

我的第一个想法是压倒一切javax.swing.JTextArea#getRowHeight就足够了.javadoc明确指出

定义行高的含义.默认为字体的高度.

所以我希望通过重写这个方法,你可以调整定义,你会在行之间获得更多的间距.糟糕,没有工作.在JDK中快速搜索该方法的用法显示了相同的内容.它主要用于计算某些大小,但在组件内部绘制文本时肯定不会使用.

通过查看javax.swing.text.PlainView#paint方法的源代码,我看到了FontMetrics所使用的,以及那些你可以轻松覆盖的方法JTextArea.所以第二种方法是扩展JTextArea(bwah,扩展Swing组件,但它是用于概念验证)

  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 );
    }
  }
Run Code Online (Sandbox Code Playgroud)

FontMetricsWrapper级基本上代表了一切,除了getHeight方法.在那个方法中,我在委托的结果中添加了10

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

这会导致更多的行间距(并且插入符太长,但可能会调整).

一个小截图来说明这一点(不如其他一些好,但它表明这种方法可能有效):

常规文本区域和扩展文本区域之间的差异

小免责声明:这感觉就像一个丑陋的黑客,可能会导致意想不到的问题.我希望有人能找到更好的解决方案.

我个人更喜欢StanislavL提出的解决方案,但这为您提供了另一种选择

  • @StanislavL它并不完美.例如,插入符号变得太大(它与修改后的文本高度一样大,远远高于实际字符).但由于他只想用一个像素增加间距,我认为这是可以接受的 (2认同)

Sta*_*avL 6

那是一段代码.它没有完成.未实现包裹线之间的行间距.您可以获得完整的源代码WrappedPlainView或在PlainView其中添加代码以实现所需的行间距

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)