Unable to Install DocumentListener On JTextArea_py5

I’m unable to connect a DocumentListener to a JTextArea Swing component using the following source code (error message is below that). I should be able to see console print() output as text is entered into the textArea but this does not happen. I’m running this code in the Thonny editor. For some reason it does not like the parameter that I’m using for .addDocumentListener(xxxx) and I’ve tried everything I can think of but nothing seems to work. Any insight would be greatly appreciated. Thanks.

import py5

from java.awt import *
from javax.swing import *
from javax.swing.event import DocumentListener
from javax.swing.text import AbstractDocument
from javax.swing.text import PlainDocument

_wndW = 400
_wndH = 400

class DocumentListener:
    
    def __init__(self):
        print("init called.")
        
    def changedUpdate(event):
        print("changed update")

    def removeUpdate(event):
        print("remove update")
    
    def insertUpdate(event):
        print("insert update")
    
def setup():
    global frame
    global txtArea
    global myListener
    
    py5.get_surface().set_visible(False)
    frame = JFrame('Add Additional Lines of Code')
    frame.setBounds(100, 100, _wndW, _wndH)
    frame.setLayout(None)
    txtArea = JTextArea("Jeremiah was a bullfrog.")
    txtArea.setBounds(10, 10, _wndW - 20, 300)
    frame.add(txtArea)
    frame.setVisible(True)
    print("Document =",txtArea.getDocument())
    myListener = DocumentListener()
    print("myListener =",myListener)
#   This causes error message
    txtArea.getDocument().addDocumentListener(myListener)

py5.run_sketch()

Error message:

    39       print("Document =",txtArea.getDocument())
    40       myListener = DocumentListener()
    41       print("myListener =",myListener)
    42   #   This causes error message
--> 43       txtArea.getDocument().addDocumentListener(myListener)
    ..................................................
     txtArea.getDocument = <method 'javax.swing.text.JTextComponent.getDocument' of jav
                            ax.swing.JTextArea[,10,10,380x300,layout=javax.swing.plaf.ba
                            sic.BasicTextUI$UpdateHandler,alignmentX=0.0,alignmentY=0.0,
                            border=javax.swing.plaf.basic.BasicBorders$MarginBorder@4da8
                            a7d0,flags=296,maximumSize=,minimumSize=,preferredSize=,care
                            tColor=javax.swing.plaf.ColorUIResource[r=0,g=0,b=0],disable
                            dTextColor=javax.swing.plaf.ColorUIResource[r=128,g=128,b=12
                            8],editable=true,margin=javax.swing.plaf.InsetsUIResource[to
                            p=0,left=0,bottom=0,...
     myListener = <__main__.DocumentListener object at 0x1587a56c0>
    ..................................................

TypeError: No matching overloads found for javax.swing.text.AbstractDocument.addDocumentListener(DocumentListener), options are:
	public void javax.swing.text.AbstractDocument.addDocumentListener(javax.swing.event.DocumentListener)


I didn’t run your code, but I’ve immediately remembered I had read this topic about turning Python classes into Java proxies via @decorators:

https://JPype.ReadTheDocs.io/en/latest/userguide.html#proxy-method-overloading

1 Like

I’ve also tried it on the EventDispatchThread for Swing, with and without py5, and that gives an EventQueue error. Without py5 shown below.

import jpype
import jpype.imports

jpype.startJVM()

import java
import javax
import platform
from java.awt import *
from javax.swing import *
from javax.swing.event import DocumentListener
from javax.swing.text import AbstractDocument
from javax.swing.text import PlainDocument

if(platform.system() == "Darwin"):
    from Cocoa import NSApp

_wndW = 400
_wndH = 400

class DocumentListener:
    
    def __init__(self):
        print("init called.")
        
    def changedUpdate(event):
        print("changed update")

    def removeUpdate(event):
        print("remove update")
    
    def insertUpdate(event):
        print("insert update")

def buildWnd():
    global txtArea
    global myListener
    global frame
    
    frame = JFrame()
    frame.setLayout(None)
    frame.setBounds(100,100,400,400)
    txtArea = JTextArea("Jeremiah was a bullfrog.")
    txtArea.setBounds(10, 10, _wndW - 20, 300)
    frame.add(txtArea)
    txtArea.repaint()
    print("Document =",txtArea.getDocument())
    myListener = DocumentListener()
    print("myListener =",myListener)
#   This causes error message and doesn't work
    txtArea.getDocument().addDocumentListener(myListener)
#   txtArea.getDocument().addDocumentListener(javax.swing.event.DocumentListener)
    frame.setVisible(True)
   
# EDT causes EventQueue error
javax.swing.SwingUtilities.invokeLater(buildWnd)
print(platform.system())
if(platform.system() == "Darwin"):    
    NSApp.run()

Error message:

Exception in thread "AWT-EventQueue-0" org.jpype.PyExceptionProxy
	at org.jpype.JPypeContext.createException(Unknown Source)
	at org.jpype.proxy.JPypeProxy.hostInvoke(Native Method)
	at org.jpype.proxy.JPypeProxy.invoke(Unknown Source)
	at jdk.proxy2/jdk.proxy2.$Proxy9.run(Unknown Source)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Addendum:

The following changes help, and allows it to start without error… until an attempt is made to enter text and then it allows only one character with a slew of errors. Still no console print() output.

@jpype.JImplements(DocumentListener)
class MyDocumentListener:
    @jpype.JOverride
    def __init__(self):
        print("init called.")
    @jpype.JOverride        
    def changedUpdate(event):
        print("changed update")
    @jpype.JOverride 
    def removeUpdate(event):
        print("remove update")
    @jpype.JOverride    
    def insertUpdate(event):
        print("insert update")

Hi @svan ! I don’t have much to add here but I would like to introduce you to vsquared who is posting on github and is doing interesting work with Java GUI components + py5.

The two of you might be able to help each other out here.

Good luck with your explorations!

1 Like