Java 跟踪 JTextArea 中的插入符号

现在很多人都在制作自己的小文本编辑器。当您进入 Java 这样的语言时,这是一个很棒的小项目。虽然它们的名字并不完全是原创的,但像“nText”和“pText”、“zText”和“wtfText”。通常,他们的主要重点是突出显示或尝试模仿某些出色的文本编辑器(如 Notepad++ 或 TextPad)的功能。您可能想要做同样的事情,您可能想要的这些功能之一是漂亮的状态栏,显示用户所在的行和列。那么谁会告诉你这样的事情?!?!如果你说Martyr2,你绝对是一个前途光明的人。我们在“地下编程”中介绍了该主题!

如果您知道发生了什么以及您需要什么工具,那么跟踪插入符号(出现在 JTextField 等控件中的小光标)是一个非常简单的过程。由于插入符号的位置更改将是一个事件(由用户触发的事件),因此我们需要一个侦听器。有道理吧?用户触发一个事件,我们的程序会监听它并做出反应。

我们将需要的侦听器称为“caretListener”。通过将此侦听器添加到我们的 JTextField(或任何 JTextComponent 控件),我们可以侦听该控件中的插入符号何时更改。当它发生时,我们会进行一些计算以找出它位于控件的哪一行以及哪一列。与大多数侦听器一样,程序员必须在侦听器中声明一个特定的方法,然后为该方法编写代码。对于 caretListener,我们感兴趣的方法是 caretUpdate() 方法。此方法传递一个 CaretEvent 对象,该对象表示有关事件的数据(如事件源)。使用源,我们会找到插入符号的位置,它的行号,然后计算是列。

CaretListener 是一个 Javax.Swing 事件,而不是典型的 java.awt 事件。所以你需要导入javax.swing.event.*; 打包到您的代码中。在那里我们可以使用 JTextArea 的“addCaretListener()”方法将侦听器附加到它。我在下面的完整演示中向您展示了它是如何工作的。我添加了代码注释,以向您展示流程的每个步骤中发生了什么。请特别注意我们在哪里声明侦听器以及如何将它放在 addCaretListener 方法调用中。这个过程被称为匿名类,因为我们从不为类分配名称,我们只是将它声明为方法调用内联。

import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.event.*;

public class caretDemo extends JFrame {
	// Two controls, one is the editor and the other is our little status bar at the
	// bottom.
	// When we update the editor, the change in caret will update the status text
	// field.
	private JTextArea editor;
	private JTextField status;

	// Start of our caretDemo class
	public caretDemo() {
		setTitle("Caret Demo");
		setSize(500, 500);

		// Lets create a border layout to make positioning of items easy and quick.
		setLayout(new BorderLayout());
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		editor = new JTextArea();

		// Add a caretListener to the editor. This is an anonymous class because it is
		// inline and has no specific name.
		editor.addCaretListener(new CaretListener() {
			// Each time the caret is moved, it will trigger the listener and its method
			// caretUpdate.
			// It will then pass the event to the update method including the source of the
			// event (which is our textarea control)
			public void caretUpdate(CaretEvent e) {
				JTextArea editArea = (JTextArea) e.getSource();

				// Lets start with some default values for the line and column.
				int linenum = 1;
				int columnnum = 1;

				// We create a try catch to catch any exceptions. We will simply ignore such an
				// error for our demonstration.
				try {
					// First we find the position of the caret. This is the number of where the
					// caret is in relation to the start of the JTextArea
					// in the upper left corner. We use this position to find offset values (eg what
					// line we are on for the given position as well as
					// what position that line starts on.
					int caretpos = editArea.getCaretPosition();
					linenum = editArea.getLineOfOffset(caretpos);

					// We subtract the offset of where our line starts from the overall caret
					// position.
					// So lets say that we are on line 5 and that line starts at caret position 100,
					// if our caret position is currently 106
					// we know that we must be on column 6 of line 5.
					columnnum = caretpos - editArea.getLineStartOffset(linenum);

					// We have to add one here because line numbers start at 0 for getLineOfOffset
					// and we want it to start at 1 for display.
					linenum += 1;
                    columnnum += 1;
				} catch (Exception ex) {
				}

				// Once we know the position of the line and the column, pass it to a helper
				// function for updating the status bar.
				updateStatus(linenum, columnnum);
			}
		});

		// Add the fields to the layout, the editor in the middle and the status at the
		// bottom.
		add(editor, BorderLayout.CENTER);

		status = new JTextField();
		add(status, BorderLayout.SOUTH);

		// Give the status update value
		updateStatus(1, 1);
	}

