Reputation: 315
When I added tooltip text to a JButton component in my JDialog, the button (Actually, two buttons that do similar things) acts as if it is disabled (setEnabled(false)). I have a feeling it is not directly related to the actual tooltip text, and is doing something in a loop on the EDT. Anyways, here is the class.
package org.carroll.dialogs.editing;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JTextField;
import org.carroll.data.school.AllCourses;
import org.carroll.data.settings.Settings;
import org.carroll.internal.InternalPanel;
import org.carroll.school.Course;
import org.carroll.utils.Logging;
import org.swing.Dialog;
import org.swing.Listeners;
import org.swing.dialogs.messages.ErrorMessage;
/**
* Dialog for editing a course. Is custom to editing courses.
*
* @author Joel Gallant
*/
public class EditCourseDialog extends Dialog {
JButton save, done, cancel;
KeyListener doneListener = new Listeners.DoneListener() {
@Override
public void enterPressed() {
if (!done.isFocusOwner()) {
done.doClick();
}
}
};
static Course currentCourse;
/**
* Creates dialog with default course selected.
*/
public EditCourseDialog() {
super("Edit Course");
currentCourse = AllCourses.getInstance().get(0);
}
/**
* Creates dialog that selects a course by default.
*
* @param startingSelection default selection
*/
public EditCourseDialog(String startingSelection) {
super("Edit Course");
try {
currentCourse = AllCourses.getInstance().get(startingSelection);
} catch (NoSuchFieldException ex) {
currentCourse = AllCourses.getInstance().get(0);
}
}
public EditCourseDialog(Course startingCourse) {
super("Edit Course");
currentCourse = startingCourse;
}
void editCourse(String name, int credits, int units, int[] semester, int order) {
Logging.log(name + " edited.");
currentCourse.setName(name);
currentCourse.setCredits(credits);
currentCourse.setUnits(units);
currentCourse.setSemester(semester);
currentCourse.setOrder(order);
if (!AllCourses.getInstance().getElements().contains(currentCourse)) {
AllCourses.getInstance().add(currentCourse);
}
InternalPanel.COURSES.refresh();
}
@Override
protected void init() {
GridBagLayout layout = new GridBagLayout();
setLayout(layout);
setPreferredSize(new Dimension(385, 280));
Integer[] creditArray = {1, 3, 5};
String[] semesterArray;
try {
semesterArray = new String[Integer.parseInt(Settings.getInstance().get("Semesters").getValue()) + 1];
for (int x = 0; x < Integer.parseInt(Settings.getInstance().get("Semesters").getValue()); x++) {
semesterArray[x] = String.valueOf(x + 1);
}
semesterArray[semesterArray.length - 1] = "Year";
} catch (NoSuchFieldException ex) {
semesterArray = new String[2];
semesterArray[0] = "1";
semesterArray[1] = "2";
}
final JComboBox<String> course = new JComboBox<>(AllCourses.getInstance().getNames());
final JLabel nameLabel = new JLabel("Name"),
creditsLabel = new JLabel("Credits"),
unitsLabel = new JLabel("Units"),
semesterLabel = new JLabel("Semester"),
orderLabel = new JLabel("Order");
final JTextField name = new JTextField(),
units = new JTextField(),
order = new JTextField();
final JButton up = new JButton("↑"),
down = new JButton("↓");
final JComboBox<Integer> credits = new JComboBox<>(creditArray);
final JComboBox<String> semester = new JComboBox<>(semesterArray);
save = new JButton("Save");
done = new JButton("Done");
cancel = new JButton("Cancel");
course.setSelectedItem(currentCourse.getName());
String orderExpl = "<html>The order you are doing the courses in during the semester. "
+ "<br>It starts at 1, and goes on. (Do not make multiple courses with same order)</html>";
orderLabel.setToolTipText(orderExpl);
order.setToolTipText(orderExpl);
up.setToolTipText(orderExpl);
down.setToolTipText(orderExpl);
name.setText(currentCourse.getName());
name.setCaretPosition(0);
units.setText(String.valueOf(currentCourse.getUnits()));
credits.setSelectedItem(currentCourse.getCredits());
semester.setSelectedItem(currentCourse.getSemesters().length > 1 ? "Year" : String.valueOf(currentCourse.getSemesters()[0]));
order.setText(String.valueOf(currentCourse.getOrder()));
up.setFont(up.getFont().deriveFont(Font.BOLD, (float) 14));
down.setFont(up.getFont());
course.addKeyListener(doneListener);
name.addKeyListener(doneListener);
units.addKeyListener(doneListener);
credits.addKeyListener(doneListener);
semester.addKeyListener(doneListener);
order.addKeyListener(doneListener);
done.addKeyListener(doneListener);
cancel.addKeyListener(doneListener);
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int[] semesters;
if (semester.getSelectedItem().equals("Year")) {
semesters = new int[Integer.parseInt(Settings.getInstance().get("Semesters").getValue())];
for (int x = 0; x < semesters.length; x++) {
semesters[x] = x + 1;
}
} else {
semesters = new int[]{Integer.parseInt(semester.getSelectedItem().toString())};
}
editCourse(name.getText(), Integer.parseInt(credits.getSelectedItem().toString()),
Integer.parseInt(units.getText()), semesters,
Integer.parseInt(order.getText()));
} catch (NumberFormatException ex) {
new ErrorMessage(ex, "A number was entered wrong").createAndViewGUI();
} catch (NoSuchFieldException ex) {
new ErrorMessage(ex).createAndViewGUI();
}
}
});
done.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int[] semesters;
if (semester.getSelectedItem().equals("Year")) {
semesters = new int[Integer.parseInt(Settings.getInstance().get("Semesters").getValue())];
for (int x = 0; x < semesters.length; x++) {
semesters[x] = x + 1;
}
} else {
semesters = new int[]{Integer.parseInt(semester.getSelectedItem().toString())};
}
editCourse(name.getText(), Integer.parseInt(credits.getSelectedItem().toString()),
Integer.parseInt(units.getText()), semesters,
Integer.parseInt(order.getText()));
dispose();
} catch (NumberFormatException ex) {
new ErrorMessage(ex, "A number was entered wrong").createAndViewGUI();
} catch (NoSuchFieldException ex) {
new ErrorMessage(ex).createAndViewGUI();
}
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
up.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
AllCourses.getInstance().move(currentCourse.getName(), true);
order.setText(String.valueOf(currentCourse.getOrder()));
InternalPanel.COURSES.refresh();
}
});
down.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
AllCourses.getInstance().move(currentCourse.getName(), false);
order.setText(String.valueOf(currentCourse.getOrder()));
InternalPanel.COURSES.refresh();
}
});
course.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
try {
currentCourse = AllCourses.getInstance().get(course.getSelectedItem().toString());
} catch (NoSuchFieldException ex) {
currentCourse = AllCourses.getInstance().get(course.getSelectedIndex());
}
name.setText(currentCourse.getName());
units.setText(String.valueOf(currentCourse.getUnits()));
credits.setSelectedItem(currentCourse.getCredits());
semester.setSelectedItem(currentCourse.getSemesters().length > 1 ? "Year" : String.valueOf(currentCourse.getSemesters()[0]));
order.setText(String.valueOf(currentCourse.getOrder()));
}
});
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(5, 8, 5, 8);
constraints.weightx = 1;
constraints.weighty = 1;
constraints.gridwidth = 4;
layout.addLayoutComponent(course, constraints);
constraints.gridy = 1;
constraints.gridwidth = 1;
layout.addLayoutComponent(nameLabel, constraints);
constraints.gridx = 1;
constraints.gridwidth = 3;
layout.addLayoutComponent(name, constraints);
constraints.gridy = 2;
constraints.gridx = 0;
constraints.gridwidth = 1;
layout.addLayoutComponent(creditsLabel, constraints);
constraints.gridx = 1;
constraints.gridwidth = 3;
layout.addLayoutComponent(credits, constraints);
constraints.gridx = 0;
constraints.gridy = 3;
constraints.gridwidth = 1;
layout.addLayoutComponent(unitsLabel, constraints);
constraints.gridx = 1;
constraints.gridwidth = 3;
layout.addLayoutComponent(units, constraints);
constraints.gridy = 4;
constraints.gridx = 0;
constraints.gridwidth = 1;
layout.addLayoutComponent(semesterLabel, constraints);
constraints.gridx = 1;
constraints.gridwidth = 3;
layout.addLayoutComponent(semester, constraints);
constraints.gridy = 5;
constraints.gridx = 0;
layout.addLayoutComponent(orderLabel, constraints);
constraints.gridx = 1;
constraints.gridwidth = 1;
layout.addLayoutComponent(up, constraints);
constraints.gridx = 2;
layout.addLayoutComponent(down, constraints);
constraints.gridx = 3;
layout.addLayoutComponent(order, constraints);
constraints.gridy = 6;
constraints.gridx = 0;
layout.addLayoutComponent(save, constraints);
constraints.gridx = 1;
constraints.gridwidth = 2;
layout.addLayoutComponent(done, constraints);
constraints.gridx = 3;
constraints.gridwidth = 1;
layout.addLayoutComponent(cancel, constraints);
add(course);
add(nameLabel);
add(name);
add(creditsLabel);
add(credits);
add(unitsLabel);
add(units);
add(semesterLabel);
add(semester);
add(orderLabel);
add(up);
add(down);
add(order);
add(save);
add(done);
add(cancel);
}
@Override
public void createAndViewGUI() {
if (currentCourse != null) {
super.createAndViewGUI();
} else {
new ErrorMessage(new NoSuchFieldException("No courses"), "No courses to edit").createAndViewGUI();
}
}
Obviously that is pretty confusing without context. This is the Dialog class it extends.
package org.swing;
import java.awt.Component;
import java.awt.event.WindowEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import org.carroll.dialogs.MainFrame;
/**
* Basic interface for all user dialogs. Extends {@link JFrame}.
*
* @author Joel Gallant
*/
public abstract class Dialog extends JDialog {
Component c = null;
/**
* Creates a basic dialog that disposes on closing.
*
*/
public Dialog() {
super(MainFrame.getInstance());
}
/**
* Creates a basic dialog that disposes on closing.
*
* @param location relative position of the window
*/
public Dialog(Component location) {
this();
this.c = location;
}
/**
* Creates a basic dialog that disposes on closing.
*
* @param title title of the dialog
*/
public Dialog(String title) {
super(MainFrame.getInstance(), title);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
/**
* Creates a basic dialog that disposes on closing.
*
* @param title title of the dialog
* @param location relative position of the window
*/
public Dialog(String title, Component location) {
super(MainFrame.getInstance(), title);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
this.c = location;
}
/**
* Creates a basic dialog which follows the default close operation given in
* the parameter.
*
* @param title title of the dialog
* @param defaultCloseOperation default closing operation of the window
*/
public Dialog(String title, int defaultCloseOperation) {
super(MainFrame.getInstance(), title);
setDefaultCloseOperation(defaultCloseOperation);
}
/**
* Creates a basic dialog which follows the default close operation given in
* the parameter.
*
* @param title title of the dialog
* @param defaultCloseOperation default closing operation of the window
* @param location relative position of the window
*/
public Dialog(String title, int defaultCloseOperation, Component location) {
this(title, defaultCloseOperation);
this.c = location;
}
/**
* Initializes everything needed to display the GUI.
*/
protected abstract void init();
@Override
public void dispose() {
super.dispose();
dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSED));
}
/**
* Create all necessary components of the dialog and display it.
*/
public void createAndViewGUI() {
init();
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
pack();
setLocationRelativeTo(c);
setVisible(true);
}
});
}
The important thing to note here is that init() is called outside of the EDT and that the behaviour ONLY happens when the setToolTipText() method is called. The same behaviour is observed in a different, but similarly structured class.
Is this a loop causing a problem in the EDT or is it related to how toolTip Text works? (I have never used tooltiptext and am pretty new to swing / java)
Any more info needed, just ask.
Thanks
Upvotes: 1
Views: 755
Reputation: 159754
The problem here is that your label orderLabel
expands over the 2 buttons, up
and down
. I've added a green border to highlight:
The buttons are not disabled but mouse clicks are blocked due to the fact that there is an overriding MouseListener
now in place for the tooltip.
The solution is to either remove the tooltip for this label or trim back its size such that it doesn't overlap the buttons.
Upvotes: 2
Reputation: 347194
Firstly, never update any UI component outside the EDT
, this includes construction, you have no idea when a component will request to be updated and cause a repaint or when it at actually attach itself to a native peer.
There use to be a believe that you could initialize components outside the EDT
, so long as you added them to the UI within it. This was a misconception at the time and the Swing dev team actually stated that this was a bad practice
You might like to read Is it safe to construct Swing/AWT widgets NOT on the Event Dispatch Thread? for more details
Secondly, never perform any time consuming tasks in the EDT
, they will prevent the EDT
from processing paint and event requests, making the UI appear non responsive.
Without knowing how long you loops are running, it's impossible to say. The best suggestion I can make is to comment out the actually bodies of the actionPerformed
methods and test it again
Upvotes: 2