jsugar

The method handling function has been added, so it's now possible to easily add buttons, with methods, and all those things, without having to bother about manually writing boilerplate code.

Author
Vngngdn
Date
July 16, 2016, 5:17 p.m.
Hash
2f8e61037413b00baea109ea8197b58d3758a9ff
Parent
9a80574732fe8211110e423a94492b42966365f4
Modified files
Window.java
anotherTest.java

Window.java

48 additions and 21 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
import java.lang.reflect.Method;
32
32
33
33
class Window {
34
34
	private JPanel panel; // The panel that contains all the components.
35
35
	private JFrame frame; // The "window" being presented to the user.
36
36
37
37
	/**
38
38
	 * Constructor of Window.
39
39
	 * By creating a new Window instance, this constructor will automatically
40
40
	 * start the initialization of the GUI. After doing so, the caller can
41
41
	 * start adding components to the window as pleased.
42
42
	 * @param title The title to be shown in the window's title bar.
43
43
	 */
44
44
	public Window() {
45
45
		this.panel = new JPanel();
46
46
		// TODO: The current title is "Hello world!" but that will become caller
47
47
		// defined soon.
48
48
		JFrame frame = new JFrame("Hello world!");
49
49
		// Makes it so that if the user clicks the X in the titlebar, the window
50
50
		// closes:
51
51
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
52
52
		//frame.getContentPane().add(lblHelloWorld); // So you use a get() in order to set() data? #JavaWTF
53
53
		frame.setContentPane(this.panel); // Connecting the component panel to the window.
54
54
		// Makes the window fit to the necessary width and height, so it can show all "subcomponents".
55
55
		frame.pack(); 	
56
56
		frame.setVisible(true); // Makes the window visible to the user.
57
57
		this.frame = frame;
58
58
	}
59
59
60
60
	/**
61
61
	 * Resizes the window to fit all components.
62
62
	 * By calling this method, the window will evaluate the currently visible
63
63
	 * components, and resize itself so that all components become properly
64
64
	 * visible.
65
65
	 */
66
66
	private void updateWindow() {
67
67
		this.frame.pack();
68
68
	}
69
69
70
70
	/**
71
71
	 * A series of tests for method and class handling.
72
72
	 * When a caller presents certain methods with data concerning reflection,
73
73
	 * the Java classes you need to use for that are quite opaque, and don't
74
74
	 * offer much safety in any way.
75
75
	 * The solution therefore, is run some validation checks, but these take up
76
76
	 * a decent amount of space in terms of LoC.
77
77
	 * This method takes care of all that. Call this function whenever data
78
78
	 * needs to be validated.
79
79
	/**
+
80
	 * @param object The class instance in where this method will be called.
+
81
	 * @return The method that could be derived from the supplied data, or null
+
82
	 * if that wasn't possible.
+
83
	 * @throws NullPointerException if either methodName or object are null
+
84
	 * pointers.
+
85
	 * @throws IllegalArgumentException if methodName is empty, or the method
+
86
	 * does not appear to be declared in the given object, or object is not a
+
87
	 * class.
+
88
	 */
+
89
	// All unchecked typecasts are safe, and the use of raw types is taken care
+
90
	// of.
+
91
	@SuppressWarnings({"unchecked","rawtypes"})
+
92
	private Method handleReflectionData(String methodName, Object object) {
+
93
		// Null pointer checking:
+
94
		if (methodName == null || object == null) {
+
95
			throw new NullPointerException("One or more of the given parameters are null pointers.");
+
96
		}
+
97
+
98
		// XXX: Some might say the next line should be in an else{} block. But
+
99
		// Scoping rules require that I'd then have to wrap the rest of the
+
100
		// method in the same else to use it.
+
101
		Class methodClass = object.getClass(); 
+
102
		if (methodName.equals("")) {
+
103
			throw new IllegalArgumentException("The given methodName was empty.");
+
104
		}
+
105
		Method method;
+
106
		try { // First: Look if there's a method without parameters.
+
107
			method = methodClass.getMethod(methodName, null);
+
108
		}
+
109
		catch (NoSuchMethodException exception) {
+
110
			try {
+
111
				// It's possible that the method requires an event parameter, so
+
112
				// check for that as well:
+
113
				Class<?>[] parameters = {java.awt.event.ActionEvent.class};
+
114
				method = methodClass.getMethod(methodName, parameters);
+
115
			}
+
116
			catch (NoSuchMethodException e) {
+
117
				throw new IllegalArgumentException("The given method does not appear in the given class. Be aware that the given method mustn't have any parameters, or only 1 parameter, which has to be of type java.awt.event.ActionEvent.");
+
118
			}
+
119
		}
+
120
		// At this stage, the given data has been validated, and we've been able
+
121
		// to retrieve the method itself.
+
122
		return method;
+
123
	}
+
124
+
125
	/**
80
126
	 * Creates a button in the GUI for interaction.
81
127
	 * This function offers a convenient way to create a button, that can be
82
128
	 * directly interacted with by the user. After creation, the button itself
83
129
	 * is returned to the caller, if he wishes to do something else with it.
84
130
	 * @param text The text that will be displayed in the button.
85
131
	 * @param action The action that will be returned to the action listener.
86
132
	 * @param methodName The name of the method that will be called when an
87
133
	 * action is triggered.
88
134
	 * @param objectInstance The object instance that contains the given method.
89
135
	 * This may only be a null pointer if triggerMethod is not an instance
90
136
	 * method.
91
137
	 * performed. This method may accept an ActionEvent parameter as its only
92
138
	 * parameter, or no parameters at all.
93
139
	 * @throws NullPointerException if triggerMethod is a null pointer, or
94
140
	 * the empty String was given.
95
141
	 * @throws IllegalArgumentException if triggerMethod has more than 1
96
142
	 * parameter, or the 1 required parameter is not of type ActionEvent.
97
143
	 * @return The button that was created.
98
144
	 * @see java.awt.event.ActionEvent
99
145
	 * @see java.lang.reflect.Method.invoke()
100
146
	 */
101
147
	public JButton createButton(String text, String action, String methodName, Object triggerObject) {
102
148
		Method triggerMethod;
103
-
		try {
104
-
			triggerMethod = triggerObject.getMethod(methodName, null);
105
-
		}
106
-
		catch (Exception e) {
107
-
			throw new IllegalArgumentException("The given method name does not exist in the given class.");
108
-
		}
109
-
110
-
+
149
111
150
		// For starters, we first assert that the given parameters are valid:
112
151
		if (text == null) {
113
152
			text = "";
114
153
		}
115
154
		if (action == null) {
116
155
			action = "";
117
156
		}
118
157
		if (triggerMethod == null) {
119
-
			throw new NullPointerException("The given method was a null pointer. All buttons need a functionality.");
120
-
		}
121
-
		Class<?>[] parameters = triggerMethod.getParameterTypes();
122
-
		if (parameters.length > 1) {
123
-
			throw new IllegalArgumentException("The given method needs more than 1 parameter, which is not allowed.");
124
-
		}
125
-
		if (parameters.length != 0) {
126
-
			if (parameters[0] != java.awt.event.ActionEvent.class) {
127
-
				throw new IllegalArgumentException("The given method has a parameter, but that parameter is not of type java.awt.event.ActionEvent.");
128
-
			}
129
-
		}
130
-
		
131
158
		// When the method gets here, everything's been validated correctly.
132
159
		JButton button = new JButton(text);
133
160
		button.setActionCommand(action);
134
161
		button.addActionListener(
135
162
				new java.awt.event.ActionListener() {
136
163
					public void actionPerformed(java.awt.event.ActionEvent event) {
137
164
						try {
138
165
							triggerMethod.setAccessible(true);
139
166
							if (parameters.length == 0) {
140
-
								// FIXME: Next line throws a warning?
+
167
								// FIXME: Next line throws a warning?
141
168
								triggerMethod.invoke(triggerObject, null);
142
169
							}
143
170
							else {
144
171
								triggerMethod.invoke(triggerObject, new Object[]{event});
145
172
							}
146
173
						}
147
174
						catch (Exception useless) {
148
175
							/*
149
176
							 * XXX: Some info on why I don't just throw said
150
177
							 * Exception to the caller:
151
178
							 * Java has this awful language constraint, which
152
179
							 * forces every damn exception that isn't a subclass
153
180
							 * of RuntimeException, to be declared in the method
154
181
							 * declaration. This tends to infect all underlying
155
182
							 * methods as well, and all that for reasons I can't
156
183
							 * comprehend. In order to keep JSugar a simple and
157
184
							 * clean library, I'll rather just handle it here,
158
185
							 * and throw a RuntimeException with appropriate
159
186
							 * details.
160
187
							 */
161
188
							throw new IllegalArgumentException("triggerMethod is not accessible from this context.");
162
189
						}
163
190
					}
164
191
				});
165
192
		this.panel.add(button);
166
193
		this.frame.pack();
167
194
		return button;
168
195
	}
169
196
170
197
	/**
171
198
	 * Ask the user for input through a dialog box.
172
199
	 * This method presents the user with an input field, that can accept
173
200
	 * textual input. The method will return the given input after the user's
174
201
	 * clicked a button to send.
175
202
	 * @param text The text/question to be asked to the user.
176
203
	 * @return A String, equal to what the user entered.
177
204
	 * @throws NullPointerException if text is a null pointer.
178
205
	 */
179
206
	public String inputDialog(String text) {
180
207
		if (text == null) {
181
208
			throw new NullPointerException("The given text/question was a null pointer.");
182
209
		}
183
210
		return JOptionPane.showInputDialog(text);
184
211
	}
185
212
186
213
	/**
187
214
	 * Give the user a dialog box.
188
215
	 * This method can be used to provide a simple dialog to the user.
189
216
	 * This will show the user the given question, after which a boolean value
190
217
	 * is returned, holding the choice.
191
218
	 * @param text The text/question to be asked to the user.
192
219
	 * @return True if the user confirms, False if he denies.
193
220
	 * @throws NullPointerException if text is a null pointer.
194
221
	 */
195
222
	public boolean confirmDialog(String text) {
196
223
		if (text == null) {
197
224
			throw new NullPointerException("The given text/question was a null pointer.");
198
225
		}
199
226
		final int ACCEPTED = 0;
200
227
		final int DENIED = 1;
201
228
		int result = this.choiceDialog(text, new String[]{"Confirm", "Deny"});
202
229
		if (result == ACCEPTED) {
203
230
			return true;
204
231
		}
205
232
		else {
206
233
			return false;
207
234
		}
208
235
	}
209
236
210
237
	/**
211
238
	 * Give the user a choice dialog box.
212
239
	 * This method gives the user a simple dialog with predefined choices.
213
240
	 * These choices are to be provided by the caller in a simple array.
214
241
	 * Tip: This method works extremely well with arbitrary created choices.
215
242
	 * That is: if the outcome of the dialog is trivial (e.g. Only 1 choice),
216
243
	 * then that value is immediately returned.
217
244
	 * @param text The text/question to be asked to the user.
218
245
	 * @param choices An array of Strings, containing the choices the user can
219
246
	 * pick.
220
247
	 * @return The index value of the picked choice, or -1 if no choices were
221
248
	 * given.
222
249
	 * @throws NullPointerException if text is a null pointer.
223
250
	 */
224
251
	public int choiceDialog(String text, String[] choices) {
225
252
		if (text == null) {
226
253
			throw new NullPointerException("The given text/question was a null pointer.");
227
254
		}
228
255
		// First: handling the trivial cases:
229
256
		if (choices.length == 0) {
230
257
			return -1;
231
258
		}
232
259
		else if (choices.length == 1) {
233
260
			return 0;
234
261
		}
235
262
		int answer = JOptionPane.CLOSED_OPTION;
236
263
		// The dialog needs to be shown again until the user has made a possible
237
264
		// choice, i.e. Chickening out using the close button is not possible
238
265
		// (Because that returns CLOSED_OPTION).
239
266
		while (answer == JOptionPane.CLOSED_OPTION) {
240
267
				JOptionPane.showOptionDialog(
241
268
					null, // The parent component. May become the panel?
242
269
					text, // The text/question to describe the goal
243
270
					"Dialog", // The text in the title bar
244
271
					JOptionPane.DEFAULT_OPTION, // The kind of available options
245
272
					JOptionPane.QUESTION_MESSAGE, // The type of message
246
273
					null, // The icon to show
247
274
					choices, // The possible choices
248
275
					choices[0] // The standard choice
249
276
					);
250
277
		}
251
278
		return answer;
252
279
	}
253
280
		
254
281
255
282
	/**
256
283
	 * Creates a label in the GUI for interaction.
257
284
	 * This function offers a convenient way to create a label, that can be
258
285
	 * directly interacted with by the user. After creation, the label itself
259
286
	 * is returned to the caller, if he wishes to do something else with it.
260
287
	 * @param text The text that will be displayed in the label.
261
288
	 * @return The label that was created.
262
289
	 */
263
290
	public JLabel createLabel(String text) {
264
291
		JLabel label = new JLabel(text);
265
292
		this.panel.add(label);
266
293
		return label;
267
294
	}
268
295
269
296
	/**
270
297
	 * Removes the given component from the GUI.
271
298
	 * This method allows its caller to remove a component from the GUI.
272
299
	 * @param component The component to be removed.
273
300
	 * @throws NoSuchElementException if the given component does not exist in
274
301
	 * the GUI.
275
302
	 * @throws NullPointerException if the given component is a null pointer.
276
303
	 */
277
304
	public void removeComponent(JComponent component) {
278
305
		int originalSize = this.panel.getComponentCount();
279
306
		this.panel.remove(component);
280
307
		int newSize = this.panel.getComponentCount();
281
308
		if (originalSize != newSize+1) {
282
309
			throw new NoSuchElementException("The given component does not exist in the GUI.");
283
310
		}
284
311
	}
285
312
}
286
313

anotherTest.java

0 additions and 2 deletions.

View changes Hide changes
1
1
import java.lang.reflect.Method;
2
2
public class anotherTest {
3
3
	public anotherTest() {
4
4
		Window window = new Window();
5
5
		JButton button = new JButton(); // Yeah, have to initialize that, because Java.
6
6
		try {
7
-
		button = window.createButton("Knopje!!", "???", "printSomething",  this);
8
7
		} catch(Exception e) {}
9
-
		try {
10
8
			Thread.sleep(1000);
11
9
		} catch (InterruptedException e){
12
10
			e.printStackTrace();
13
11
		}
14
12
		button.setText("LOL");
15
13
		System.out.println("Done.");
16
14
17
15
		System.out.println("Okay, that worked...");
18
16
	}
19
17
20
18
	public void printSomething() {
21
19
		System.out.println("Okay, I can print stuff.");
22
20
	}
23
21
}
24
22