	// This helper function updates the status bar with the line number and column
	// number.
	private void updateStatus(int linenumber, int columnnumber) {
		status.setText("Line: " + linenumber + " Column: " + columnnumber);
	}

	// Entry point to the program. It kicks off by creating an instance of our class
	// and making it visible.
	public static void main(String args[]) {
		caretDemo caretDemoApp = new caretDemo();
		caretDemoApp.setVisible(true);
	}
}
 

在上面的代码中,我们启动应用程序并创建一个标准的 500 x 500 JFrame。在 JFrame 中,我们创建了两个控件并将它们放在一个 BorderLayout 中,称它们为“编辑器”和“状态”。如果您不熟悉布局管理器,可以在 [url=”http://java.sun.com/docs/books/tutorial/uiswing/layout/using.html”]Using Layout Managers (The Java Tutorials ) 网址]。“编辑器”是一个 JTextArea 控件,位于中心区域。我们称为“状态”的状态栏位于底部(南部区域)。

但是在将控件添加到布局之前,我们将 caretListener 附加到编辑器控件并实现 caretUpdate() 方法。这就是魔法发生的地方。当插入符号四处移动时,我们会得到它相对于编辑器左上角的位置。这个返回的整数是正数,并且我们在控件中写入的越多,它就会不断向上攀升。我们也用它来计算偏移量。将偏移量视为插入符号的标记位置。第一个计算是在给定插入符号的当前位置的情况下确定我们在哪一行。它将返回一个整数(从零开始)来指示该行。第二个计算使用该行号来确定该行开始的插入符号位置。

如果我们按 5 次 Enter 键,而不输入任何文本,那么该行的开头将是 5。我们的插入符号的整体位置也是 5。如果我要改为在第一行键入“A”然后点击按回车键五次,第 5 行的开头将是插入符号位置 6。因此,如果我们获取插入符号的当前位置 (6) 并减去第五行的开头 (6),我们将得到 0……列号。

假设我们转到第五行并键入字母“B”。我们将在插入符号的位置 7。我们将计算插入符号在第五行开头的位置,它是 6。所以我们取 7 - 6 并返回 1,我们在第五行的第 1 列。我希望那部分是有道理的。将偏移量想象为“如果插入符号在那个位置,它的值是多少?” 如果我们的插入符号在第五行的开头,它的值为 6。行的结尾也有一个偏移量。如果插入符号在第五行的末尾,它的位置会是什么?因为我们打了一个字母,所以是 7。即使插入符号本身在该行的其他地方。

caretListener 将成为更新状态行的关键,将行号和列号传递给它。侦听器还将在各种其他任务中发挥作用,包括跟踪选择了多少字符等。请记住,此事件将获得高流量使用,因为每次光标更改时都会触发它。出于这个原因,建议您保持计算简短和快速。我不建议创建大型对象或复杂的计算,否则当您只是尝试在该字段中键入时,您将开始体验缓慢的行为。

现在您已经装备了 caretListener 并准备好在这些小文本编辑器程序上进行战斗。随意使用上面的代码,将其分开,将其撕成碎片或出于您的一般目的。我把它扔到公共领域(就像我在这个博客上的所有代码一样)。

享受并感谢您的阅读! 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值