forthebadge forthebadge Gem Version

This gem was last updated on the 30.10.2023 (dd.mm.yyyy notation), at 20:00:02 o'clock.

Goals of the swing_paradise project

This project contains some add-on bindings to jruby Swing.

It is thus only really useful for jruby; and even there it is very incomplete. Mega-beta quality, at best. I do not recommend anyone to use this project as of yet.

Note that while the primary focus will be on Swing-based applications, there is a secondary focus of this project in that I will attempt to create as many Swing-based applications as possible to make working on Windows suck less. With this I specifically mean being able to use custom, ad-hoc widgets that solve certain problems, such as "I want to delete the first page of this .pdf file, via a GUI" on windows. In fact, that has been one major use case why I intensified code for this project in October 2023 - I had to use windows as primary operating system every now and then, and it always annoyed me compared to Linux, so I decided to create widgets (and describe them, too) that will help me on windows. Also note that this is an ongoing effort - I can not predict how useful and extensive this will be. Stay tuned nonetheless.

Another, secondary focus, is to provide useful documentation in regards to Swing. This helps me as a mnemonic, but it may also be helpful to new users, in what they can do with the project here in the long run.

SwingParadise::BaseModule

SwingParadise::BaseModule is the core helper module of this gem.

You can include it, since it is a module, via:

require 'swing_paradise/base_module/base_module.rb'
include SwingParadise::BaseModule

See also the distributed examples if you want to know more about how to use this in practice.

Since as of 29th October 2023, this will also automatically pull in most of the important java-swing methods. I found this easier to work with, than have to remember which widgets I need.

This is done via java_import statements, such as:

java_import javax.swing.JPasswordField

So basically you can omit a few lines in your application by tapping into the BaseModule module.

Simplified quitting

Use the following method to quit easily:

do_quit

For instance, a quit button could then be done in this manner:

quit_button.on_clicked {
  do_quit
}

Useful java_import headers

include Java

java_import javax.swing.JButton
java_import javax.swing.JFrame
java_import javax.swing.JLabel
java_import javax.swing.JPanel
java_import javax.swing.JTextArea
java_import javax.swing.JScrollBar
java_import javax.swing.JTextField
java_import javax.swing.JSpinner
java_import javax.swing.SpinnerNumberModel
java_import java.lang.System
java_import java.awt.Font

Usage example for setBounds

_.setBounds(10, 20, 200, 40)  /* is: x-coordinate, y-coordinate, width, height) */
_.set_bounds(10, 20, 200, 40) /* is: x-coordinate, y-coordinate, width, height) */

Note that both variants work. I prefer .set_bounds().

JTextArea

The JTextArea class provides a component that displays multiple lines of text.

If only one line of input is required from the user, then a text field should be used rather than JTextArea.

In raw Java, the code for instantiating a new JTextArea goes like this:

text_area = new JTextArea(5, 20);
JScrollPane scroll_pane = new JScrollPane(text_area); 
text_area.setEditable(false);

In Java, you can set the background colour to a colour of your choosing via:

import java.awt.Color;
Color color = new Color(255,0,0); /* This is red. */
text_area.setBackground(color);

JComboBox - working with combo-boxes in Java swing and jruby

You can instantiate a new combo box via:

combo_box = JComboBox.new

Now, in order to fill it up, you can use something like this:

array = %w( apple bird cat dog eagle ferret )
array.each {|this_item|
  combo_box.addItem(this_item)
}

So .addItem() can be used.

As the above is a bit cumbersome, if you make use of SwingParadise::BaseModule, you can use the following API instead:

array = %w( apple bird cat dog eagle ferret )
combo_box(array)

To select a specific index, that is, a specific entry on that combo box, you can use the method .setSelectedIndex():

combo_box.setSelectedIndex(2) # For the third entry.

To query which index is the currently selected one on a combo-box, use .selected_index as in:

combo_box.selected_index

To obtain the selected entry, use:

combo_box.selected_item

Java::JavaAwtEvent::ActionEvent

