jsugar

Expanded the button creation functionality, so that it allows to bind a method to be called when calling the method, removing a lot of boilerplate code inherent to Swing.

Author
Vngngdn
Date
July 14, 2016, 7:34 p.m.
Hash
9f3e9a84cfb79ff7c5fb48b907c08f1b54cf9878
Parent
8e620b5003a81c18ce079a26eb0785f853178d67
Modified file
Window.java

Window.java

74 additions and 2 deletions.

View changes Hide changes
1
1
 * Window.java - Module to create a new window with JSugar.
2
2
 * Copyright © 2016 Maarten "Vngngdn" Vangeneugden
3
3
 * 
4
4
 * This program is free software: you can redistribute it and/or modify
5
5
 * it under the terms of the GNU General Public License as published by
6
6
 * the Free Software Foundation, either version 3 of the License, or
7
7
 * (at your option) any later version.
8
8
 * 
9
9
 * This program is distributed in the hope that it will be useful,
10
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
 * GNU General Public License for more details.
13
13
 * 
14
14
 * You should have received a copy of the GNU General Public License
15
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
16
 */
17
17
18
18
/**
19
19
 * Window class for the program.
20
20
 *
21
21
 * Window contains the necessary data and methods to present the user with what
22
22
 * he's familiar with as being a "window". To make it functional, the developer
23
23
 * can make use of a series of methods to add components to said window, remove
24
24
 * components, and so on.
25
25
 * Currently, Window also contains methods to show dialogs. This will be cleaned
26
26
 * in the near future.
27
27
 * @author Maarten Vangeneugden
28
28
 */
