swing_paradise 0.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of swing_paradise might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1557 -0
  3. data/doc/README.gen +1510 -0
  4. data/lib/swing_paradise/autoinclude.rb +3 -0
  5. data/lib/swing_paradise/awt/README.md +1 -0
  6. data/lib/swing_paradise/awt/color.rb +45 -0
  7. data/lib/swing_paradise/base_module/base_module.rb +993 -0
  8. data/lib/swing_paradise/classes +1 -0
  9. data/lib/swing_paradise/examples/001_quit_button_example.rb +55 -0
  10. data/lib/swing_paradise/examples/002_text_area_example.rb +55 -0
  11. data/lib/swing_paradise/examples/003_combo_box_example.rb +57 -0
  12. data/lib/swing_paradise/examples/004_jpanel_left_bound_example.rb +41 -0
  13. data/lib/swing_paradise/examples/005_box_layout_example.rb +39 -0
  14. data/lib/swing_paradise/examples/006_frame_example.rb +33 -0
  15. data/lib/swing_paradise/examples/007_textarea_responding_to_enter_key_example.rb +28 -0
  16. data/lib/swing_paradise/examples/008_scrolled_window_example.rb +41 -0
  17. data/lib/swing_paradise/examples/009_font_size_example.rb +39 -0
  18. data/lib/swing_paradise/examples/010_counter_example.rb +183 -0
  19. data/lib/swing_paradise/examples/011_button_with_image_example.rb +58 -0
  20. data/lib/swing_paradise/examples/012_quit_on_escape_key_being_pressed.rb +37 -0
  21. data/lib/swing_paradise/examples/013_simple_box_example.rb +38 -0
  22. data/lib/swing_paradise/examples/014_mouse_events_example.rb +41 -0
  23. data/lib/swing_paradise/examples/015_menu_example.rb +77 -0
  24. data/lib/swing_paradise/examples/016_file_chooser_example.rb +96 -0
  25. data/lib/swing_paradise/examples/017_buttons_example.rb +56 -0
  26. data/lib/swing_paradise/examples/018_colour_chooser_example.rb +51 -0
  27. data/lib/swing_paradise/examples/019_jeditorpane_example.rb +61 -0
  28. data/lib/swing_paradise/examples/020_table_example.rb +77 -0
  29. data/lib/swing_paradise/examples/021_jsplitpane_example.rb +66 -0
  30. data/lib/swing_paradise/examples/022_drawing_oval_example.rb +51 -0
  31. data/lib/swing_paradise/examples/023_show_message_dialog_example.rb +57 -0
  32. data/lib/swing_paradise/java_classes/border_factory/border_factory.rb +19 -0
  33. data/lib/swing_paradise/java_classes/box/box.rb +72 -0
  34. data/lib/swing_paradise/java_classes/button +1 -0
  35. data/lib/swing_paradise/java_classes/checkbox +1 -0
  36. data/lib/swing_paradise/java_classes/combobox +1 -0
  37. data/lib/swing_paradise/java_classes/default_table_model/default_table_model.rb +18 -0
  38. data/lib/swing_paradise/java_classes/frame +1 -0
  39. data/lib/swing_paradise/java_classes/jbutton/jbutton.rb +199 -0
  40. data/lib/swing_paradise/java_classes/jcheckbox/jcheckbox.rb +28 -0
  41. data/lib/swing_paradise/java_classes/jcombobox/jcombobox.rb +31 -0
  42. data/lib/swing_paradise/java_classes/jcomponent/jcomponent.rb +253 -0
  43. data/lib/swing_paradise/java_classes/jeditorpane/jeditorpane.rb +23 -0
  44. data/lib/swing_paradise/java_classes/jfilechooser/jfilechooser.rb +22 -0
  45. data/lib/swing_paradise/java_classes/jframe/jframe.rb +319 -0
  46. data/lib/swing_paradise/java_classes/jlabel/jlabel.rb +171 -0
  47. data/lib/swing_paradise/java_classes/jmenu/jmenu.rb +13 -0
  48. data/lib/swing_paradise/java_classes/jmenubar/jmenubar.rb +13 -0
  49. data/lib/swing_paradise/java_classes/jpanel/jpanel.rb +115 -0
  50. data/lib/swing_paradise/java_classes/jscrollpane/jscrollpane.rb +84 -0
  51. data/lib/swing_paradise/java_classes/jspinner/jspinner.rb +17 -0
  52. data/lib/swing_paradise/java_classes/jtextarea/jtextarea.rb +120 -0
  53. data/lib/swing_paradise/java_classes/jtextfield/jtextfield.rb +314 -0
  54. data/lib/swing_paradise/java_classes/label +1 -0
  55. data/lib/swing_paradise/java_classes/panel +1 -0
  56. data/lib/swing_paradise/java_classes/spinner +1 -0
  57. data/lib/swing_paradise/java_classes/textarea +1 -0
  58. data/lib/swing_paradise/misc/misc.rb +57 -0
  59. data/lib/swing_paradise/prototype/prototype.rb +79 -0
  60. data/lib/swing_paradise/requires/require_the_project.rb +15 -0
  61. data/lib/swing_paradise/toplevel_methods/misc.rb +293 -0
  62. data/lib/swing_paradise/version/version.rb +17 -0
  63. data/lib/swing_paradise/widget_collection/README.md +2 -0
  64. data/lib/swing_paradise/widget_collection/text_viewer.rb +160 -0
  65. data/lib/swing_paradise.rb +1 -0
  66. data/swing_paradise.gemspec +42 -0
  67. metadata +120 -0
