Java and Swing apps

I’m experimenting with writing some Swift code to target the JVM with Swing APIs. I’m working with Fire on macOS. Bit of background: I’m an experienced Java developer (written large Swing-based apps) and iOS/macOS developer (Swift; I have reasonably successful apps on the app store).

Now, I’m trying to get the simplest of simple Swing apps up and running - a JFrame with a JLabel. First of all, the project template I’ve had the most success with is the console application, and then modifying from there. This is what I’ve come up with:

import javax.swing
import java.awt

System.out.println("The magic happens here.")
EventQueue.invokeAndWait {
	System.out.println("Hello from the event queue")
	let frame = JFrame("This is the frame title")
	let label = JLabel("This is a label")
	frame.getContentPane().setLayout(FlowLayout())
	frame.getContentPane().add(label)
	frame.pack()
	frame.setVisible(true)
}

System.`in`.read()

If I run this from within Fire, it fails to load any of the Swing-related UI classes or resources, although it does spit out the message “Hello from the event queue”. I have cooper, rt and swift as References in the project. The last line (System.in.read()) seems necessary because even though the event thread is running, when execution reaches the end of the file, the program terminates (unlike the Java language equivalent, compiled with javac).

If I run the compiled jar output from the above program, then it runs fine - I get the frame with label, as expected, with no runtime errors. However, this is quite tedious - write code in Fire, build, then switch to terminal in order to run/view the results. What am I missing in terms of configuring the project so that I can just run it from the IDE?

For reference, here is the roughly equivalent Java code:

import java.util.*;
import javax.swing.*;
import java.awt.*;

public class Main implements Runnable {

    public static void main(String[] args) throws Exception {
        System.out.println("The magic happens here.");
        EventQueue.invokeAndWait(new Main());
    }

    public void run() {
        System.out.println("Hello from the event queue");
        JFrame frame = new JFrame("This is the frame title");
        JLabel label = new JLabel("This is a label");
        frame.getContentPane().setLayout(new FlowLayout());
        frame.getContentPane().add(label);
        frame.pack();
        frame.setVisible(true);
    }
}

One more thing - am I missing something in the IDE? Code completion lets me complete function/class names, but it provides no hints whatsoever about function parameters that I can see, unless you first type the () after the method call, then cursor back into the brackets, then press command-P, which is quite tedious. Then it only tells you the types of the arguments in the java library, and not the parameter names.

Finally, the editor could use a few “standard” keyboard shortcuts for text editing that work in all standard Apple text components e.g. OPTION+DEL should delete the previous word. CMD+DEL should delete to beginning of line, etc.

Extra info re trying to run the Swift code via the Fire IDE. This is the error it spits out:

Gabriel,

thanx for the feedback. lots of separate issues to look at here, and i’ll get back in more detail tomorrow/monday. meantime, can you send me the working Java lanaguage projecvt, including the jar so i can compare? thanx!

See attached zip file: consoleapplication.zip (190.9 KB)

In the bin/Debug directory there is also a file Main.java which I simply compiled and ran from Terminal using:

$ javac Main.java
$ java Main

thanx. i’ll have a look tomorrow

ok. lets have a look.

(a) i can reproduce the Can't find resource for bundle sun.awt.resources.awtosx, key AWT.DefaultCursor error. i get the same with he equivalent java code (when compiled with Elements), as well, so it’s not a matter of the Swift code being wrong.

That said the application runs fine after i dismiss the exception, so i am guessing this is just yet another exception (of many) that is “normal” to show up when the app is being run in the debugger. I’ll add it to the list of exceptions that we’ll silently ignore, for the future,

Run outside of the debugger, both the javac complied app and the one compiled in Elements work the same, so i’m guessing the javac app has the same exception, you just don’t see to because you’re not running in the debugger.

(b) i can also reproduce that the Swift version exits w/o the read() while the Java (even the one compiled with Elements) one does not need it. that is strange, and i’ll need to log a bug to have this investigated.

