JButton通过工具提示文本呈现无法点击

时间:2012-09-16 19:58:59

标签: java swing jbutton event-dispatch-thread

当我将工具提示文本添加到JDialog中的 JButton 组件时,按钮(实际上,两个执行类似操作的按钮)就像被禁用一样( setEnabled(false)< / em>的)。我觉得它与实际的工具提示文本没有直接关系,并且正在 EDT 的循环中做一些事情。无论如何,这是班级。

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();
    }
}

显然,如果没有上下文,那就太混乱了。这是它扩展的 Dialog 类。

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);
        }
    });
}

这里要注意的重要一点是,在 EDT 之外调用init(),并且当 setToolTipText()时,行为 ONLY em>方法被调用。在不同但结构相似的类中观察到相同的行为。

这是一个导致 EDT 出现问题的循环,还是与toolTip Text的工作方式有关? (我从来没有使用过tooltiptext而且对于swing / java来说还是新手)

需要更多信息,只需询问。

由于

2 个答案:

答案 0 :(得分:2)

首先,永远不要更新EDT之外的任何UI组件,这包括构造,您不知道组件何时会请求更新并导致重新绘制或何时将其自身附加到本机对等方。

只要您将组件添加到其中的用户界面,就可以相信您可以初始化EDT之外的组件。这当时是一种误解,Swing开发团队实际上说这是一种不好的做法

您可能希望阅读Is it safe to construct Swing/AWT widgets NOT on the Event Dispatch Thread?了解更多详情

其次,永远不要在EDT中执行任何耗时的任务,它们会阻止EDT处理绘画和事件请求,使UI看起来没有响应。

不知道你的循环运行了多长时间,这是不可能的。我可以提出的最好的建议是评论actionPerformed方法的实际主体并再次测试

答案 1 :(得分:2)

此处的问题是,您的标签orderLabel会扩展到2个按钮,updown。我添加了一个绿色边框来突出显示:

App Snapshot

按钮未被禁用,但鼠标点击被阻止,因为现在工具提示已存在覆盖MouseListener

解决方案是删除此标签的工具提示或修剪其大小,使其不与按钮重叠。