Meaningless Drivel is fun!*
The moose likes Swing / AWT / SWT and the fly likes StyleAttributes not applying when called in quick succession Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "StyleAttributes not applying when called in quick succession" Watch "StyleAttributes not applying when called in quick succession" New topic
Author

StyleAttributes not applying when called in quick succession

Clive Mercer
Greenhorn

Joined: Dec 30, 2009
Posts: 10
Hi

I have encountered a problem regarding StyleAttributes in a JTextPane. I am working on a Programmer's Editor with live syntax highlighting, and I have a problem where if I put in small sections of text, the colouring is fine. However if I paste in larger chunks, the colours do not apply correctly - to me this seems to be a speed issue. Could it be the overhead of setCharacterAttributes obtaining a writelock?

To demonstrate this, I have made a SSCCE demonstrating the problem. If I paste in the word "hello" once, it colours fine. However if I keep CTRL+V pressed, some "hello"s get coloured but others do not (screenshots are attached).

Can someone please share their expertise as to why this is, and possibly how to fix it?

Thanks!

Clive

P.S: Mods - This is a followup to an older post. I wasn't sure about the rules regarding bumping old threads, so I made a new one. I hope this is not a problem.

Source:



[Thumbnail for fine.PNG]


[Thumbnail for problem.PNG]

Clive Mercer
Greenhorn

Joined: Dec 30, 2009
Posts: 10
Bump?

I'm not really expecting a solution (although that would be great), even a pointer in the right direction would be very appreciated.
I genuinely want to learn and develop as a programmer, but it is extremely difficult if I'm stuck and can't find answers anywhere.

My question is - why do StyleAttributes not get applied if called really quickly?

Regards,
Clive
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 37890
    
  22
Moving to our GUIs forum.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 37890
    
  22
Don't know. Sorry.

Try using the System#nanoTime() method before and after your calls with ctrl-V and see how long it takes for each "paste". It can take several milliseconds for the GUI to be repainted, so you might be calling a second "paste" before the repainting is finished. Particularly if you have two threads. Remember Swing is not thread-safe and you should do all Swing activity in the same thread.
Stanislav Lapitsky
Ranch Hand

Joined: Dec 01, 2009
Posts: 53
Try to call the
doc.setCharacterAttributes(MainWindow.position, MainWindow.length, aa, true);
inside SwingUtilities.invokeAndWait();

May be that will help to solve some thread dependent probem

also try to reset the length to 0 after applying the attributes once.

Regards,
Stas
Rob Camick
Ranch Hand

Joined: Jun 13, 2009
Posts: 2152
    
    7
Well, I would say the basic structure of your program is wrong. I don't think you should be having a Thread running in the background to color the text. Remember that when Threads run they each get a chunk of the CPU for a short period of time.

So whats happening is that the GUI EDT executes and does multiple inserts of the text, which updates your position/length variables each time. Then the Colouring Thread runs which can only use the current values of those variables, so it ends up skipping some text.

The better approach would be to do the colouring in the DocumentListener. The trick is to wrap the code in a SwingUtilities.invokeLater() so you don't get a ConcurrentModificationException on the Document.
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
Clive Mercer wrote:If I paste in the word "hello" once, it colours fine. However if I keep CTRL+V pressed, some "hello"s get coloured but others do not (screenshots are attached).

Can someone please share their expertise as to why this is, and possibly how to fix it?

I agree with Mr. Camick that doing the coloring in a daemon thread is a bad idea. Your
problem is that you may be setting MainWindow.position and MainWindow.length more
than once before the daemon can notice. Also your daemon is a busy loop, which is bad.

There are ways to fix this (add to a list instead of setting a single field, sleep the thread
when the list is empty, and probably use a javax.swing.text.Position instead of an int to
handle the case where subsequent edits change the starting position of the text you want
to color before the daemon can got to it) but it's better to get rid of the thread entirely.

