File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Swing / AWT / SWT and the fly likes Displaying line # with JTextArea Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "Displaying line # with JTextArea" Watch "Displaying line # with JTextArea" New topic
Author

Displaying line # with JTextArea

James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

I have a textarea and I am wanting to display what line and column that caret is on. Its like a notepad program. I implemented a keylistener and have the following code. oh yea textInput is the textArea that is being listened to and infoArea2 and 3 are where the numbers are being displayed.



Visit my blog! http://jameshambrick.com
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
You didn't ask anything so, presuming you're looking for general comments, let me say that I think you'd be better off with a CaretListener rather than a KeyListener. That way when the user holds down a letter key (or the backspace key) the fields will be updated as the auto-repeat occurs instead of just once afterwards.

Also, getLineCount() returns the number of lines in the entire document, not which line the caret is on. And getCaretPosition() returns the character offset from the beginning of the document, not from the beginning of the current line.


bitguru blog
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

This code not work correctly. It does not display the line number that the caret it on or the column number. It just displays the caret position. I need to show those two things.
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
Originally posted by James Hambrick:
[QB]I am wanting to display what line and column that caret is on.


James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

CaretListener caretListener = new CaretListener() {

I get an error on this line here saying "Cannot find symbol" do I have to import anything? I saw somewhere I had to have a class implement CaretListener(but CaretListener is not available to be implemented)

I tried to follow through an example and did not figure out what I was doing wrong. Mainly because the class was called CaretListener the listener was called CaretListener and the method was called CaretListener and then interface was called CaretListener, the textbox was also called CaretListener I believe so that makes it hard to figure out whats what.

I have this code where textInput is the texArea that I want to apply CaretListener to

textInput.addCaretListener(caretListener);
[ November 19, 2007: Message edited by: James Hambrick ]
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

had to
import javax.swing.text.*;
import javax.swing.event.*;

now I have to incorporate word wrap into it. Once I space past 66 it drops down the next line but the column counter does not reset back to 1.

But if I enter down it resets back to 1. Need to get that working and Im done.
and when the column number is greater than 66 and the caret drops down I need to add one to the line counter.
[ November 19, 2007: Message edited by: James Hambrick ]
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
[James Hambrick:]   now I have to incorporate word wrap into it.

Incorporate word wrap into what, and do you actually have to, meaning is this a design constraint brought in to your design ideas by the use of CaretListener or some other pacakge import ? Or is this an evolution brought on by advancement in your efforts (?) all that is needed is to call setLineWrap(true);// Sets the line-wrapping policy of the text area.

[James Hambrick:]   Once I space past 66 it drops down the next line but the column counter does not reset back to 1.

What is it, as in what drops down and is the position indicator on the screen going to column one: int getDot() in javax.swing.event.CaretEvent fetches the location of the caret, but is not in javax.swing.text.JTextComponent nor javax.swing.JTextArea so (Brian Cole's) cast JTextComponent comp = (JTextComponent)ce.getSource(); may be losing some information that is needed for CaretEvent ( emphasize may - I am working on about the same level in my user-interface and do not know all of this )

The only JTextArea implementing CaretListener is javax.swing.JTextArea.AccessibleJTextArea so (Brian Cole's posted code) may losing some needed information in the cast. I do not know how peering works so this may be peering which is commonly used. To capture the caret position during word wrap after calling setLineWrap(true);// may be difficult to implement because CaretListener has only one method, it has no corresponding adapter class. Do you know how to implement caretUpdate(CaretEvent) in your class ? See the register listener discussion at General Information about Writing Event Listeners and implement caretUpdate(CaretEvent) then work your way through to:

at Text Component Features

If that fails, try ScrollPane and leave word-wrapping off, at least that keeps the view and the doc available for calling various getPosition()

[James Hambrick:]   But if I enter down it resets back to 1.

You have to reset your position values in the program directly in the interface listener methods, then set the values in the view from the updated varables in the data model. Using chained assignment operators is handy for this, but should not be overused.

[James Hambrick:]   I have this code where textInput is the texArea that I want to apply CaretListener to textInput.addCaretListener(caretListener);

See warining:
Note: The caretUpdate method is not guaranteed to be called in the event-dispatching thread. To use any methods inside of caretUpdate that update the GUI special handling is required to ensure they are executed on the event-dispatching thread. You can do this by wrapping the code inside a Runnable and calling SwingUtilities.invokeLater on that Runnable.


in the documentation on CaretListener
[ November 20, 2007: Message edited by: Nicholas Jordan ]

"The differential equations that describe dynamic interactions of power generators are similar to that of the gravitational interplay among celestial bodies, which is chaotic in nature."
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

all I know is that after hitting the spacebar 65 or 66 times the cursor jumps down to the next line.
the column count does not reset back to 1
and the line number does not increment by 1.

I used the term wordwrap because I figure that is what is setup for the cursor to jump down like that. This is a notepad like program so word wrap would have to be on. Your last post is hard to understand with my knoledge of java. I will have to research somethings before I can see what you are talking about. You are talking way over my head.
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
Originally posted by Nicholas Jordan:
The only JTextArea implementing CaretListener is javax.swing.JTextArea.AccessibleJTextArea so (Brian Cole's posted code) may losing some needed information in the cast.


No information is lost in the cast, whatever that means. And I don't see how the existence of any JTextAreas that happen to implement CaretListener is at all relevant.

If you don't like obtaining the text area from ce.getSource() then feel free to refer to it from a variable. If the caret listener is only added to one text component then it's exactly the same. If it's added to more than one then ce.getSource() will work slightly better (though it is still referring to lineField and colField directly).

[edit: pesky subject/verb agreement issues]
[ November 20, 2007: Message edited by: Brian Cole ]
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
[Brian Cole:]   No information is lost in the cast, whatever that means. And I don't see how the existence of any JTextAreas that happen to implement CaretListener is at all relevant.

What I had in mind (note I am working at the limit of my skills trying to help the poster) is that I do not see any getCaretPosition() or getCursorPosition() on class javax.swing.JComponent ... so to me that means where is the call getDot() coming from, and basically ditto your next point.

Let me put my frame of mind this way: " I have to see the code or I don't believe it. " and without intending to get a heavy computer science discussion underway, some code somewhere has to implement CaretListener. If not, please tell me where to look to see how this works.

It has to exist somewhere, it looks to me like it was done by peering, which is the frame of mind in which I posed my replies. {iow do not comprehend peering }

[Brian Cole:]   If you don't like obtaining the text area from ce.getSource() then feel free to refer to it from a variable. If the caret listener is only added to one text component then it's exactly the same. If it's added to more than one then ce.getSource() will work slightly better (though it is still referring to lineField and colField directly).

My point was TextArea does not implement CaretListener, so where is the int pos = comp.getCaretPosition(); getting the int from if it is no longer a Caret ? I believe it is this line:   Rectangle caretCoords = textPane.modelToView(dot);   that does what I was driving at, though I had posted the code looking for that. I just sorta knew somehow they would have put it in and it would not take long to find.

[James Hambrick :]   All I know is that after hitting the spacebar 65 or 66 times the cursor jumps down to the next line. The column count does not reset back to 1 and the line number does not increment by 1.

Yes, I undersand that it is doing something that is not what you have in mind: This work is not difficult, it is just that there is so much of it that more work gets done by osmosis than by a jump-up directed path. I find that it takes about five or ten readings of something to 'get the hang of it' and put up the things you will have to research so that I am not talking way over your head.

If you think this is bad, you should see what it is like in the stratospherics of computer science. People basically have to sign simple html 1.0 and 1.1 with high-grade cryptographic protocols to prevent people from twisting their words. Just keep coding compiling and fixing -> that's how the pro's do it.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

the code you may be talking about not seeing is

textInput.addCaretListener(caretListener);
//where I add the caretlistener to the textInput TextArea.
I also imported
import javax.swing.text.*;
import javax.swing.event.*;

not sure why I had to, but it would not compile without it. I found an example of using a caretlistener and looked at the import statements.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

Originally posted by Nicholas Jordan:
You have to reset your position values in the program directly in the interface listener methods, then set the values in the view from the updated varables in the data model. Using chained assignment operators is handy for this, but should not be overused.


There are so many steps to get the column number and line number that I am not certain how to set them back to 1.

Originally posted by Nicholas Jordan:
Note: The caretUpdate method is not guaranteed to be called in the event-dispatching thread. To use any methods inside of caretUpdate that update the GUI special handling is required to ensure they are executed on the event-dispatching thread. You can do this by wrapping the code inside a Runnable and calling SwingUtilities.invokeLater on that Runnable.


Is this a fault in Java? Why would I have to deal with multithreading to implement a caretlistener? If I have to I guess I will. Man VB was much easier than this! lol
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
[James Hambrick:]   not sure why I had to, but it would not compile without it. I found an example of using a caretlistener and looked at the import statements.

Yes, I could tell from the tone and wording of your posts: What you have here is ssometing to do with interfaces, which I just posted about and still do not undersand. Around the call to new just before execution drops into the curly braces something happens which I do not understand. It becomes deeply involved in arcane issues to try to explain what I am directing attention here ( to ).

[James Hambrick:]   There are so many steps to get the column number and line number that I am not certain how to set them back to 1.

That is revealed in your code, if you can show me how to get them - I can show you how to set them.

[James Hambrick:]   Is this a fault in Java? Why would I have to deal with multithreading to implement a caretlistener? If I have to I guess I will. Man VB was much easier than this! lol

The code that puts up a viewable window on the screen launches one or two threads that it does not tell you about, the discussion of why becomes overly complex and should be reserved to advanced fora. I will not get into it here.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

I am looking at the code, looking up what each line does and do not understand what this line of code does.
Element root = comp.getDocument().getDefaultRootElement();

The code you are wanting to see if what was gave to me earlier, I have not edited it yet. Once I understand the code I can then try and edit it.

actually I dont understand any of this code here


[ November 20, 2007: Message edited by: James Hambrick ]
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
Originally posted by Nicholas Jordan:
[Brian Cole:]   No information is lost in the cast, whatever that means. And I don't see how the existence of any JTextAreas that happen to implement CaretListener is at all relevant.

What I had in mind (note I am working at the limit of my skills trying to help the poster) is that I do not see any getCaretPosition() or getCursorPosition() on class javax.swing.JComponent


getCaretPosition() is defined in javax.swing.text.JTextComponent. JTextArea inherits it from there.

Don't confuse Cursor with Caret. Cursors don't have anything to do with this topic.

... so to me that means where is the call getDot() coming from, and basically ditto your next point.

Let me put my frame of mind this way: " I have to see the code or I don't believe it. " and without intending to get a heavy computer science discussion underway, some code somewhere has to implement CaretListener.


I think you must be confused about CaretListener. It's an interface that a coder can implement to be notified of caret events. Now there are undoubtedly classes in the JDK that do implement CaretListener (such as AccessibleJTextArea as you mentioned) but this is irrelevant. It sounds to me like you are actually looking for the code that fires the caret events, not code that happens to be listening to them.

Feel free to throw around heavy computer science if you want. I can handle it, though I'm not sure how it would help with what is essentially a library API question.

My point was TextArea does not implement CaretListener, so where is the int pos = comp.getCaretPosition(); getting the int from if it is no longer a Caret ? I believe it is this line:   Rectangle caretCoords = textPane.modelToView(dot);   that does what I was driving at


You're beginning to lose me here.

Indeed, JTextArea does not implement CaretListener, but it doesn't need to. It inherits getCaretPosition() from JTextComponent. All getCaretPosition() does it call getDot() on its Caret. (A text component's default Caret is set by the LnF, but if you like you can set your own Caret via the setCaret() method.)

The modelToView() method is irrelevant here. We could use it if we needed to convert character offsets to screen positions for some reason, but how would that be helpful in determining the line/column number of the Caret position? (Actually, I guess it could be used to pinpoint where a line-wrap is happening, but it would be ugly. See below.)

[James Hambrick :]   All I know is that after hitting the spacebar 65 or 66 times the cursor jumps down to the next line. The column count does not reset back to 1 and the line number does not increment by 1.

Yes, I undersand that it is doing something that is not what you have in mind: This work is not difficult, it is just that there is so much of it that more work gets done by osmosis than by a jump-up directed path. I find that it takes about five or ten readings of something to 'get the hang of it' and put up the things you will have to research so that I am not talking way over your head.


Now you've truly lost me. I suppose it's possible that you are talking way over my head. I think it is more likely that you are fundamentally confused about how text components work in Swing and are unintentionally spreading this confusion to others in this forum.

"This work is not difficult," you say? I think I must disagree. I posted some relatively simple code that obtains line-wrap-independent line and column numbers, the way a programmer's text editor would report them. But even that code is slightly difficult, as it relies on the details of how the JTextArea's PlainDocument maintains a tree of javax.swing.text.Element objects. Most Swing programmers haven't had a need to delve into that stuff.

But to obtain line and column numbers that depend on line-wrap, as programs such as M$Word do, is significantly more difficult. One possible approach is to examine the tree of javax.swing.text.View objects created by the EditorKit's ViewFactory. Another is to replace the text component's PlainDocument with a Document that has been written to split its Elements at the line wrap boundry. A third approach is (as mentioned above) to iterate through the Document offsets calling modelToView() and examining coordinates to detect new lines, but this is inelegant and slow (probably unworkably slow for large Documents).

[edit: fix some typos]
[ November 20, 2007: Message edited by: Brian Cole ]
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
Originally posted by James Hambrick:
actually I dont understand any of this code here




Well, comp.getDocument() gets the JTextArea's Document, which by default is a PlainDocument. If you take a look at the javadoc for PlainDocument, it says "The Element returned by getDefaultRootElement is a map of the lines, and each child element represents a line."

What this means that the Nth Element corresponds to the Nth line, presuming we count from zero. Other kinds of Documents don't necessarily work this way, hence my warning about JTextPane/JEditorPane.

lineNum = root.getElementIndex(pos); This asks for the index (== the line number) of the Element corresponding to the Caret position.

colNum = pos - root.getElement(lineNum).getStartOffset(); This asks for the start position of Element (== the Caret-containing line) and subtracts it from the Caret position. The difference is the number of characters in the Document between the start of the line and the Caret.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

so all I have to do is

if(colNum =66)
//set the caret position to (lineNum +1) and colNum = 1(how so you do that???
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
[Brian Cole:]   I think you must be confused about CaretListener. It's an interface that a coder can implement to be notified of caret events. Now there are undoubtedly classes in the JDK that do implement CaretListener (such as AccessibleJTextArea as you mentioned) but this is irrelevant. It sounds to me like you are actually looking for the code that fires the caret events, not code that happens to be listening to them.

What I was trying to do is ( as gently as I could figure out ) get the poster to implement CaretListener or show me where in the app is was implemented, I did the best work I could do and I missed it even though the docs show that Class JTextComponent implements get for the caret.

Let's simplifiy for a moment and address:



Well see, int getCaretPosition() only gives you an int. That you can apply directly to an indicator on the screen, perhaps a status bar or maybe printing it to System.out as I remember from earlier in the conversation, but as you can see this int getCaretPosition() is only returning an int, not a Position(x,y); ( or some derivation there of in a a libray such as awt dot text or JStuff or wherever your base class resides.

What you need is an x,y data structure that will tell you where the caret is independent of ,.... you have to really be careful here and basically it takes a lot of digging and just keep working the issue without getting in too big a hurry. I was trying to be encouraging by saying This work is not difficult ... and am getting into a discussion with a real computer scientist. I got that quote from Ivor Horton, who specializes in beginners.

If you will notice, the code I put up has: Rectangle caretCoords = textPane.modelToView(dot); , and therein is the key to your woes. See, it has an x,y type of "what the thing is" {is a / has a from OO nomenclature} and since Brian seems to know the libraries and can handle the cs of the matter, he will very very likely know exactly where this call came from and where it is going. The letter 'x' usually means ( in java graphics ) what you are calling column position and at that point you have to dig into the libraries. Without Brian's skill you are going to be in for a real haul, this is not like VB where everything is on rubber-rails and you can just slap up some code and the compiler will try to come up with something that will work. It is a precise mindset in which one misplaced puncutaion can fail in unexpected ways.

The code I got was taken directly off of the Sun Tutorial Website for exactly the problem you are facing. The first line of the code is public void caretUpdate(CaretEvent e) , which if you wrote that line yourself and claimed implements caret listener in you declarations, then you would register ( I'll let Brian decide how you should do the next step ) then caretCoords.x would in all reasonable expectation be the x you are looking for.

You then set whatever on-screen variable is showing the colum number to caretCoords.x. You do not //set the caret position to (lineNum +1) and colNum == 1 , you GET the caret position and set your display from where the caret ( listener ) tells you the caret is.

You may need to refresh the screen, but Brian knows the libs so he will know contemporary practice on this, just do whatever is current practice.

It may be that int getCaretPosition(); will take care of all of this, but you state your problem is that the display flips on boolean word wrap so without seeing the entire code for the whole app, I have to guess. Because this is not VB, the disucssion can splay off in a foray, but as you can see -> you are getting much better help here than you were in beginner.
[ November 22, 2007: Message edited by: Nicholas Jordan ]
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

I have just finished looking at your code and your code works except for the fact that the column number increments by 6 and the line number increments by 11 but I can fix that I think lol. Should just be able to divide the column number by 6 to get the column number and the line number by 11 to get the line number.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

So after dividing by 6 and 11, adding one to each one then converting to a string it works. yah
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
[James Hambrick:]   So after dividing by 6 and 11, adding one to each one then converting to a string it works. yah

You should tell me why you have to fixup the values, if this was done just to get through homework, we don't do homework.

Fixes like that are always indicative of deeper problems.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

homework?? Im not in school! I am working on a volunteer project to get some Java experience and got stuck on something. I learn as I go.

I had to fix up the values because the 1st column was 0 then the next column number was 6 and the next was 12 and then next was yep column number 18.

The first line number was 0 the next was 11 and the next was 22 and the next was 33 and yep the next was 44. So I had to divide it out and add 1 to get the true column number and line number. the convert it to a string because infoArea2.setText() on only accepts strings not ints.
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
[James Hambrick:]   homework?? Im not in school! I am working on a volunteer project to get some Java experience and got stuck on something. I learn as I go.

Okay, I like that. I was just trying to save the moderators some typing because they seem to be dilligent about not doing people's homework. I am working not far away from where you are ( conceptually, in code development ) and found that a class that I wrote 'DataSet' was actually the same name as code that had already been written as a standard for network data transfer.

[James Hambrick:]   I had to fix up the values because the 1st column was 0 then the next column number was 6 and the next was 12 and then next was yep column number 18.

Okay, that is the critical piece of information I was trying to elicit. I would maintian a line number and a position in a line as a nested class or as instance variable(s), then do the fixups when the view called the data model. Everyone ( it seems to me ) writes the View Model, then dismisses the Data Model with a studied, aristiocratic Air Superiority Complex that would leave the Amirejibi with a moderate case of heebie-jeebies. Brian Cole will be the one to help you if you want to have the View inform the Controller where the carrot is when the bunnies come to corrall your code.

[James Hambrick:]   The first line number was 0 the next was 11 and the next was 22 and the next was 33 and yep the next was 44. So I had to divide it out and add 1 to get the true column number and line number. the convert it to a string because infoArea2.setText() on only accepts strings not ints.

This hails classic nested class or View.getColumnNumber() and fixing vals up this way should be noted in the comments as likely to be reworked later.

To make an int a string just anywhere call Integer.toString(int i) just pretty much wherever you need the conversion done to make an int displayable as a String.

Very, very handy - really often.
James Hambrick
Ranch Hand

Joined: Sep 04, 2004
Posts: 282

Originally posted by Nicholas Jordan:

Okay, that is the critical piece of information I was trying to elicit. I would maintian a line number and a position in a line as a nested class or as instance variable(s), then do the fixups when the view called the data model. Everyone ( it seems to me ) writes the View Model, then dismisses the Data Model with a studied, aristiocratic Air Superiority Complex that would leave the Amirejibi with a moderate case of heebie-jeebies. Brian Cole will be the one to help you if you want to have the View inform the Controller where the carrot is when the bunnies come to corrall your code.



Huh??? I did comment my code telling what I did but what do you mean by this? I do not understand what you are talking about. I have all my code in the caretUpadte() method.
Nicholas Jordan
Ranch Hand

Joined: Sep 17, 2006
Posts: 1282
I have all my code in the caretUpdate() method

Well, that sounds good, but in most of this OO stuff some method call like carrot Update will be part of a library somewhere. In other words caret Update is called by machine architecture and you get an int from displaySelectionInfo(e.getDot(), e.getMark()); and what it looks to me like you are doing ( the citation you show ) is doing some 'fancy footwork' or 'tabbing traversal' to get columns to implement. Because this may have been done already in the View Model or something, I do not want to get crossways with the OO crowd, but what I mean by my remark is that you are doing arithmetic ( fixups ) to get a column number from [ actually I do not know where it is coming from ] and ususlly in this OO style that has been done for you, somewhere... ? That is where Brian Cole will likely be useful for you. He will know what I am talking about an be able to advise you on whether that arithmetic is done for you somewhere in the View.

The fact that the behaviour inverts on boolean word-wrap tells me that the View may be doing the Word - Wrapping, in which case you would have to update your column indicator like this:

[ November 25, 2007: Message edited by: Nicholas Jordan ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Displaying line # with JTextArea