class Java::JavaAwtEvent::ActionEvent is the base class for when Java Swing fires an event, such as when the user changes the content of a combo-box.

The syntax to use it, from jruby, goes like this:

widget.add_action_listener { |event|
}

So you designate a block variable; I recommend to call it event.

How can you find out the specific event?

One way goes via the method .get_action_command(), such as in:

event.get_action_command

For the changed content of a combo-box, the result would comboBoxChanged.

To respond to this, you can use the following snippet:

case event.get_action_command
when /comboBoxChanged/
end

I needed this functionality for a widget that, when the user changes the combo-box content, another entry is also changed, reflecting the currently selected entry there.

Available colours

Just a simple listing of available colours in a java swing application:

Color::RED
Color::BLUE
Color::GREEN
Color::BLACK

Obtaining the height and width of a widget

Use .getBounds as in:

frame.getBounds()
height = r.height
width  = r.width

JFrame

To set a grid layout you can use:

frame.set_layout(
  java.awt.GridLayout.new(2, 2, 2, 2)
)

This is especially useful for any 2D layouts.

JPanel

In raw jruby, you can create a new instance of JPanel by issuing this:

panel = JPanel.new

You can then assign different layouts to be used. For instance, to keep the panel left-aligned, meaning you will see new elements all appear in a linear left-to-right fashion, you can use a FlowLayout like this:

panel.layout = FlowLayout.new(FlowLayout::LEFT)

This would look similar to the following image:

This seems quite convenient and easy to use, so the swing_paradise gem tries to make this even easier. Here is the proposed API for the above two lines:

panel = create_panel { :left }

This is exactly the same as:

panel = JPanel.new
panel.layout = FlowLayout.new(FlowLayout::LEFT)

Working with colours in SWING and jruby

The generic way to handle colours in java-swing goes like this:

import java.awt.Color;
Color color = new Color(255,0,0); /* This is red. */

Choosing files via a GUI

You can use something like the following to get a file-chooser in jruby-swing:

file_chooser = JFileChooser.new
# file_chooser.setFileSelectionMode(JFileChooser::DIRECTORIES_ONLY)

result = file_chooser.showOpenDialog(nil)
case result
when JFileChooser::APPROVE_OPTION
  this_file = file_chooser.getSelectedFile.getAbsoluteFile.to_s
  # this_file = File.absolute_path(this_file)
  main_entry?.set_text(this_file)
end

Adjust accordingly to your use case.

Contact information and mandatory 2FA coming up in 2022

If your creative mind has ideas and specific suggestions to make this gem more useful in general, feel free to drop me an email at any time, via:

shevy@inbox.lt

Before that email I used an email account at Google gmail, but in 2021 I decided to slowly abandon gmail, for various reasons. In order to limit the explanation here, allow me to just briefly state that I do not feel as if I want to promote any Google service anymore when the user becomes the product (such as via data collection by upstream services). I feel this is a hugely flawed business model.

Do keep in mind that responding to emails may take some time, depending on the amount of work I may have at that moment.

In 2022 rubygems.org, or rather the corporate overlords who control the rubygems.org infrastructure these days, decided to make 2FA mandatory for every gem owner eventually: see https://blog.rubygems.org/2022/06/13/making-packages-more-secure.html

Mandatory 2FA will eventually be extended to all rubygems.org developers and maintainers. As I can not use 2FA, for reasons I will skip explaining here, this means that my projects will eventually be taken over by shopify (or, correspondingly, whoever effectively controls the rubygems.org ecosystem). At that point, I no longer have any control what is done to my projects since shopify (respectively those controlling the gems ecosystem) took away control here. Not sure at which point ruby became corporate-controlled - that was not the case several years ago.

Ruby also only allows 2FA users to participate on the issue tracker these days:

https://bugs.ruby-lang.org/issues/18800

(Note that this was changed a few months ago, so the last part is no longer valid - it is possible to register again without mandating 2FA. I will retain the above notice for a bit longer, though, as I feel we should not restrict communication via mandatory authentification in general. Fighting spam is a noble goal, but when it also means you lock out real human people then this is definitely NOT good.)