data/doc/README.gen ADDED
@@ -0,0 +1,1510 @@
1
+ DEFAULT_HEADER
2
+
3
+ ## Introduction to the swing_paradise project and its different goals
4
+
5
+ In the last some months of the year 2023/2024 I thought about the
6
+ goals of this project. This made me re-arrange the introductionary
7
+ section here. I will keep a numbered list of the goals of the
8
+ swing_paradise project.
9
+
10
+ (1) This gem contains some add-on bindings to jruby-Swing. This
11
+ is the primary goal.
12
+
13
+ <b>Swing</b> is an extension of the <b>Abstract Window Toolkit</b> (AWT),
14
+ a GUI (graphical user interface).
15
+
16
+ As Swing depends on Java, this project here really only makes
17
+ sense for use via <b>jruby</b>.
18
+
19
+ At present the project is fairly incomplete, but over the
20
+ coming months this should be improved. Right now this project
21
+ is beta-quality and I do not recommend anyone to use this
22
+ project. However had, for some limited scope, this project may
23
+ be fairly useful even if incomplete.
24
+
25
+ (2) Note that while the primary focus of this project will be on
26
+ Swing-based applications and add-on improvements, to make working
27
+ with jruby and Swing suck less, there is a secondary focus for
28
+ this project as well, in that I will attempt to create as many
29
+ Swing-based applications as possible, to make working on Windows
30
+ suck less. Most of these add-ons will reside under
31
+ <b>swing_paradise/widget_collection/</b>, but some may be grouped
32
+ into different gems, under either gui/jruby/ or gui/universal_widgets.
33
+ The latter will probably become more relevant in the future,
34
+ whereas for now, gui/jruby/ will be where most of the gui-relevant
35
+ bindings reside under.
36
+
37
+ With "Swing-based applications" I specifically mean being able to
38
+ use custom, ad-hoc widgets that solve certain problems, such
39
+ as "I want to delete the first page of this .pdf file,
40
+ via a GUI", on windows. In fact, that has been one major use
41
+ case why I intensified code for this project in October
42
+ 2023 - I had to use windows as primary operating system
43
+ every now and then, and it always annoyed me compared
44
+ to Linux, so I decided to create widgets (and describe
45
+ them, too) that will help me on windows. Also note that
46
+ this is an ongoing effort - I can not predict how useful
47
+ and extensive this will be. Stay tuned nonetheless.
48
+
49
+ (3) Another focus of this project is to provide useful documentation
50
+ in regards to Swing, as well as jruby. This helps me as a mnemonic,
51
+ but it may also be helpful to new users, in what they can do
52
+ with the project here in the long run. When I started this
53
+ project there was next to no project that documented
54
+ Swing + jruby. So one aim of this project has been to
55
+ polish the documentation as much as possible.
56
+
57
+ ## Terminology
58
+
59
+ In Java-Swing, a window is called a <b>frame</b>, which is represented
60
+ by class <b>JFrame</b>.
61
+
62
+ The default layout for Java-Swing components is a border layout.
63
+
64
+ ## SwingParadise::BaseModule
65
+
66
+ SwingParadise::BaseModule is the core helper module of
67
+ this gem.
68
+
69
+ You can include it, since it is a module, via:
70
+
71
+ require 'swing_paradise/base_module/base_module.rb'
72
+ include SwingParadise::BaseModule
73
+
74
+ See also the distributed examples if you want to know
75
+ more about how to use this in practice.
76
+
77
+ Since as of 29th October 2023, this will also automatically
78
+ pull in most of the important java-swing methods. I found
79
+ this easier to work with, than have to remember which
80
+ widgets I need.
81
+
82
+ This is done via java_import statements, such as:
83
+
84
+ java_import javax.swing.JPasswordField
85
+
86
+ So basically you can omit a few lines in your application
87
+ by tapping into the BaseModule module.
88
+
89
+ ## Simplified quitting
90
+
91
+ Use the following method to <b>quit</b> easily:
92
+
93
+ do_quit
94
+
95
+ For instance, a <b>quit button</b> could then be done in this
96
+ manner:
97
+
98
+ quit_button.on_clicked {
99
+ do_quit
100
+ }
101
+
102
+ ## Useful java_import headers
103
+
104
+ include Java
105
+
106
+ java_import javax.swing.JButton
107
+ java_import javax.swing.JFrame
108
+ java_import javax.swing.JLabel
109
+ java_import javax.swing.JPanel
110
+ java_import javax.swing.JTextArea
111
+ java_import javax.swing.JScrollBar
112
+ java_import javax.swing.JTextField
113
+ java_import javax.swing.JSpinner
114
+ java_import javax.swing.SpinnerNumberModel
115
+ java_import java.lang.System
116
+ java_import java.awt.Font
117
+
118
+ ## Usage example for setBounds
119
+
120
+ _.setBounds(10, 20, 200, 40) /* is: x-coordinate, y-coordinate, width, height) */
121
+ _.set_bounds(10, 20, 200, 40) /* is: x-coordinate, y-coordinate, width, height) */
122
+
123
+ Note that both variants work. I prefer <b>.set_bounds()</b>.
124
+
125
+ <!---
126
+
127
+ https://www.rubydoc.info/gems/swing_paradise/0.1.13#jtextarea
128
+
129
+ -->
130
+ ## JTextArea
131
+
132
+ First, let's have a look as to how a JTextArea may look like (on Windows):
133
+
134
+ <img src="https://i.imgur.com/CWVYskn.png" style="margin: 1em">
135
+
136
+ The <b>JTextArea class</b> provides a component that displays multiple lines of
137
+ text.
138
+
139
+ If only one line of input is required from the user, then a <b>text field</b>
140
+ should be used rather than JTextArea.
141
+
142
+ In <b>raw Java</b>, the code for instantiating a new JTextArea goes like this:
143
+
144
+ text_area = new JTextArea(5, 20);
145
+ JScrollPane scroll_pane = new JScrollPane(text_area);
146
+ text_area.setEditable(false);
147
+
148
+ In the code above, the API for JTextArea() follows this
149
+ signature: <b>JTextArea(int rows, int columns)</b> - so you first
150
+ pass in the number of rows, and then pass in the number of columns.
151
+
152
+ In Java, you can set the background colour to a colour of your choosing via:
153
+
154
+ import java.awt.Color;
155
+ Color color = new Color(255,0,0); /* This is red. */
156
+ text_area.setBackground(color);
157
+
158
+ The textarea is quite flexible. For instance, you can force it to
159
+ ignore newlines entered by the user, thus making it essentially
160
+ a single-line input entry:
161
+
162
+ textview = create_textarea
163
+ textview.getDocument.putProperty('filterNewlines', true)
164
+
165
+ As this is a bit annoying to remember, I added this method:
166
+
167
+ textview.filter_newlines
168
+
169
+ As always, you need to include SwingParadise::BaseModule for
170
+ this add-on functionality.
171
+
172
+ Most of the time you probably don't want this behaviour though.
173
+
174
+ To set to a different background colour, use something like this:
175
+
176
+ textview.setBackground(Color::GREEN)
177
+
178
+ Line-wrapping and wrap-style can also be set:
179
+
180
+ textview.setLineWrap(true)
181
+ textview.setWrapStyleWord(false)
182
+
183
+ ## JComboBox - working with combo-boxes in Java swing and jruby
184
+
185
+ You can instantiate a new combo box via:
186
+
187
+ combo_box = JComboBox.new
188
+
189
+ Now, in order to fill it up, you can use something like this:
190
+
191
+ array = %w( apple bird cat dog eagle ferret )
192
+ array.each {|this_item|
193
+ combo_box.addItem(this_item)
194
+ }
195
+
196
+ So .addItem() can be used to add more elements to the combo-box.
197
+
198
+ As the above is a bit cumbersome, if you make use of
199
+ <b>SwingParadise::BaseModule</b>, you can use the following API
200
+ instead:
201
+
202
+ array = %w( apple bird cat dog eagle ferret )
203
+ combo_box(array) # So you can simply pass in the full Array here
204
+
205
+ To select a specific index, that is, a specific entry on that
206
+ combo box, you can use the method <b>.setSelectedIndex()</b>:
207
+
208
+ combo_box.setSelectedIndex(2) # For the third entry.
209
+
210
+ To query which index is the currently selected one on a
211
+ combo-box, use the method <b>.selected_index</b>, as in:
212
+
213
+ combo_box.selected_index
214
+
215
+ To obtain the selected entry, use <b>.selected_item</b>,
216
+ as in:
217
+
218
+ combo_box.selected_item
219
+
220
+ ## Java::JavaAwtEvent::ActionEvent
221
+
222
+ Events in java can be found under <b>java.awt.events.*</b>.
223
+
224
+ <b>class Java::JavaAwtEvent::ActionEvent</b> is the base class for
225
+ when Java Swing fires an event, such as when the user changes the
226
+ content of a combo-box.
227
+
228
+ The syntax to use it, from <b>jruby</b>, goes like this:
229
+
230
+ widget.add_action_listener { |event|
231
+ }
232
+
233
+ So you designate a block variable; I recommend to consistently call
234
+ it <b>event</b>, as that should simplify things.
235
+
236
+ How can you find out the specific event?
237
+
238
+ One way goes via the method <b>.get_action_command()</b>,
239
+ such as in:
240
+
241
+ event.get_action_command
242
+
243
+ action_command = event.get_action_command
244
+
245
+ For the changed content of a combo-box, the result
246
+ would <b>comboBoxChanged</b>.
247
+
248
+ To respond to this, you can use the following snippet:
249
+
250
+ case event.get_action_command
251
+ when /comboBoxChanged/
252
+ end
253
+
254
+ I needed this functionality for a widget that, when the user changes
255
+ the combo-box content, another entry is also changed, reflecting the
256
+ currently selected entry there.
257
+
258
+ ## Available colours
259
+
260
+ Just a simple listing of available colours in a java swing
261
+ application:
262
+
263
+ Color::RED
264
+ Color::BLUE
265
+ Color::GREEN
266
+ Color::BLACK
267
+
268
+ ## Obtaining the height and width of a widget
269
+
270
+ Use .getBounds as in:
271
+
272
+ frame.getBounds()
273
+ height = r.height
274
+ width = r.width
275
+
276
+ ## The GridLayout
277
+
278
+ A GridLayout in java-swing looks like this:
279
+
280
+ <img src="https://docs.oracle.com/javase/tutorial/figures/uiswing/layout/GridLayoutDemo.png" style="margin: 1em">
281
+
282
+ In other words: you arrange elements (widgets) in a 2D-like matrix. This
283
+ is also called <b>a grid of cells</b>. Each component in the grid
284
+ is <b>exactly</b> the same size.
285
+
286
+ To create a new GridLayout, in raw Java, use this:
287
+
288
+ /* API: GridLayout(int rows, int cols) */
289
+ GridLayout x = new GridLayout(3, 3); /* A 3x3 grid */
290
+
291
+ You can then add new elements to it via:
292
+
293
+ .add(new JButton("Button 1"));
294
+ .add(new JButton("Button 2"));
295
+
296
+ And so forth.
297
+
298
+ If you use SwingParadise::BaseModule then you can also make
299
+ use of the .create_grid() method.
300
+
301
+ grid = create_grid('2x2')
302
+ grid.add(button('Button 1'))
303
+ grid.add(button('Button 2'))
304
+
305
+ This should be equivalent to the above mentioned Java code.
306
+
307
+ ## JCheckBox and checkboxes in Java swing
308
+
309
+ Let's first look at an image how checkboxes look in Java swing:
310
+
311
+ <img src="https://i.imgur.com/E5gugWY.png" style="margin: 1em">
312
+
313
+ Let's next have a look at how we <b>add checkboxes in raw Java swing</b>:
314
+
315
+ JPanel panel = new JPanel();
316
+ panel.add(label);
317
+
318
+ JCheckBox one = new JCheckBox("one");
319
+ JCheckBox two = new JCheckBox("two");
320
+
321
+ panel.add(one);
322
+ panel.add(two);
323
+
324
+ So, we make use of <b>JCheckBox</b>. A second argument can be passed,
325
+ to determine whether the check-box is checked or whether it is not:
326
+
327
+ JCheckBox.new("Foobar", true)
328
+ JCheckBox.new("Foobar", false)
329
+
330
+ To determine whether a JCheckBox is <b>checked</b> - aka selected, the
331
+ following method can be used:
332
+
333
+ checkbox.isSelected()
334
+
335
+ Or, if you use the swing_paradise gem, you can also use:
336
+
337
+ checkbox.is_selected?
338
+
339
+ To mark the checkbox as checked, use:
340
+
341
+ checkbox.setSelected(true)
342
+
343
+ ## JFrame
344
+
345
+ To create a new frame, aka a new JFrame, from jruby, use:
346
+
347
+ frame = JFrame.new # This would be an untitled frame.
348
+ frame = JFrame.new("Frame Title") # And this would set the title to "Frame Title".
349
+
350
+ If you'd like to you could also use the full qualifier (full name),
351
+ which is:
352
+
353
+ frame = javax.swing.JFrame.new
354
+ # panel = Java::javax::swing::JFrame.new # This variant may also work, but is not as elegant as the one above.
355
+
356
+ However had, note that both variants shown above are more verbose, so
357
+ it may not be worth the extra time to type; nonetheless, should you
358
+ ever have a use case to scope specifically to a particular class,
359
+ you can preface it via <b>javax.swing</b> (or wherever else that
360
+ particular swing-class resides at).
361
+
362
+ To set a grid layout you can use the method called <b>.set_layout()</b>,
363
+ as seen in the following example:
364
+
365
+ frame.set_layout(
366
+ java.awt.GridLayout.new(2, 2, 2, 2)
367
+ )
368
+
369
+ This is especially useful for any 2D layouts.
370
+
371
+ To <b>exit a JFrame</b>, as the main pane, Java Swing usually
372
+ requires that you use something like this:
373
+
374
+ frame.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
375
+
376
+ I found this a bit cumbersome to type and difficult to
377
+ remember, so the SwingParadise::BaseModule allows you
378
+ to use this method instead:
379
+
380
+ default_close
381
+
382
+ This one is easier for me to remember, and less to type, too.
383
+
384
+ Note that you can not add a JFrame to another JFrame. I ran into
385
+ this issue in December 2023, so I had to note this down here.
386
+
387
+ The explanation I found stated this:
388
+
389
+ "JFrame is a <b>top level container</b> and as such it cannot
390
+ be <b>added</b> to any other container."
391
+
392
+ Typically a JFrame contains two parts: a space area on top for
393
+ the menu bar, and the content pane below the menu bar. Often
394
+ the menu bar is missing, though, so the content pane is
395
+ ultimately more important than the menu bar.
396
+
397
+ Further methods for the JFrame include these (as a sample):
398
+
399
+ .setVisible(boolean b)
400
+ .setTitle(String title)
401
+ .setSize(int width, int height)
402
+ .setLocation(int horizontal, int vertical)
403
+ .pack()
404
+ .setDefaultCloseOperation(int operation)
405
+
406
+ By default a JFrame is not visible, so we have to use:
407
+
408
+ frame.setVisible(true)
409
+
410
+ To make it visible.
411
+
412
+ You can designate the size of the main JFrame via .setSize():
413
+
414
+ .setSize(int width, int height)
415
+ .setSize(600, 420)
416
+
417
+ Note that calling the method .pack() will resize the frame so that
418
+ it tightly fits around components embedded into its content
419
+ pane.
420
+
421
+ To make the whole application quit when the close-action is
422
+ triggered, use:
423
+
424
+ frame.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
425
+
426
+ ## JPanel
427
+
428
+ In raw jruby, you can create a new instance of JPanel by issuing
429
+ this:
430
+
431
+ panel = JPanel.new
432
+
433
+ You can then assign different layouts to be used. For instance,
434
+ to keep the panel left-aligned, meaning you will see new elements
435
+ all appear in a linear left-to-right fashion, you can use a
436
+ FlowLayout like this:
437
+
438
+ panel.layout = FlowLayout.new(FlowLayout::LEFT)
439
+
440
+ This would look similar to the following image:
441
+
442
+ <img src="https://i.imgur.com/Yr7t7hJ.png" style="margin: 1em">
443
+
444
+ This seems quite convenient and easy to use, so the swing_paradise
445
+ gem tries to make this even easier. Here is the proposed API
446
+ for the above two lines:
447
+
448
+ panel = create_panel { :left }
449
+
450
+ This is <b>exactly</b> the same as:
451
+
452
+ panel = JPanel.new
453
+ panel.layout = FlowLayout.new(FlowLayout::LEFT)
454
+
455
+ Note that FlowLayout is the default layout manager for
456
+ every JPanel. The components will be laid out in a single
457
+ row one after the other.
458
+
459
+ Here is another picture how this would look:
460
+
461
+ <img src="https://www.guru99.com/images/uploads/2012/06/java-flow-layout-manager.jpg" style="margin: 1em">
462
+
463
+ JPanel can also be used to draw onto, via the method called
464
+ <b>paintComponent</b>. Whenever the GUI is resized, this
465
+ method will be automatically called.
466
+
467
+ Take note that .paintComponent() should not be called directly;
468
+ instead, use the .repaint() method in the event you wish to
469
+ draw onto the panel.
470
+
471
+ The API for paintComponent in raw Java Swing goes as follows:
472
+
473
+ public void paintComponent(Graphics g)
474
+
475
+ Graphics here belongs to AWT.
476
+
477
+ ## Working with colours in SWING and jruby
478
+
479
+ The generic way to handle colours in java-swing goes like this:
480
+
481
+ import java.awt.Color;
482
+ Color color = new Color(255,0,0); /* This is red. */
483
+
484
+ ## Using no specific layout
485
+
486
+ Via:
487
+
488
+ frame.setLayout(nil)
489
+
490
+ You can avoid using any specific layout.
491
+
492
+ ## GridBagLayout
493
+
494
+ GridBagLayout aligns components by placing them within a grid
495
+ of cells, allowing components to span more than one cell.
496
+
497
+ The following image shows how this may look like:
498
+
499
+ <img src="https://www.guru99.com/images/uploads/2012/06/java-grid-bag-layout.jpg" style="margin: 1em">
500
+
501
+ ## JButton and buttons in swing
502
+
503
+ Java-Swing calls a button JButton. JButton is not the only button
504
+ available in Java-Swing: we can also use JCheckBox, JRadioButton,
505
+ JMenuItem, JCheckBoxMenuItem, JRadioButtonMenuItem or JToggleButton.
506
+
507
+ An example for a widget that uses three buttons will be shown
508
+ next (on Windows XP):
509
+
510
+ <img src="https://i.imgur.com/xBvl7Fq.png" style="margin: 1em">
511
+
512
+ You can add an icon to a button in swing.
513
+
514
+ First, let's show the Java version for this:
515
+
516
+ JButton button = new JButton(new ImageIcon("foobar.jpg"));
517
+
518
+ <b>ImageIcon</b> can be used for <b>pixel graphics</b>.
519
+
520
+ Next, the equivalent ruby code:
521
+
522
+ button = JButton.new(ImageIcon.new('foobar.jpg'))
523
+
524
+ If you use the swing_paradise gem, the above can be simplified a
525
+ little bit further:
526
+
527
+ button = button(ImageIcon.new('foobar.jpg'))
528
+
529
+ I may extend this API to simplify this further, such as
530
+ <b>button_with_image()</b> or something like that. In fact, in
531
+ February 2024 this was indeed extended: if you use SwingParadise::BaseModule
532
+ then you can use the method called <b>button_with_image()</b> to add
533
+ a button with an image. There are two ways to call this: one is by simply
534
+ passing the path to a local image. The second way is to also pass an
535
+ optional text that is displayed next to the image.
536
+
537
+ To change the background colour for a button, use the following API:
538
+
539
+ button.setBackground(Color.green) # This would make it green.
540
+
541
+ To let a JButton respond to on-click events, one has to
542
+ attach a listener, via the following API:
543
+
544
+ button.addActionListener(ActionListener listener)
545
+
546
+ In jruby this is implemented via a block form, that is via:
547
+
548
+ {
549
+ }
550
+
551
+ To <b>focus</b> on a button, use:
552
+
553
+ button.requestFocusInWindow();
554
+
555
+ To obtain the text (label) if a JButton, use the method
556
+ <b>.getText</b>.
557
+
558
+ If you make use of the swing-paradise gem then you can
559
+ simply call the .on_clicked {} method on a button,
560
+ such as via:
561
+
562
+ button = JButton.new('Please click me.')
563
+ button.on_clicked {
564
+ puts 'I was clicked.'
565
+ }
566
+
567
+ There is, interestingly enough, another way possible for
568
+ achieving the above, in that you specify a distinct
569
+ class that will be invoked when the button is called.
570
+
571
+ So, the code for the button at hand would then look like
572
+ this:
573
+
574
+ button = JButton.new('Please click me.')
575
+ button.addActionListener(ClickAction.new)
576
+
577
+ And you also need to define class ClickAction, like this:
578
+
579
+ class ClickAction
580
+
581
+ include ActionListener
582
+
583
+ def actionPerformed(event) # you can also use: "def action_performed" instead
584
+ puts 'This time the button was called from within clas ClickAction.'
585
+ end
586
+
587
+ end
588
+
589
+ This solution is not quite as convenient as the .on_clicked {} variant,
590
+ but perhaps there may be times when this is needed, so it is mentioned
591
+ here in the documentation. Personally I will continue to prefer
592
+ the <b>.on_clicked {} method variant</b> though - my brain has an
593
+ easier time remembering that variant.
594
+
595
+ You can also use tooltips for a button.
596
+
597
+ Examples:
598
+
599
+ button.setToolTipText('Press Alt+H to trigger this button.')
600
+ button.hint = 'Press Alt+H to trigger this button.'
601
+
602
+ If you need to obtain the tooltip-text, you can use:
603
+
604
+ puts button.getToolTipText
605
+
606
+ The location where the tooltip will be shown, can be obtained via:
607
+
608
+ puts button.getToolTipLocation(MouseEvent)
609
+
610
+ If you want to make the button have a flat-style look, use:
611
+
612
+ button.setBorderPainted(false)
613
+ button.setFocusPainted(false)
614
+ button.setContentAreaFilled(false)
615
+
616
+ The full <b>API documentation</b> for JButton can be found here:
617
+
618
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JButton.html
619
+
620
+ ## JLabel and text
621
+
622
+ You can right-align a JLabel widget via:
623
+
624
+ JLabel(String text, int horizontalAlignment)
625
+ JLabel label = new JLabel("Telephone", SwingConstants.RIGHT);
626
+
627
+ In jruby-swing this would look like this:
628
+
629
+ label = JLabel.new('Telephone', SwingConstants::RIGHT)
630
+
631
+ After you created a label, you can call several methods on it.
632
+
633
+ For instance, to change the foreground colour, use:
634
+
635
+ label.setForeground(Color c)
636
+
637
+ For the background colour use:
638
+
639
+ label.setBackground(Color c)
640
+
641
+ You can also set the label to be opaque, via:
642
+
643
+ label.setOpaque(boolean b)
644
+ label.setOpaque(true)
645
+ label.setOpaque(false)
646
+
647
+ If true is passed to the latter method then the label
648
+ will be transparent; if it is false, then the label will be
649
+ non-transparent.
650
+
651
+ Interestingly you can also use HTML markup in a JLabel. The
652
+ following example shows how this can be done:
653
+
654
+ label = JLabel.new("<html><span>This is your text</span></html>");
655
+
656
+ ## JColorChooser (javax.swing.colorchooser)
657
+
658
+ <b>JColorChooser</b> can be used to pick a certain colours.
659
+
660
+ Let's have a look at an image, to find out how this may actually look:
661
+
662
+ <img src="https://docs.oracle.com/javase/tutorial/figures/uiswing/components/ColorChooserDemoMetal.png" style="margin: 1em">
663
+
664
+ In raw Java, we would use the following to create a new JColorChooser instance:
665
+
666
+ banner = new JLabel("Some text.", JLabel.CENTER);
667
+ banner.setForeground(Color.yellow);
668
+ jcolorchooser = new JColorChooser(banner.getForeground());
669
+ add(jcolorchooser, BorderLayout.PAGE_END);
670
+
671
+ If you want to create a dialog, for the user to make a choice, you can
672
+ use the <b>.createDialog()</b> method:
673
+
674
+ jcolorchooser.createDialog()
675
+ jcolorchooser.createDialog # Remember, in ruby you can omit the ().
676
+
677
+ ## JOptionPane
678
+
679
+ <b>JOptionPane</b> can be used to ask the user about confirmation about
680
+ certain actions, such as <b>Do you really want to delete this
681
+ file?</b>.
682
+
683
+ ## BorderLayout
684
+
685
+ A BorderLayout places components in up to five areas:
686
+
687
+ <b>top</b>, <b>bottom</b>, <b>left</b>, <b>right</b>,
688
+ and <b>center</b>.
689
+
690
+ It is <b>the default layout manager</b> for every java JFrame.
691
+
692
+ It looks like this:
693
+
694
+ <img src="https://www.guru99.com/images/uploads/2012/06/java-border-layout-manager.jpg" style="margin: 1em">
695
+
696
+ ## BorderFactory
697
+
698
+ BorderFactory can be used to create a frame with a label.
699
+
700
+ Usage example in jruby:
701
+
702
+ _ = BorderFactory.createTitledBorder(' Shell ')
703
+ _.setTitleFont(Font.new('Tahoma', Font::PLAIN, 50)) # This here can be used to set the font that is used.
704
+
705
+ Many variants exist for BorderFactory.
706
+
707
+ For instance, to set a matte-border, you can use:
708
+
709
+ ImageIcon icon = createImageIcon("images/wavy.gif", "wavy-line border icon"); # 20x22
710
+ BorderFactory.createMatteBorder(-1, -1, -1, -1, icon));
711
+
712
+ ## ImageIcon
713
+
714
+ The name icon is a slight misnomer for this class, as it can also deal with
715
+ large images.
716
+
717
+ As argument to this class the path to a local filename should be supplied,
718
+ as a String.
719
+
720
+ Example:
721
+
722
+ image_icon = ImageIcon.new('/tmp/foobar.png')
723
+
724
+ You can also supply an URL instead of a String to a local path.
725
+
726
+ You can query the height and width of this image via:
727
+
728
+ image_icon.getImageHeight() # returns the image height, in n pixels.
729
+ image_icon.getImageWidth() # returns the image width, in n pixels.
730
+
731
+ Keep in mind that instances of class ImageIcon are non-graphical components.
732
+ This means that they have to be put into some container, such as
733
+ JLabel, e. g.:
734
+
735
+ JLabel.new(ImageIcon picture)
736
+ JLabel.new(image_icon) # re-using the variable defined above ^^^
737
+
738
+ You can also load images <b>asynchronously</b>. This can be done via
739
+ <b>Toolkit</b> from the AWT library.
740
+
741
+ Example in Java-Swing:
742
+
743
+ Image picture = Toolkit.getDefaultToolkit.getImage(String filename);
744
+ Image picture = Toolkit.getDefaultToolkit.getImage(String url);
745
+
746
+ In jruby-Swing:
747
+
748
+ picture = Toolkit.getDefaultToolkit.getImage(String filename)
749
+ picture = Toolkit.getDefaultToolkit.getImage('foobar.png')
750
+
751
+ If you need to load multiple images, possibly distributed on
752
+ various servers on the internet, you may want to make use
753
+ of class <b>MediaTracker</b>, which is part of the AWT
754
+ library. MediaTracker can monitor the loading process of many
755
+ images. Interestingly MediaTracker makes use of an id,
756
+ such as via the following method call:
757
+
758
+ .addImage(Image picture, int id)
759
+
760
+ ## Java::JavaAwtEvent::ActionEvent and events in general
761
+
762
+ An event in a SWING application is typically of class
763
+ <b>Java::JavaAwtEvent::ActionEvent</b>, as far as Ruby is
764
+ concerned.
765
+
766
+ ## JTextField
767
+
768
+ <b>JTextField</b> is a lightweight component that allows the
769
+ editing of a single line of text.
770
+
771
+ A <b>JTextField</b> - also known as an <b>entry</b> - is
772
+ a <b>subclass</b> of the <b>JTextComponent</b> class.
773
+
774
+ <b>Padding</b> can be added to a JTextField via the method
775
+ .setMargin() and passing proper insets to it.
776
+
777
+ Example:
778
+
779
+ setMargin(Insets m)
780
+
781
+ text_field = new JTextField("A text field example.");
782
+ text_field.setMargin(new Insets(10, 10, 10, 10));
783
+
784
+ JTextField can also be instantiated in this manner:
785
+
786
+ JTextField(String text, int columns)
787
+
788
+ So the second argument means how many columns this entry
789
+ should have.
790
+
791
+ Documentation for JTextField can be seen here:
792
+
793
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JTextField.html
794
+
795
+ ## Textfields in Java-SWING via JFormattedTextField
796
+
797
+ If you have a need to hide certain input elements, such as
798
+ via a user-password, you could use the following code, in
799
+ Java-SWING:
800
+
801
+ import javax.swing.text.MaskFormatter;
802
+ MaskFormatter mask_formatter = new MaskFormatter("###-##-####");
803
+
804
+ JFormattedTextField has three preconfigured format types:
805
+
806
+ numbers
807
+ dates
808
+ strings
809
+
810
+ ## JScrollBar
811
+
812
+ First, before this subsection explains some things about a <b>JScollBar</b>, let us state
813
+ that in many cases a developer may want to use <b>JScrollPane</b> instead.
814
+
815
+ <b>JScrollBar</b> is used to create a scrolling widget. This refers to
816
+ a widget that has a vertical and a horizontal bar - both of which
817
+ can be optional - allowing the mouse pointer to click and drag
818
+ the child-widget, to the right, left, up or down. This is especially
819
+ useful for a text-buffer widget, where regular text is displayed
820
+ that overflows to the right hand side (or somewhere else).
821
+
822
+ The following image shows how this looked on Windows XP:
823
+
824
+ <img src="https://i.imgur.com/6AEwGR7.png" style="margin: 1em">
825
+
826
+ So, to summarize: the scroll bar is used to determine the
827
+ viewing area of the component (the child-widget).
828
+
829
+ The scroll bar involves a knob that can be adjusted by the
830
+ user. This is meant for use with the mouse pointer.
831
+
832
+ How to create a new instance for a scroll bar in Java?
833
+
834
+ The following code example (<b>ScrollBarExample.java</b>) shows this:
835
+
836
+ import javax.swing.*;
837
+ import java.awt.*;
838
+
839
+ class ScrollBarExample {
840
+
841
+ public static void main(String[] args) {
842
+ final JFrame frame = new JFrame("ScrollBarExample");
843
+
844
+ JScrollBar scrollBarH = new JScrollBar(JScrollBar.HORIZONTAL, 30, 20, 0, 500);
845
+ JScrollBar scrollBarV = new JScrollBar(JScrollBar.VERTICAL, 30, 40, 0, 500);
846
+
847
+ frame.setSize(300,200);
848
+ frame.getContentPane().add(scrollBarH, BorderLayout.SOUTH);
849
+ frame.getContentPane().add(scrollBarV, BorderLayout.EAST);
850
+ frame.setVisible(true);
851
+ }
852
+
853
+ }
854
+
855
+ Which relevant properties does the scroll bar have?
856
+
857
+ orientation: This indicates a horizontal or a vertical Scrollbar.
858
+ value: This indicates the model's current value. The upper
859
+ limit on the model's value is maximum - extent and the
860
+ lower limit is minimum.
861
+ extent: This indicates the width of the knob of the scrollbar.
862
+ minimum: This indicates the minimum width of the track on which the scrollbar moves.
863
+ maximum: This indicates the maximum width of the track on which the scrollbar moves.
864
+
865
+ If you instantiate a new scrollbar in jruby, using this syntax:
866
+
867
+ JScrollBar.new
868
+
869
+ then the following initial values are used:
870
+
871
+ minimum = 0
872
+ maximum = 100
873
+ value = 0
874
+ extent = 10
875
+
876
+ The first argument is orientation (as Integer).
877
+
878
+ Example:
879
+
880
+ JScrollBar.new(int orientation)
881
+ JScrollBar.new(1)
882
+
883
+ In other words: you can use this to determine the orientation
884
+ of the scrollbar. The value <b>orientation=0</b> means we will
885
+ make use of a horizontal scroll bar, whereas the value
886
+ <b>orientation=1</b> means we will get a vertical scroll bar.
887
+ Most commonly a horizontal scroll bar is used.
888
+
889
+ The most commonly used methods of the JScrollBar class are
890
+ as follows:
891
+
892
+ - The addAdjustmentListener(AdjustmentListener l) method adds a
893
+ listener to the specified JScrollBar instance. The listener
894
+ will be notified every time a change to the model of the
895
+ scroll bar is detected.
896
+ - The getModel() method returns the model of the scroll bar.
897
+ - The getMaximum() method returns the maximum value (maximum -
898
+ extent) of the scrollbar.
899
+ - The getMinimum() method returns the minimum value of the scroll
900
+ bar.
901
+ - The getOrientation() method returns the orientation of the
902
+ scroll bar.
903
+ - The getValue() method returns the scrollbar’s value.
904
+ - The setMaximum() method is used to set the maximum value
905
+ of the scrollbar.
906
+ - The setMinimum() method is used to set the minimum value of the scroll bar.
907
+ - The setOrientation() method is used to set the orientation of the scroll bar.
908
+ - The setValue() method is used to set the scrollbar’s value.
909
+
910
+ If you want to set inner padding, you have to make use of
911
+ a border:
912
+
913
+ scroll_bar.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10))
914
+
915
+ ## Checking for the escape-key being pressed
916
+
917
+ In raw Java SWING, we can use the following line of code to check whether
918
+ the user has pressed the escape-key:
919
+
920
+ if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
921
+ }
922
+
923
+ In jruby SWING, this would be:
924
+
925
+ if (event.getKeyCode() == KeyEvent::VK_ESCAPE) {
926
+ }
927
+
928
+ Note that <b>KeyEvent::VK_ESCAPE</b> returns a number; in this case
929
+ that number is <b>27</b>.
930
+
931
+ ## The Graphics class
932
+
933
+ Available methods include:
934
+
935
+ drawLine(int xstart, int ystart, int xend, int yend)
936
+ drawRect(int xleft, int ytop, int width, int height)
937
+ drawOval(int xleft, int ytop, int width, int height)
938
+ drawString(String text, int xleft, int ybottom)
939
+ fillRect(int xleft, int ytop, int width, int height)
940
+ fillOval(int xleft, int ytop, int width, int height)
941
+ setColor(Color col)
942
+
943
+ All these int-arguments refer to <b>pixels</b>.
944
+
945
+ <b>.drawLine(xstart,ystart,xend,yend)</b> draws a line segment
946
+ between the points with coordinates (xstart, ystart) and
947
+ (xend, yend).
948
+
949
+ Note that .setColor(col) sets the colour of the drawing to col.
950
+ This colour is used until the setColor command is used again.
951
+
952
+ ## The mouse and mouse-events
953
+
954
+ A mouse event in jruby is of class <b>Java::JavaAwtEvent::MouseEvent</b>.
955
+
956
+ In Java-Swing two interfaces process mouse events:
957
+
958
+ 1) MouseListener
959
+ 2) MouseMotionListener
960
+
961
+ Note that key listeners react to key strokes (aka key press events).
962
+
963
+ ## JScrollPane
964
+
965
+ First, let's have a look how a JScrollPane may look like:
966
+
967
+ <img src="https://i.imgur.com/sGd0NN6.png" style="margin: 1em">
968
+
969
+ JScrollPane is the primary widget to be used when scrolling
970
+ should be used (in Swing).
971
+
972
+ Next, let's look at a raw Java example for how to work with a <b>JScrollPane</b>:
973
+
974
+ import java.awt.FlowLayout;
975
+ import javax.swing.JFrame;
976
+ import javax.swing.JScrollPane; /* This is where it resides. */
977
+ import javax.swing.JtextArea;
978
+
979
+ public class JScrollPaneExample {
980
+ private static final long serialVersionUID = 1L;
981
+
982
+ private static void createAndShowGUI() {
983
+
984
+ // Create and set up the window.
985
+ final JFrame frame = new JFrame("Scroll Pane Example");
986
+
987
+ // Display the window.
988
+ frame.setSize(500, 500);
989
+ frame.setVisible(true);
990
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
991
+
992
+ // set flow layout for the frame
993
+ frame.getContentPane().setLayout(new FlowLayout());
994
+
995
+ JTextArea textArea = new JTextArea(20, 20);
996
+ JScrollPane scrollableTextArea = new JScrollPane(textArea);
997
+
998
+ scrollableTextArea.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
999
+ scrollableTextArea.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
1000
+
1001
+ frame.getContentPane().add(scrollableTextArea);
1002
+ }
1003
+ public static void main(String[] args) {
1004
+
1005
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
1006
+ public void run() {
1007
+ createAndShowGUI();
1008
+ }
1009
+ });
1010
+ }
1011
+ }
1012
+
1013
+ In jruby this may look like so:
1014
+
1015
+ text_area = JTextArea.new(20, 20)
1016
+ scrollable_text_area = JScrollPane.new(text_area) # Add the scroll-pane here.
1017
+ scrollable_text_area.setHorizontalScrollBarPolicy(JScrollPane::HORIZONTAL_SCROLLBAR_ALWAYS)
1018
+ scrollable_text_area.setVerticalScrollBarPolicy(JScrollPane::VERTICAL_SCROLLBAR_ALWAYS)
1019
+
1020
+ In other words: you pass the widget that you want to see scroll-bars for,
1021
+ into JScrollPane.new() - in that case, the variable text_area.
1022
+
1023
+ The viewport that you see will display the content of the JTextArea then.
1024
+
1025
+ If the whole component fits into the viewport then the default behaviour is
1026
+ that the scroll bars disappear. This behaviour can be changed, though, via
1027
+ the horizontal and vertical policy.
1028
+
1029
+ ## Using mnemonics for JButton
1030
+
1031
+ You can use shortcut-keys, aka mnemonics, for buttons.
1032
+
1033
+ This is done in general via the method called <b>.setMnemonic()</b>.
1034
+
1035
+ Example for this:
1036
+
1037
+ button.setMnemonic(KeyEvent::VK_H)
1038
+
1039
+ VK_H means Alt+H. Alt here refers to the Alt-key. H is simply the letter
1040
+ H on the keyboard, so this means "press the alt-key as well as the h
1041
+ key".
1042
+
1043
+ If you instead want to enable Akt+H, use:
1044
+
1045
+ button.setMnemonic(KeyEvent::VK_A)
1046
+
1047
+ You can also use numbers instead. For instance:
1048
+
1049
+ button.setMnemonic(KeyEvent::VK_1)
1050
+
1051
+ This would allow you to respond to "Alt+1" key combinations. You can
1052
+ find examples related to this in the file at <b>examples/017_button_example.rb</b>.
1053
+ That file will, in the long run, contain all useful button-related
1054
+ activities that may be useful when designing applications via jruby-SWING.
1055
+
1056
+ As I find this a bit cumbersome to remember (I can't remember VK_1 or
1057
+ similar crypt names), I decided to add an API that simplifies this.
1058
+
1059
+ Usage example:
1060
+
1061
+ button.keycombo('Alt+1') # respond to alt+1
1062
+ button.keycombo('Alt+W') # respond to alt+W
1063
+
1064
+ Note that this currently (<b>January 2024</b>) only works for Alt-key
1065
+ combinations. At a later time I may extend this for more key-combinations.
1066
+
1067
+ ## Working with JTable
1068
+
1069
+ A new table can be created via:
1070
+
1071
+ JTable(int rows, int cols): Creates a table of size rows * cols.
1072
+
1073
+ Like a table with (2, 3), 2 rows, and 3 columns.
1074
+
1075
+ You can also simplify it a bit, by using
1076
+ <b>javax.swing.table.DefaultTableModel</b> via:
1077
+
1078
+ m = javax.swing.table.DefaultTableModel.new
1079
+ m.add_column("id")
1080
+ m.add_column("name")
1081
+ m.add_row(['1', "jimmy"].to_java)
1082
+ m.add_row(['2', "robert"].to_java)
1083
+
1084
+ table = JTable.new(m)
1085
+ # The fulle qualifier for JTable is javax.swing.JTable, by the way.
1086
+
1087
+ You can add java-specific objects, such as a vector, via:
1088
+
1089
+ m.add_row java.util.Vector.new('"ト', 'あ', 'い'])
1090
+
1091
+ You can also pass the columns by calling DefaultTableModel.new,
1092
+ like this:
1093
+
1094
+ m = DefaultTableModel.new(nil, ["No.", "Name", "Path"].to_java)
1095
+
1096
+ The <b>API documentation</b> for JTable can be found here:
1097
+
1098
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JTable.html
1099
+
1100
+ ## Converting an Array into Java::JavaLang:Object:
1101
+
1102
+ This can be done by calling .to_java.
1103
+
1104
+ Example for this:
1105
+
1106
+ pp ["1", "jimmy"].to_java # => #<Java::JavaLang::Object[2]: ["1", "jimmy"]>
1107
+
1108
+ ## JEditorPane()
1109
+
1110
+ <b>JEditorPane()</b> can be used to <b>display text via java-swing</b>.
1111
+
1112
+ Let's have a look at an image, how this may look:
1113
+
1114
+ <img src="https://i.imgur.com/aVioB68.png" style="margin: 1em">
1115
+
1116
+ If you need to obtain the current text stored in a JEditorPane,
1117
+ you can use the method called <b>.getText()</b>.
1118
+
1119
+ ## JComponent
1120
+
1121
+ Every <b>JComponent</b> can have one or more <b>borders</b>.
1122
+
1123
+ You can put a border around a JComponent. This is done via
1124
+ the <b>.setBorder()</b> method.
1125
+
1126
+ This method is usually combined with the <b>BorderFactory class</b>.
1127
+
1128
+ In raw Java swing, the code would look like this:
1129
+
1130
+ JPanel pane = new JPanel();
1131
+ pane.setBorder(BorderFactory.createLineBorder(Color.black));
1132
+
1133
+ ## javax.swing.border
1134
+
1135
+ This subsection may eventually contain some information about
1136
+ borders in java-swing applications.
1137
+
1138
+ ## JTextPane
1139
+
1140
+ <b>JTextPane</b> can be used to render HTML content.
1141
+
1142
+ The full scope of JTextPane is <b>javax.swing.JTextPane</b>.
1143
+
1144
+ ## Creating a MenuBar via JMenu
1145
+
1146
+ First, let's look at how a Menu (JMenu) looks in Java-Swing:
1147
+
1148
+ <img src="https://i.imgur.com/PNlkIfK.png" style="margin: 1em">
1149
+
1150
+ The primary menu bar is called <b>JMenuBar</b> in Java-Swing.
1151
+
1152
+ To then create a menu, in raw Java-Swing, the following code
1153
+ could be used:
1154
+
1155
+ JMenuBar menu_bar = new JMenuBar(); # Create a new menubar here.
1156
+ JMenu m1 = new JMenu("FILE");
1157
+ menu_bar.add(m1);
1158
+ JMenu m2 = new JMenu("Help");
1159
+ menu_bar.add(m2);
1160
+
1161
+ Or in jruby code:
1162
+
1163
+ menu_bar = JMenuBar.new
1164
+ m1 = JMenu.new("FILE")
1165
+ menu_bar.add(m1)
1166
+ m2 = JMenu.new("Help")
1167
+ menu_bar.add(m2)
1168
+
1169
+ If you use the swing_paradise gem then you can also use <<
1170
+ rather than .add(). Example:
1171
+
1172
+ menu_bar << m1
1173
+ menu_bar << m2
1174
+
1175
+ This is a bit shorter to type.
1176
+
1177
+ Take note that the constructor for <b>JMenu</b> is this:
1178
+
1179
+ JMenu(String menuTitle);
1180
+ JMenu.new(menuTitle) # This for jruby.
1181
+
1182
+ So the name of the menu entry should be given, as a <b>String</b>.
1183
+
1184
+ You can also attach mnemonics to this, such as via:
1185
+
1186
+ menu = JMenu.new('A Menu')
1187
+ menu.setMnemonic(KeyEvent.VK_A)
1188
+
1189
+ As can be seen from the above code, we first need to create a new
1190
+ <b>JMenuBar</b> - this is the first step.
1191
+
1192
+ Then, now that we have a menu-bar, we can add new menus to
1193
+ it, of class JMenu. We use the method called .add() to
1194
+ add menu-entries there.
1195
+
1196
+ Once you are done with the menu, it is time to add it. The menu
1197
+ is typically added to a <b>JFrame</b>, via the following
1198
+ API:
1199
+
1200
+ setJMenuBar(JMenuBar menuBar)
1201
+ frame.setJMenuBar(menuBar)
1202
+
1203
+ Take note that there are two distinct methods that are rather
1204
+ similar: one is called <b>.setJMenuBar</b> and the other one is
1205
+ called <b>.setMenuBar</b>. JMenuBar() is for Swing and MenuBar()
1206
+ is for AWT.
1207
+
1208
+ Individual Menu items behave like buttons.
1209
+
1210
+ If you have a need to disable an individual menu item then you
1211
+ can do so via:
1212
+
1213
+ setEnabled(boolean b)
1214
+
1215
+ Example in jruby-Swing for disabling a menu item:
1216
+
1217
+ menu_item.setEnabled(false)
1218
+
1219
+ To then bind an event to a menu-item, use <b>.addActionListener</b>.
1220
+
1221
+ Example for this:
1222
+
1223
+ first = JMenuItem.new('Item 1')
1224
+ m1.add(first)
1225
+ first.addActionListener {|event|
1226
+ puts 'Hello world!'
1227
+ }
1228
+ # Or, to exit, use this:
1229
+ first.add_action_listener { |event|
1230
+ System.exit(0) # or just exit, should be fine too.
1231
+ }
1232
+
1233
+ If you have a need to repaint the menu bar, you can use .revalidate()
1234
+ as in:
1235
+
1236
+ menu_bar.revalidate()
1237
+ menu_bar.revalidate # or this one, as ruby allows you to omit ()
1238
+
1239
+ Once you created your menu, you have to fill the submenus with
1240
+ JMenuItem entries. The following shows such an example I was
1241
+ using in January 2024:
1242
+
1243
+ open_a_local_file_entrypoint = JMenuItem.new('Open a local file', KeyEvent::VK_T)
1244
+ open_a_local_file_entrypoint.use_this_font = :hack_26
1245
+ open_a_local_file_entrypoint.addActionListener {|event|
1246
+ do_choose_a_local_file_then_read_it_in
1247
+ }
1248
+ m1.add(open_a_local_file_entrypoint)
1249
+
1250
+ So, to respond to the on-selected event, make use of .addActionListenere.
1251
+
1252
+ ## Working with JSplitPane
1253
+
1254
+ Via JSplitPane - to be found under <b>javax.swing.JSplitPane</b> - you can
1255
+ split a pane, such as splitting into a left and a right component.
1256
+
1257
+ Let's look at two images as to how <b>JSplitPane</b> looks like:
1258
+
1259
+ <img src="https://i.imgur.com/zDe6NHK.png" style="margin: 1em">
1260
+ <img src="https://i.imgur.com/ucVpEcj.png" style="margin: 1em">
1261
+
1262
+ To create a new <b>split-pane</b>, you would use the following code:
1263
+
1264
+ split_pane = JSplitPane.new(JSplitPane::VERTICAL_SPLIT)
1265
+
1266
+ You can then modify its layout, or whether it allows one-touch
1267
+ expendable behaviour:
1268
+
1269
+ split_pane.setContinuousLayout(true)
1270
+ split_pane.setOneTouchExpandable(true)
1271
+
1272
+ You can then put other widgets into it, such as a button on top:
1273
+
1274
+ button_on_top = JButton.new('A')
1275
+ split_pane.setTopComponent(button_on_top)
1276
+
1277
+ And a button on bottom:
1278
+
1279
+ button_on_bottom =JButton.new('B')
1280
+ split_pane.setBottomComponent(button_on_bottom)
1281
+
1282
+ ## Assigning Enter as the trigger key for all JButtons in a Java-Swing application
1283
+
1284
+ UIManager.put("Button.defaultButtonFollowsFocus", Boolean::TRUE)
1285
+
1286
+ ## Font, working with fonts and using fonts in a java-swing application
1287
+
1288
+ Working with fonts in a java-swing application (or jruby-swing application)
1289
+ can be a bit tricky. This paragraph here tries to gather useful information
1290
+ pertaining to this.
1291
+
1292
+ The raw Java code for creating a new font, goes like this:
1293
+
1294
+ Font use_this_font = new Font("SansSerif", Font.PLAIN, 20);
1295
+
1296
+ In jruby this would be equivalent to the following code:
1297
+
1298
+ use_this_font = Font.new('SansSerif', Font::Plain, 20)
1299
+
1300
+ Next follows a list, as example, how to handle different fonts - first
1301
+ in java-swing, then in jruby-swing:
1302
+
1303
+ widget.setFont(new Font("Times New Roman", Font.PLAIN, 12))
1304
+ widget.setFont(new Font("Hack", Font.PLAIN, 40))
1305
+
1306
+ # now in jruby:
1307
+ widget.setFont(Font.new("Times New Roman", Font::PLAIN, 12))
1308
+ widget.setFont(Font.new("Hack", Font::PLAIN, 40))
1309
+
1310
+ ## Choosing files via a GUI, through JFileChooser - file-chooser functionality
1311
+
1312
+ Let's first have a look how JFileChooser may look on WinXP:
1313
+
1314
+ <img src="https://i.imgur.com/pkEoG6T.png" style="margin: 1em">
1315
+
1316
+ You can use something like the following to get a file-chooser
1317
+ in jruby-swing:
1318
+
1319
+ file_chooser = JFileChooser.new
1320
+ # file_chooser.setFileSelectionMode(JFileChooser::DIRECTORIES_ONLY)
1321
+
1322
+ result = file_chooser.showOpenDialog(nil) # or pass true here, to show the open dialog.
1323
+ case result
1324
+ when JFileChooser::APPROVE_OPTION
1325
+ this_file = file_chooser.getSelectedFile.getAbsoluteFile.to_s
1326
+ # this_file = File.absolute_path(this_file)
1327
+ main_entry?.set_text(this_file)
1328
+ end
1329
+
1330
+ Adjust accordingly to your use case. Keep in mind that on closing, a
1331
+ file selection dialogue returns an integer value which is one of
1332
+ the following integer constants:
1333
+
1334
+ APPROVE_OPTION: indicates that the ‘Open’ or ‘Save’, in case of a
1335
+ save dialogue button of the dialogue has been
1336
+ clicked.
1337
+ CANCEL_OPTION: indicates that the ‘Cancel’ button of the dialogue
1338
+ has been clicked.
1339
+
1340
+ Note that <b>JFileChooser::APPROVE_OPTION</b> returns <b>0</b>.
1341
+
1342
+ To obtain the file that was selected, the method <b>.getSelectedFile</b>
1343
+ can be used, as shown in the code example above.
1344
+
1345
+ Since as of January 2024 you can also use UniversalWidgets.main_file?
1346
+ and UniversalWidgets.set_main_file() to keep track of the chosen file.
1347
+
1348
+ ## JDialog and dialogues in jruby-SWING
1349
+
1350
+ First, what is a dialogue?
1351
+
1352
+ A dialogue is basically a simple means, via a widget, to obtain
1353
+ information from the user. This can then be of help for user-program
1354
+ interaction.
1355
+
1356
+ Dialogues - that is, the widgets - are used when the application needs
1357
+ information from the user in order to proceed with a task or some
1358
+ other event.
1359
+
1360
+ In jruby-SWING, the primary use of dialogues happens via
1361
+ <b>JDialog</b>:
1362
+
1363
+ <b>JDialog</b> can be thought of to be <b>a pop-up window</b> that pops out
1364
+ when a message has to be displayed to the user.
1365
+
1366
+ The namespace for <b>JDialog</b> is <b>javax.swing.JDialog</b>.
1367
+
1368
+ Some dialoguses are pre-defined. For instance, a message dialogue
1369
+ can be invoked via:
1370
+
1371
+ JOptionPane.showMessageDialog(
1372
+ Component parent,
1373
+ String title,
1374
+ String message,
1375
+ int type
1376
+ );
1377
+
1378
+ More documentation pertaining to JDialog, in particular its API,
1379
+ can be seen here:
1380
+
1381
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JDialog.html
1382
+
1383
+ ## Working with JRadioButton
1384
+
1385
+ First, let's look at <b>two images</b> to see how a JRadioButton
1386
+ may look like:
1387
+
1388
+ <img src="https://i.imgur.com/E4S1VWL.png" style="margin-right: 1em">
1389
+ <img src="https://i.imgur.com/hSrhzWz.jpg" style="margin: 1em">
1390
+
1391
+ <b>JRadioButton</b>'s fully qualified namespace is
1392
+ <b>javax.swing.JRadioButton</b>. Its superclass is
1393
+ a <b>JToggleButton</b>.
1394
+
1395
+ To create a new JRadioButton via java-swing, use:
1396
+
1397
+ JRadioButton x = new JRadioButton("Foobar");
1398
+
1399
+ <b>Radio buttons</b> can be pressed and they can be grouped. They
1400
+ will stay pressed until another radio button of the group is
1401
+ pressed. A black dot appears inside the circular area if
1402
+ the button is pressed, as can be seen on the above image.
1403
+
1404
+ The text that is displayed on a radio-button can be defined
1405
+ via passing a String as the first argument, as seen in the
1406
+ above example. For sake of completion we will show how this
1407
+ is done in jruby too:
1408
+
1409
+ radio_button = JRadioButton.new('Foobar')
1410
+
1411
+ If you have a need to programmatically set that radio button
1412
+ selected or de-selected, use this method:
1413
+
1414
+ radio_button.setSelected(true) # It is now selected.
1415
+ radio_button.setSelected(false) # It is now de-selected.
1416
+
1417
+ .setActionCommand(String command) assigns the string command
1418
+ as the action command to the button. Radio buttons are not
1419
+ automatically assigned an action command. This is because
1420
+ their label is often not a text but a picture. The action
1421
+ command can be set via this method.
1422
+
1423
+ <b>.getActionCommand()</b> returns the action command
1424
+ assigned to the button.
1425
+
1426
+ Normally radio buttons are put into a <b>ButtonGroup</b>. This
1427
+ has the effect that if the user selects one radio button,
1428
+ all other radio buttons are de-selected. In other words:
1429
+ this achieves that only one radio button is actively
1430
+ selected at any given moment in time.
1431
+
1432
+ In order to group radio-buttons into a button group, we should
1433
+ first create a new instance of ButtonGroup, such as via:
1434
+
1435
+ button_group = ButtonGroup.new
1436
+
1437
+ Next, use the method <b>.add()</b> to add radio_buttons into that
1438
+ button group:
1439
+
1440
+ button_group.add(radio_button1)
1441
+ button_group.add(radio_button2)
1442
+
1443
+ The <b>API documentation</b> for <b>JRadioButton</b> can be seen here:
1444
+
1445
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JRadioButton.html
1446
+
1447
+ ## Java Swing Plaf
1448
+
1449
+ The javax.swing.plaf package contains several subpackages and related packages.
1450
+
1451
+ <b>Plaf</b> stands for <b>pluggable look and feel</b>.
1452
+
1453
+ ## Swing versus AWT
1454
+
1455
+ <b>Swing component</b> class names begin with a J. AWT components do
1456
+ not.
1457
+
1458
+ For instance, JButton is a swing-component whereas Button is an
1459
+ AWT component.
1460
+
1461
+ This distinction holds true for most components, but one exception
1462
+ is the <b>JComboBox</b>, which replaces the AWT Choice component.
1463
+
1464
+ The following table shows the AWT component and the nearest
1465
+ swing replacement:
1466
+
1467
+ AWT Component | Nearest Swing Replacement
1468
+ -------------------------------------------------
1469
+ Button | JButton
1470
+ Canvas | JPanel
1471
+ Checkbox | JCheckBox
1472
+ Checkbox in CheckboxGroup | JRadioButton in ButtonGroup
1473
+ Choice | JComboBox
1474
+ Component | JComponent
1475
+ Container | JPanel
1476
+ Label | JLabel
1477
+ List | JList
1478
+ Menu | JMenu
1479
+ MenuBar | JMenuBar
1480
+ MenuItem | JMenuItem
1481
+ Panel | JPanel
1482
+ PopupMenu | JPopupMenu
1483
+ Scrollbar | JScrollBar
1484
+ ScrollPane | JScrollPane
1485
+ TextArea | JTextArea
1486
+ TextField | JTextField
1487
+ Applet | JApplet
1488
+ Dialog | JDialog
1489
+ FileDialog | JFileChooser
1490
+ Frame | JFrame
1491
+ Window | JWindow
1492
+
1493
+ ## JPasswordField
1494
+
1495
+ JPasswordField is a specialized text field that can be used for inputting
1496
+ a password into a Swing-Application.
1497
+
1498
+ Cut and copy operations are not possible within this
1499
+ component, but text can be pasted into it.
1500
+
1501
+ On Windows it may look like this:
1502
+
1503
+ <img src="https://static.javatpoint.com/java/swing/images/java-jpasswardfield1.png" style="margin: 1em">
1504
+
1505
+ ## Potentially useful links pertaining to Java-Swing
1506
+
1507
+ https://web.mit.edu/6.005/www/sp14/psets/ps4/java-6-tutorial/components.html
1508
+ https://www.javatpoint.com/java-swing
1509
+
1510
+ CONTACT_INFORMATION