29
29
import javax.swing.*; // FIXME: Maybe namespacing it to "javax.swing;" is a better idea.
30
30
import java.util.NoSuchElementException;
31
31
+
32
32
33
class Window {
33
34
	private JPanel panel; // The panel that contains all the components.
34
35
	private JFrame frame; // The "window" being presented to the user.
35
36
36
37
	/**
37
38
	 * Constructor of Window.
38
39
	 * By creating a new Window instance, this constructor will automatically
39
40
	 * start the initialization of the GUI. After doing so, the caller can
40
41
	 * start adding components to the window as pleased.
41
42
	 * @param title The title to be shown in the window's title bar.
42
43
	 */
43
44
	public Window() {
44
45
		this.panel = new JPanel();
45
46
		// TODO: The current title is "Hello world!" but that will become caller
46
47
		// defined soon.
47
48
		JFrame frame = new JFrame("Hello world!");
48
49
		// Makes it so that if the user clicks the X in the titlebar, the window
49
50
		// closes:
50
51
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
51
52
		//frame.getContentPane().add(lblHelloWorld); // So you use a get() in order to set() data? #JavaWTF
52
53
		frame.setContentPane(this.panel); // Connecting the component panel to the window.
53
54
		// Makes the window fit to the necessary width and height, so it can show all "subcomponents".
54
55
		frame.pack(); 	
55
56
		frame.setVisible(true); // Makes the window visible to the user.
56
57
		this.frame = frame;
57
58
	}
58
59
59
60
60
-
+
61
	 * Resizes the window to fit all components.
+
62
	 * By calling this method, the window will evaluate the currently visible
+
63
	 * components, and resize itself so that all components become properly
+
64
	 * visible.
+
65
	 */
+
66
	private void updateWindow() {
+
67
		this.frame.pack();
+
68
	}
+
69
61
70
	/**
62
71
	 * Creates a button in the GUI for interaction.
63
72
	 * This function offers a convenient way to create a button, that can be
64
73
	 * directly interacted with by the user. After creation, the button itself
65
74
	 * is returned to the caller, if he wishes to do something else with it.
66
75
	 * @param text The text that will be displayed in the button.
67
76
	 * @param action The action that will be returned to the action listener.
68
77
	 * @return The button that was created.
+
78
	 * @param triggerObject The object instance that contains the given method.
+
79
	 * This may only be a null pointer if triggerMethod is not an instance
+
80
	 * method.
+
81
	 * performed. This method may accept an ActionEvent parameter as its only
+
82
	 * parameter, or no parameters at all.
+
83
	 * @throws NullPointerException if triggerMethod is a null pointer.
+
84
	 * @throws IllegalArgumentException if triggerMethod has more than 1
+
85
	 * parameter, or the 1 required parameter is not of type ActionEvent.
+
86
	 * @return The button that was created.
69
87
	 */
+
88
	 * @see java.lang.reflect.Method.invoke()
+
89
	 */
70
90
	public JButton createButton(String text, String action) {
71
-
		JButton button = new JButton(text);
+
91
		// For starters, we first assert that the given parameters are valid:
+
92
		if (text == null) {
+
93
			text = "";
+
94
		}
+
95
		if (action == null) {
+
96
			action = "";
+
97
		}
+
98
		if (triggerMethod == null) {
+
99
			throw new NullPointerException("The given method was a null pointer. All buttons need a functionality.");
+
100
		}
+
101
		Class<?>[] parameters = triggerMethod.getParameterTypes();
+
102
		if (parameters.length > 1) {
+
103
			throw new IllegalArgumentException("The given method needs more than 1 parameter, which is not allowed.");
+
104
		}
+
105
		if (parameters.length != 0) {
+
106
			if (parameters[0] != java.awt.event.ActionEvent.class) {
+
107
				throw new IllegalArgumentException("The given method has a parameter, but that parameter is not of type java.awt.event.ActionEvent.");
+
108
			}
+
109
		}
+
110
		
+
111
		// When the method gets here, everything's been validated correctly.
+
112
		JButton button = new JButton(text);
72
113
		button.setActionCommand(action);
73
114
		this.panel.add(button);
+
115
				new java.awt.event.ActionListener() {
+
116
					public void actionPerformed(java.awt.event.ActionEvent event) {
+
117
						try {
+
118
							if (parameters.length == 0) {
+
119
								// FIXME: Next line throws a warning?
+
120
								triggerMethod.invoke(triggerObject, null);
+
121
							}
+
122
							else {
+
123
								triggerMethod.invoke(triggerObject, new Object[]{event});
+
124
							}
+
125
						}
+
126
						catch (Exception useless) {
+
127
							/*
+
128
							 * XXX: Some info on why I don't just throw said
+
129
							 * Exception to the caller:
+
130
							 * Java has this awful language constraint, which
+
131
							 * forces every damn exception that isn't a subclass
+
132
							 * of RuntimeException, to be declared in the method
+
133
							 * declaration. This tends to infect all underlying
+
134
							 * methods as well, and all that for reasons I can't
+
135
							 * comprehend. In order to keep JSugar a simple and
+
136
							 * clean library, I'll rather just handle it here,
+
137
							 * and throw a RuntimeException with appropriate
+
138
							 * details.
+
139
							 */
+
140
							throw new IllegalArgumentException("triggerMethod is not accessible from this context.");
+
141
						}
+
142
					}
+
143
				});
+
144
		this.panel.add(button);
74
145
		return button;
+
146
		return button;
75
147
	}
76
148
77
149
	/**
78
150
	 * Ask the user for input through a dialog box.
79
151
	 * This method presents the user with an input field, that can accept
80
152
	 * textual input. The method will return the given input after the user's
81
153
	 * clicked a button to send.
82
154
	 * @param text The text/question to be asked to the user.
83
155
	 * @return A String, equal to what the user entered.
84
156
	 * @throws NullPointerException if text is a null pointer.
85
157
	 */
86
158
	public String inputDialog(String text) {
87
159
		if (text == null) {
88
160
			throw new NullPointerException("The given text/question was a null pointer.");
89
161
		}
90
162
		return JOptionPane.showInputDialog(text);
91
163
	}
92
164
93
165
	/**
94
166
	 * Give the user a dialog box.
95
167
	 * This method can be used to provide a simple dialog to the user.
96
168
	 * This will show the user the given question, after which a boolean value
97
169
	 * is returned, holding the choice.
98
170
	 * @param text The text/question to be asked to the user.
99
171
	 * @return True if the user confirms, False if he denies.
100
172
	 * @throws NullPointerException if text is a null pointer.
101
173
	 */