Here's how I would handle this task:This presumes you want non-hello text typed or pasted in the middle of a red hello to be
black, instead of inheriting the red foreground. Otherwise get rid of the else clauses.
Put in place via: ((AbstractDocument yourTtextPane.getDocument()).setDocumentFilter( new RedDocumentFilter() );

Also, you will want to call setVisible(true) at the end, after the call to setSize(), not at the beginning.


bitguru blog
Clive Mercer
Greenhorn

Joined: Dec 30, 2009
Posts: 10
Thanks for your responses!

Rob Camick/Stanislav Lanitsky/Campbell Ritchie:
The project is a Code Editor with syntax highlighting - the reason I used a separate thread instead of doing the colouring from within the listener was so that a user will not have to wait for the colouring to take place whilst they work with the document. If the colouring code was placed inside the listener via SwingUtilities.invokeLater(), then every modification would force the user to wait for the program to catch up.

In the SSCCE, you are right, some values would be skipped if the updates are happening quicker than the Colourer thread can colour them. This is a fault in my SSCCE, the actual application uses a Vector to "queue" words up waiting to be coloured. However, this colouring problem is present in both applications.
This leads me to believe that I've misunderstood StyleAttributes or some aspect of concurrency which is causing the doc.setCharacterAttributes() to not be able to colour certain characters if called repeatedly in a short amount of time.

Brian Cole:
I did not know about javax.swing.text.Position, I will certainly look it up. The DocumentFilter solutions looks like a great idea, thank you for showing me this, I shall try it tonight!
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 37890
    
  22
You're welcome
Brian Cole
Author
Ranch Hand

Joined: Sep 20, 2005
Posts: 862
Clive Mercer wrote:
The project is a Code Editor with syntax highlighting - the reason I used a separate thread instead of doing the colouring from within the listener was so that a user will not have to wait for the colouring to take place whilst they work with the document.


In this case I wouldn't argue against a separate thread. (Do make sure it sleeps instead of busy-looping, though.) However it doesn't really make sense to use a DocumentFilter for this. You don't really want to color only the text the user types or pastes, since a user change in one location can cause color differences in other parts of the document.

Chapter 22 of O'Reilly's Java Swing has some simple code that may or not be helpful:
  • ParenMatcher
  • LiveParenMatcher (subclass of ParenMatcher)
  • (full disclosure: These code examples were written by yours truly. Also, did I mention they were simple?)

    I would suggest beginning with coloring the entire document when the user makes any change. If coloring from the last change hasn't completed yet, abort that and start anew. (This means the coloring thread has to keep checking if it should abort, since there's no clean way to kill a thread without its cooperation.)
    Clive Mercer
    Greenhorn

    Joined: Dec 30, 2009
    Posts: 10
    Brian, this is great stuff. The code editor is extremely simple, so things like matching parenthesis are a little beyond me (I'm a beginner!). The two samples however are very informative and I shall certainly look into them.

    If the DocumentFilter was used to do the colouring, would it still render the document unusable until it is completed, like it would be when colouring from within the DocumentListener?

    Thanks again for your input and patience
    Clive Mercer
    Greenhorn

    Joined: Dec 30, 2009
    Posts: 10
    Brian, I used your examples of ParenMatcher and LiveParenMatcher. Inside LiveParenMatcher's listener I had my parsing algorithm break down and identify individual keywords then send them to a static Vector inside a wrapper class. This vector class is tested to work correctly under concurrency.
    ParenMatcher's run() method would then busy-loop (for testing) waiting for the Vector's size to become more than zero, at which point it would enter a loop, get the keyword details and colour them.



    Unfortunately, I am back at square one. Although every single word is identified, stored and retrieved correctly, many are not coloured at all. It's almost as if setCharacterAttributes() ignores some of the calls made to it!

    Here is the code for the run() method:

    CQ is wrapper class containing the static vector, TypeDuo is the class which holds information of each word to be coloured. The println() statement verifies that every word is correctly received and sent to setCharacterAttributes(), the question is, why are some of these words ignored?

    Any and all help is very appreciated, this problem is driving me crazy!
    Brian Cole
    Author
    Ranch Hand

    Joined: Sep 20, 2005
    Posts: 862
    How are things supposed to get in to the ColourQueue? I would think it should be in the run() method before the loop, but I don't see anything there.
    Clive Mercer
    Greenhorn

    Joined: Dec 30, 2009
    Posts: 10
    The DocumentListener receives the insertUpdate() or removeUpdate() events and passes this information to another class. This class then places these words ("TypeDuo" objects) into the ColourQueue. I know that the ColourQueue is getting populated correctly and that no changes are being lost - as evidenced by the println() statement on line 9.

    Some of the words get coloured correctly, however many appear to be ignored, although they are definetly retreived from the ColourQueue.

    Could there be something blocking setCharacterAttributes() from applying the changes, such as some sort of Document lock?

    Regards,
    Clive
     
     
    subject: StyleAttributes not applying when called in quick succession
     
    Similar Threads
    Universal way to detect field changes?
    run this file
    IllegalStateException in a StyledDocument
    JTextPane --find the mystery
    How can I make command line interface (CLI)