Find out about Cay Horstmann's GBC class, which makes grid bag easier to use. There are more details in his Book Core JavaII (vol I). This grid bag tutorial is only suitable for drinking beer to.Stephan van Hulst wrote:I tend to craft my Swing applications by hand, using BorderLayout and BoxLayout if possible, but for complex forms GridBagLayout certainly is most flexible. I'm glad to see you're getting practice by doing it by hand as well. . . .
I would go further and say that the calculator should be in a different class from all the display components.Don't extend JFrame. Your calculator uses a frame, it is not one. . . . .
Stephan van Hulst wrote:
Don't extend JFrame. Your calculator uses a frame, it is not one.
Your Fraction, CalcPanel and FractionCalc classes can be final.
Don't call pack() or setVisible() from the constructor. They can start new threads and you shouldn't start threads from constructors.
Use whole words. la, instru, fc, a, b, calc, dec, nu, deno, etc. don't mean anything. Characters don't cost anything, so write identifiers out.
Why are you resetting gridx, fill and gridwidth for the second component? They already had the intended values after setting them the first time.
You should interact with Swing components from the Event Dispatch Thread. Use SwingUtilities.invokeLater() to construct your calculator from the EDT.
You're not consequent with your imports. Why do you use the star import for java.awt and javax.swing, but not for java.awt.event?
Why does CalcPanel contain protected members?
Use Action instead of ActionListener. You can easily reuse them in multiple components, and they will all get the same name.
Remove commented-out code from your programs.
I recommend giving Fraction only one private constructor, and then provide a factory method for integers and a factory method for other fractions.
Don't overload the equals method. Instead, override equals(Object) and hashCode().
Your Fraction class doesn't use a normalized internal representation. The values of zero, one and whole can be derived from nu and deno.
Don't perform parameter checking in your gcd() method. It's private, you may assume it will be called correctly.
Stephan van Hulst wrote:
Don't reuse listeners in multiple components if you're going to differentiate their behavior based on getSource(). If you only need a partial implementation of a listener, override the adapter instead. For instance, create an anonymous FocusAdapter instead of a FocusListener.
Stephan van Hulst wrote:
Instead of using switch statements, bind an instance of an operator class to your choiceBox, and then let the currently selected item perform the operation on the operands.
Stephan van Hulst wrote:
You can probably lay out the components of your CalcPanel using some sort of loop. You're not performing parameter checking in your constructors. If you make sure that instances of fractions only exist in their simplified form, you can implement Comparable<Fraction> easily.
Please explain why. Whenever I see a display component implementing a listener, I start to get suspicious about the design. Does the Listener apply to the panel itself?Al Hobbs wrote:. . . I made CalcPanel implement Focuslistener. . . .
Al Hobbs wrote:For this I made CalcPanel implement Focuslistener. I originally changed what I had into focusadapter, but I changed it to implement instead because I couldn't figure how to give them all the same listener without reusing the listener.
I had made my own operator methods but I wasn't sure what you meant by binding a class to the box.
I'm not really sure how I would use a loop to layout the components if I only have one of each to do.
I wasn't really sure what kind of parameter checking to do. I added some checks in the actions of the buttons to check whether they will work without returning an error.
Not really sure what I'd do with comparable.
Stephan van Hulst wrote:
What is a FractionCalc? did you mean FractionCalculator? It isn't actually a calculator though, it's a class that just initializes and runs your form. Call it something like CalculatorApplication or CalculatorForm. The fractionCalc field should probably be named frame, and it should be private and final. Why does the addComponents() method require a container parameter? It can directly operate on the field. Don't let components implement listeners. Keep an instance of OnFocusEraser in your panel class. Your panel class doesn't need the num1, num2 and operation fields. Their values are already represented by the firstNumberField, secondNumberField and choiceBox. Class names should always begin with capital letters, so your abstract actions as well. Don't verify fields in your actions. Disable actions when the fields they are supposed to work with hold invalid values. You can also add instances of InputVerifier to your text fields. The pattern you use to verify input isn't actually all that robust. What if I enter a Chinese ideogram? You could make your "Decimal" button toggle between decimal and fractional notation. You can do this with the setAction() method. Your Fraction class still doesn't have a normalized state. The zero, one and whole fields are redundant. You can calculate them on the fly from the numerator and denominator. Numer doesn't mean anything. Deno doesn't mean anything. Personally, I also prefer to drop the get prefix in the case of simple properties, so I'd just call them numerator() and denominator(). Your toString() method doesn't need the zero and one properties. If the denominator is one, just return the numerator by itself. Zero and one are not interesting special cases. Don't use double to implement your equals() method. Floating point values are not exact. Instead, find the least common multiple of the two fractions.
Stephan van Hulst wrote:
Make your abstract actions anonymous, and assign an instance of them to a field of your panel. I'll give an example shortly. Instead of writing an anonymous class to create and turn on your application, you can use a lambda expression. You don't need a gcd() method. You can use BigInteger.gcd(). You may want to consider basing your entire Fraction class on BigInteger rather than int.
Al Hobbs wrote:I had written the reusable class Handlers and it worked great except that the useDecimalNotationAction had an illegal reference to the useFractionalNotationAction. The IDE solved it by basically writing what was in the Handler class. I wasn't sure the appropriate way to respond to it.
I wasn't sure about the anonymous class part of starting the application. Did you mean erasing the FractionCalculatorForm and just putting it's details into an anonymous class in CalcPanel or Fraction?
Wow, I had no idea there would already be a method built into the standard API already for finding gcd. I just kept it because it's only one method, and I like my method I wrote because it's recursive.
I had alot of trouble with disabling the buttons. At first I had it disable both buttons from shouldyieldfocus, but there was a problem because the buttons could only get re enabled by clicking a textfield.
When I used your way of making the actions, I changed the action to do nothing and change the label when the input was incorrect, so that it could be clicked again.
I had tried using documentlistener before I went the current route but I couldn't get it to work.
I was also wondering if there's a good book that has stuff about making reusable classes like the Handlers class. I honestly didn't understand it at first. Also, is there anyway to make classes like that but for different things like an inputverifier?
Consider Paul's rocket mass heater. |