© i’ll look at additional options to show more info on methods — maybe as part of there Code Completion dropdown itself; i’ll also want to add, eventually, for the parameter list to show automatically when typing (.

(d) it’s normal that CC doesn’t show parameter names because the java .jar files actually don’t contain those, and our compiler has noway to get them, for external methods :(. the info just is not there.

(e) i’ll log to have Option-Del and Cmd-Del added to the list — i was not aware of those shortcuts at all. Any other others you’re missing or would like to see? (Ctrl-Y is also on the list).

thanx!
marc

Thanks, logged as bugs://77238: Fire: add Option-Del and Command-Del keyboard shortcuts

Thanks, logged as bugs://77239: Cooper: Swift app terminates right away while same Java Language app does not

We found the problem.

thing is, Java (platform) does not allow return codes from main(). So what we do to e unable this is when you define main() to return an integer, we adda code to System.exit(<code>). Thing is, with how Swift declares the entry points there’s not signature you specify, so the end of Swift’s main() will always call System.exit(), which then brings down the app.

The Java version shows the same behavior if you change main to

	public static int main(String[] args) throws Exception {
		System.out.println("before invokeAndWait.");
		EventQueue.invokeAndWait(new Main());
		System.out.println("after invokeAndWait.");
		//return 0;
	}

(with our compiler, not with javac, which doesn’t support this).

we’re thinking about how to solve this, for now, the readln is the appropriate workaround, i’m afraid.

yours,
marc

bugs://77239 got closed with status wontfix.

Hey there :slight_smile: Apologies for the length of time I’ve been away - had computer issues (my iMac died) and this is also currently a side-project to evaluate viability for using this in future projects.

I am a little surprised that you’ve marked bugs://77239 as “wontfix”. I don’t think the “workaround” of having a System.in.read() is a viable long-term solution, and effectively what this means is that I will never be able to use this for any Swing-based project I might consider in the future (I have a rather large Swing-based application I’m the sole developer/maintainer on, and would have loved to start mixing in some Swift-based code).

Well, necessity is the mother of invention as they say. In other words, I found a solution:

import java.awt
import java.awt.event
import java.util.concurrent
import javax.swing

let applicationDoneLatch = CountDownLatch(1)

class ApplicationDoneListener: WindowAdapter {
	override func windowClosed(_ event: WindowEvent!) {
		applicationDoneLatch.countDown()
	}
}

print("The magic happens here.")
EventQueue.invokeAndWait {
	print("Hello from the event queue")
	let frame = JFrame("This is the frame title")
	frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
	frame.addWindowListener(ApplicationDoneListener())
	let label = JLabel("This is a label")
	frame.getContentPane().setLayout(FlowLayout())
	frame.getContentPane().add(label)
	frame.pack()
	frame.setVisible(true)
}

print("Waiting for finish")
applicationDoneLatch.await()
print("finishing")

Regarding macOS editing keyboard shortcuts… whatever you can do in terms of text editing navigation (e.g. Option+Right to move to the end of the word) also works with deleting text.

For example:

  • Option+Fn+Delete deletes from cursor to the end of the word.
  • Cmd+Fn+Delete deltes from the cursor to the end of the line

There are other navigation shortcuts:

  • Option+Up arrow moves to beginning of current line, or, if at beginning of the line, moves to the beginning of the previous line
  • Option+Down arrow moves to the end of the current line, or, if at the end of the line, moves to the end of the next line (this one is particularly useful)

Then there’s other standard macOS shortcuts such as Ctrl+T that transposes the characters either side of the insertion point (great for fixing those typos where you type characters out of order!)

As someone who uses Xcode a lot and uses a lot of keyboard shortcuts, having these missing really lowers makes using Fire an unpleasant thing.

The readln() might not be the right one term solution for Swing apps, but the original issue was closed because it’s not bug per se. The different in execution between the Java and the Swift version which i could not explain was explained (and is a difference between return value or no return value, really, regardless of language — just that Swift always hits the case that does have one), and that won’t/can’t be changed.

The “problem” needs to be solved on code level, not in the compiler. Your he solution with awaiting the event is probably better/cleaner, agreed.

Thanx; i’ve annotated 77238 with the extra info, and i’ll try to give this issue priority, if not for this weeks beta then for next.

thanx!

Keyboard shortcuts are all implemented for today’s upcoming beta. if you can think of any more, let me know!

bugs://77238 got closed with status fixed.

Awesome that you’ve got the keyboard shortcuts done; I look forward to trying them out! Speaking of which, when will that become publicly available? Since I’m only trialling Fire with Silver (I’m only interested in the Swift support), I don’t have an “active subscription” and therefore don’t have access to beta builds. I’m currently running the last release of Fire which according to the About box is 9.0.97.2071 (master), built on floorshow, 20161122-122747.

We’re currently looking at releasing 9.1 in a couple off weeks.

If you’d like to have a go at the beta, in the mean time, you can get it here: http://secure.remobjects.com/portal/silver.

yours,
marc

That’s awesome! Thanks! Downloading now.

1 Like