102
174
	public boolean confirmDialog(String text) {
103
175
		if (text == null) {
104
176
			throw new NullPointerException("The given text/question was a null pointer.");
105
177
		}
106
178
		final int ACCEPTED = 0;
107
179
		final int DENIED = 1;
108
180
		int result = this.choiceDialog(text, new String[]{"Confirm", "Deny"});
109
181
		if (result == ACCEPTED) {
110
182
			return true;
111
183
		}
112
184
		else {
113
185
			return false;
114
186
		}
115
187
	}
116
188
117
189
	/**
118
190
	 * Give the user a choice dialog box.
119
191
	 * This method gives the user a simple dialog with predefined choices.
120
192
	 * These choices are to be provided by the caller in a simple array.
121
193
	 * Tip: This method works extremely well with arbitrary created choices.
122
194
	 * That is: if the outcome of the dialog is trivial (e.g. Only 1 choice),
123
195
	 * then that value is immediately returned.
124
196
	 * @param text The text/question to be asked to the user.
125
197
	 * @param choices An array of Strings, containing the choices the user can
126
198
	 * pick.
127
199
	 * @return The index value of the picked choice, or -1 if no choices were
128
200
	 * given.
129
201
	 * @throws NullPointerException if text is a null pointer.
130
202
	 */
131
203
	public int choiceDialog(String text, String[] choices) {
132
204
		if (text == null) {
133
205
			throw new NullPointerException("The given text/question was a null pointer.");
134
206
		}
135
207
		// First: handling the trivial cases:
136
208
		if (choices.length == 0) {
137
209
			return -1;
138
210
		}
139
211
		else if (choices.length == 1) {
140
212
			return 0;
141
213
		}
142
214
		int answer = JOptionPane.CLOSED_OPTION;
143
215
		// The dialog needs to be shown again until the user has made a possible
144
216
		// choice, i.e. Chickening out using the close button is not possible
145
217
		// (Because that returns CLOSED_OPTION).
146
218
		while (answer == JOptionPane.CLOSED_OPTION) {
147
219
				JOptionPane.showOptionDialog(
148
220
					null, // The parent component. May become the panel?
149
221
					text, // The text/question to describe the goal
150
222
					"Dialog", // The text in the title bar
151
223
					JOptionPane.DEFAULT_OPTION, // The kind of available options
152
224
					JOptionPane.QUESTION_MESSAGE, // The type of message
153
225
					null, // The icon to show
154
226
					choices, // The possible choices
155
227
					choices[0] // The standard choice
156
228
					);
157
229
		}
158
230
		return answer;
159
231
	}
160
232
		
161
233
162
234
	/**
163
235
	 * Creates a label in the GUI for interaction.
164
236
	 * This function offers a convenient way to create a label, that can be
165
237
	 * directly interacted with by the user. After creation, the label itself
166
238
	 * is returned to the caller, if he wishes to do something else with it.
167
239
	 * @param text The text that will be displayed in the label.
168
240
	 * @return The label that was created.
169
241
	 */
170
242
	public JLabel createLabel(String text) {
171
243
		JLabel label = new JLabel(text);
172
244
		this.panel.add(label);
173
245
		return label;
174
246
	}
175
247
176
248
	/**
177
249
	 * Removes the given component from the GUI.
178
250
	 * This method allows its caller to remove a component from the GUI.
179
251
	 * @param component The component to be removed.
180
252
	 * @throws NoSuchElementException if the given component does not exist in
181
253
	 * the GUI.
182
254
	 * @throws NullPointerException if the given component is a null pointer.
183
255
	 */
184
256
	public void removeComponent(JComponent component) {
185
257
		int originalSize = this.panel.getComponentCount();
186
258
		this.panel.remove(component);
187
259
		int newSize = this.panel.getComponentCount();
188
260
		if (originalSize != newSize+1) {
189
261
			throw new NoSuchElementException("The given component does not exist in the GUI.");
190
262
		}
191
263
	}
192
264
}
193
265