Reputation:
I am developing an image processing software (just for fun) and one of the features it has is image resizing option. Basically window pops up, with two JTextArea
components to get desired image width and height for resizing. There is also JCheckBox
for keeping Aspect ratio if user desires it. The problem is. When check box is selected and user supposedly inputs either width or height first. I want the other text area to update itself accordingly every time a change is made so it would keep AR. I have developed some code that deals with this, but it does not provide what I really want due to lack of understanding what listener to what component should I really assign.
Code:
String height, width;
if (checkBoxImage.isSelected()){
// aspect ratio = width / height
width = widthArea.getText();
height = heightArea.getText();
double aspectRatio = (double) images.get(tabbedPane.getSelectedIndex()).getWidth() / images.get(tabbedPane.getSelectedIndex()).getHeight();
/**
* to do, update width, height area
* to the closest user input
*/
if(heightArea.getText().length() != 0 && heightArea.getText().length() <= 5
&& heightArea.getText().charAt(0) != '0'){
//parsing string to integer
try{
int heightNum = Integer.parseInt(height);
int widthNum = (int) Math.round(aspectRatio * heightNum);
widthArea.setText(String.valueOf(widthNum) );
widthArea.updateUI();
frameimgSize.repaint();
}
catch(NumberFormatException e1){JOptionPane.showMessageDialog(error,e1.getMessage(),"Error", JOptionPane.ERROR_MESSAGE);}
}
//width has been entered first
else if(widthArea.getText().length() != 0 && widthArea.getText().length() <= 5 &&
widthArea.getText().charAt(0) != '0'){
try{
int widthNum = Integer.parseInt(width);
int heightNum = (int) Math.round(aspectRatio * widthNum);
heightArea.setText(String.valueOf(heightNum) );
heightArea.updateUI();
frameimgSize.repaint();
}
catch(NumberFormatException e1){JOptionPane.showMessageDialog(error,e1.getMessage(),"Error", JOptionPane.ERROR_MESSAGE);}
}
}
Upvotes: 0
Views: 90
Reputation: 3829
Is it ever valid to have non-numeric values in your width and height fields?
If not, then use JSpinners
or JFormattedTextFields
instead of JTextFields
. If so, (say for example you allow a "units" to be entered as well as width and height) you should attach a DocumentListener
to your JTextFields to monitor changes to the content of the underlying text documents. Here's an example:
widthField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
update();
}
public void removeUpdate(DocumentEvent e) {
update();
}
public void insertUpdate(DocumentEvent e) {
update();
}
// your method that handles any Document change event
public void update() {
if( aspectCheckBox1.isSelected() ) {
// parse the width and height,
// constrain the height to the aspect ratio and update it here
}
}
});
You'd then add a similar DocumentListener to your heightTextField.
Note that if you use JTextFields you need to parse their contents, read the units (where applicable) and handle NumberFormatExceptions in the case where the user enters invalid numeric values.
To answer your question about where to add your handlers...
The update of the Width should happen when there is a Document change to the Height GUI element. Similarly the update of the Height should happen when there is a document change to the Width GUI element.
You'll need to gracefully handle divide by zero errors (or restrict input to always be greater than 0), perform your calculations using doubles and preferably use Math.round()
to get the best integer values for preserving aspect.
ie:
int calculateHeight(int width, double aspect) {
if( aspect <= 0.0 ) {
// handle this error condition
}
return (int)Math.round(width / aspect);
}
For actually tracking the aspect ratio, I would store it in a member variable and add an ActionListener
to the JCheckBox... because updating the target aspect ratio on every value change of the width and height fields could result in aspect-ratio "creeping" due to integer round-off.
Here's an example on tracking your aspect every time the aspect ratio check state changes:
private double aspect = 1.0;
aspectCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
preserveAspectActionPerformed(evt);
}
});
private void preserveAspectActionPerformed(java.awt.event.ActionEvent evt) {
try {
double w = Double.parseDouble(widthField.getText());
double h = Double.parseDouble(heightField.getText());
aspect = w / h;
}
catch(NumberFormatException ex) {
// ... error occurred due to non-numeric input
// (use a JSpinner or JFormattedTextField to avoid this)
}
}
The most important thing is to avoid using the wrong input type for the job:
Hope that helps you.
Upvotes: 3
Reputation: 347184
First, I wouldn't use JTextArea
, it's meant for free form text editing (think NotePad). Instead you should, at the very least, use a JTextField
but a JSpinner
might actually even be better.
Take a look at How to Use Text Fields for more details.
Essentially, for JTextField
, you could use a ActionListener
and/or a FocusListener
to monitor for changes to the field.
This listeners will tend to be notified after the fact, that is, only once the user has finished editing fields. If you want real time feed back, you could use a DocumentListener
which will notifiy each time the underlying Document
of the field is modified, in real time.
A JSpinner
is a little more complicated as it's a component that contains an editor and controls. You can use a ChangeListener
, which will notifiy when a change to the fields model is commited. This occurs in place of the ActionListener
and FocusListener
mentioned previously, so you should only require a single listener, but won't provide real time feedback (at least, not without a lot more work)
Upvotes: 3