Редактор ячеек JTree получает щелчки мыши по-разному в зависимости от ОС

Я создал фреймворк рендерера / редактора древовидных ячеек, который по общему признанию немного хакерский, но он прекрасно работает в Windows и Linux. Изображение ниже иллюстрирует пример установки.

введите описание изображения здесь

Цель состоит в том, что если пользователь нажимает на изображение (цифра) 1 или 2, то приложение отвечает на этот щелчок, но не выбирает строку дерева. Если пользователь нажимает на текст один или два, приложение отвечает на этот щелчок и выбирает строку дерева. То, как я это реализовал, опять-таки немного глупо. В основном, когда пользователь нажимает на строку дерева, отображается компонент редактора (который выглядит идентично компоненту визуализации), а компонент редактора имеет прослушиватель мыши, который может определить, где пользователь щелкнул в строке.

Тот факт, что это работает в Windows/Linux, основывается на чем-то, на что я всегда думал, на что мне полагалось надуманно. По сути, если вы щелкнете строку один раз, этот единственный щелчок приведет к тому, что оба (а) вызовут редактор и (б) активируют слушателя мыши на компоненте редактора. Я так хочу! Однако, когда вы пытаетесь запустить приложение на Mac OSX (10.6.2, если это имеет значение), вышеупомянутое ошибочное предположение больше не выполняется. В любое время, когда вы хотите взаимодействовать с деревом, вы должны щелкнуть дважды (один раз, чтобы активировать редактор, и снова, чтобы активировать прослушиватель мыши).

SSCCE ниже может воспроизвести поведение. Конечно, если у вас нет OSX, вы не можете воспроизвести нежелательное поведение, но, возможно, вы все равно можете порекомендовать более разумный способ для достижения моей цели. Смотрите консоль для sysout в сообщениях указывалось, что происходит, когда вы нажимаете на различные части дерева.

Да, и SSCCE ссылается на эти два изображения:

изображение 1ямге 2

package TreeTest;

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.EventObject;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

@SuppressWarnings("serial")
public class TreeTest extends JComponent {

    private JFrame frame;
    private DefaultTreeModel treeModel;
    private DefaultMutableTreeNode root;
    private JTree tree;

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(
                UIManager.getSystemLookAndFeelClassName());
        } catch (Throwable e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TreeTest window = new TreeTest();
                    window.frame.setVisible(true);
                    window.frame.requestFocusInWindow();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TreeTest() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame("Tree Test");
        frame.setBounds(400, 400, 250, 150);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        root = new DefaultMutableTreeNode("root");
        treeModel = new DefaultTreeModel(root);
        tree = new JTree(treeModel);
        tree.setEditable(true);
        tree.getSelectionModel().setSelectionMode(
            TreeSelectionModel.SINGLE_TREE_SELECTION);
        tree.setRootVisible(false);
        tree.setShowsRootHandles(false);
        tree.setCellRenderer(new TreeRenderer());
        tree.setCellEditor(new TreeEditor());
        tree.putClientProperty("JTree.lineStyle", "None");
        tree.setBackground(Color.white);

        treeModel.insertNodeInto(new DefaultMutableTreeNode("two"), root, 0);
        treeModel.insertNodeInto(new DefaultMutableTreeNode("one"), root, 0);

        TreeNode[] nodes = treeModel.getPathToRoot(root);
        tree.expandPath(new TreePath(nodes));
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                System.out.println("SELECTION CHANGED!");
            }
        });

        frame.getContentPane().add(tree);
    }

    public class TreeComponent extends JPanel {

        public TreeComponent(JLabel numIcon, JLabel numText) {
            this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
            this.add(numIcon);
            this.add(numText);
        }
    }

    public class TreeRenderer implements TreeCellRenderer {

        private ImageIcon oneIcon;
        private ImageIcon twoIcon;

        public TreeRenderer() {
            try {
                oneIcon = new ImageIcon(ImageIO.read(
                    new URL("http://i.imgur.com/HtHJkfI.png")));
                twoIcon = new ImageIcon(ImageIO.read(
                    new URL("http://i.imgur.com/w5jAp5c.png")));
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {
            JLabel numIcon = new JLabel();
            numIcon.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            numIcon.setAlignmentY(JLabel.CENTER_ALIGNMENT);
            numIcon.setBorder(new EmptyBorder(0, 0, 0, 4));

            JLabel numText = new JLabel();

            TreeComponent comp = new TreeComponent(numIcon, numText);

            String str = (String) ((DefaultMutableTreeNode) value).getUserObject();
            if (str.equals("one")) {
                numIcon.setIcon(oneIcon);
                numText.setText("one");
            } else if (str.equals("two")) {
                numIcon.setIcon(twoIcon);
                numText.setText("two");
            }

            numText.setOpaque(true);
            if (selected) {
                numText.setBackground(new Color(209, 230, 255));
                numText.setBorder(new LineBorder(
                    new Color(132, 172, 221), 1, false));
            } else {
                numText.setBackground(Color.white);
                numText.setBorder(new LineBorder(Color.white, 1, false));
            }
            comp.setFocusable(false);
            comp.setBackground(Color.white);
            return comp;
        }
    }

    public class TreeEditor implements TreeCellEditor {

        private TreeRenderer rend;
        private TreeComponent editorComponent;
        private JTree tree;
        private DefaultTreeModel treeModel;
        private DefaultMutableTreeNode node;
        private String str;

        public TreeEditor() {
            rend = new TreeRenderer();
        }

        @Override
        public Component getTreeCellEditorComponent(
            final JTree tree, final Object value, boolean isSelected,
            boolean expanded, boolean leaf, int row) {
            this.tree = tree;
            treeModel = (DefaultTreeModel) tree.getModel();
            node = (DefaultMutableTreeNode) value;
            Object userObject = node.getUserObject();
            this.str = (String) userObject;

            TreeNode[] nodes = treeModel.getPathToRoot(node);
            final TreePath path = new TreePath(nodes);

            editorComponent = (TreeComponent) rend.getTreeCellRendererComponent(
                tree, value, isSelected, expanded, leaf, row, false);
            editorComponent.addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent e) {
                    TreeEditor.this.stopCellEditing();
                    int x = e.getX();
                    if (x >= 0 && x <= 16) {
                        System.out.println(
                            "you clicked the image for row " + str);
                    } else if (x > 16) {
                        System.out.println(
                            "you clicked the text for row " + str);
                        tree.setSelectionPath(path);
                    }
                }
            });
            return editorComponent;
        }

        @Override
        public boolean isCellEditable(EventObject anEvent) {
            return true;
        }

        @Override
        public boolean shouldSelectCell(EventObject anEvent) {
            return false;
        }

        @Override
        public boolean stopCellEditing() {
            tree.cancelEditing();
            return false;
        }

        @Override
        public Object getCellEditorValue() {
            return null;
        }

        @Override
        public void cancelCellEditing() {
        }

        @Override
        public void addCellEditorListener(CellEditorListener l) {
        }

        @Override
        public void removeCellEditorListener(CellEditorListener l) {
        }
    }
}

3 ответа

Решение

Краткий обзор того, как реализовать сложные cellEditors. Предполагается, что все интерактивные элементы редактора действительно редактируют свойство userObject узла - как в случае полного кода OP.

Сотрудники

  • фиктивный объект данных с несколькими свойствами
  • средство визуализации с несколькими дочерними элементами, каждое из которых привязано к одному свойству объекта данных
  • редактор, который использует "живой" экземпляр компонента рендеринга, то есть добавляет слушателей для соответствия контракту редактора по мере необходимости

Некоторый код (очевидно, не пригодный для использования в реальных условиях, просто чтобы понять идею:)

public static class ViewProvider extends AbstractCellEditor 
    implements TreeCellEditor, TreeCellRenderer {

    private JCheckBox firstBox;
    private JButton colorButton;
    private JComponent nodePanel;
    private JButton nameButton;

    private Data data;
    private boolean ignore;

    public ViewProvider(boolean asEditor) {
        initComponents();
        if (asEditor)
          installListeners();
    }

    protected void initComponents() {
        nodePanel = new JPanel();
        nodePanel.setOpaque(false);
        firstBox = new JCheckBox();
        colorButton = new JButton();
        // if we need something clickable use something ... clickable :-)
        nameButton = new JButton();
        nameButton.setContentAreaFilled(false);
        nameButton.setOpaque(true);
        nameButton.setBorderPainted(false);
        nameButton.setMargin(new Insets(0, 0, 0, 0));
        nodePanel.add(firstBox);
        nodePanel.add(colorButton);
        nodePanel.add(nameButton);
    }

    protected void installListeners() {
        ActionListener cancel = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                cancelCellEditing();
            }

        };
        nameButton.addActionListener(cancel);
        ActionListener stop = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                stopCellEditing();
            }

        };
        firstBox.addActionListener(stop);
        // Note: code for using a button to trigger opening a dialog
        // is in the tutorial, should replace this
        colorButton.addActionListener(stop);
    }

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {
        Data data = (Data) ((DefaultMutableTreeNode) value).getUserObject();
        firstBox.setSelected(data.isVisible);
        colorButton.setBackground(data.color);
        nameButton.setText(data.name);
        nameButton.setBackground(selected ? Color.YELLOW : tree.getBackground());
        nameButton.setFont(tree.getFont());
        return nodePanel;
    }

    @Override
    public Component getTreeCellEditorComponent(JTree tree, Object value,
            boolean isSelected, boolean expanded, boolean leaf, int row) {
        // copy to not fiddle with the original
        data = new Data((Data) ((DefaultMutableTreeNode) value).getUserObject());
        ignore = true;
        getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, false);
        ignore = false;
        return nodePanel;
    }

    @Override
    public Object getCellEditorValue() {
        return data;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        // at this point the editing component is added to the tree
        // and the mouse coordinates still in tree coordinates
        if (anEvent instanceof MouseEvent) {
            MouseEvent me = (MouseEvent) anEvent;
            Point loc = SwingUtilities.convertPoint(me.getComponent(), 
                    me.getPoint(), nodePanel);
            return loc.x >= nameButton.getX();
        }
        return false;
    }

    @Override
    public boolean stopCellEditing() {
        if (ignore) return false;
        // real-world data will have setters
        data.isVisible = firstBox.isSelected();
        return super.stopCellEditing();
    }

    @Override
    public void cancelCellEditing() {
        if (ignore) return;
        data = null;
        super.cancelCellEditing();
    }

}

// simple Data - obviously not for production 
public static class Data {
    boolean isVisible;
    Color color;
    String name;

    public Data(boolean isVisible, Color color,
            String name) {
        this.isVisible = isVisible;
        this.color = color;
        this.name = name;
    }

    /**
     * A copy constructor to allow editors to manipulate its
     * properties without changing the original.
     * 
     * @param original
     */
    public Data(Data original) {
        this.isVisible = original.isVisible;
        this.color = original.color;
        this.name = original.name;
    }
}

// usage:
DefaultMutableTreeNode root = new DefaultMutableTreeNode(
    new Data(true, Color.RED, "someName"));
root.add(new DefaultMutableTreeNode(new Data(true, Color.GREEN, "other")));
root.add(new DefaultMutableTreeNode(new Data(false, Color.BLUE, "whatagain")));
root.add(new DefaultMutableTreeNode(new Data(false, Color.YELLOW, "dummy")));

JTree tree = new JTree(root);
tree.setCellRenderer(new ViewProvider(false));
tree.setCellEditor(new ViewProvider(true));
tree.setEditable(true);

Я не уверен, что понимаю требование, но приведенный ниже пример добавляет удобную привязку клавиш и работает с любым подходом, выполняемым одним щелчком, показанным здесь. Я решил переопределить canEditImmediately(), как предполагает Клеопатра, при условии ее предостережения относительно удобства использования.

изображение дерева

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.EventObject;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellEditor;
import javax.swing.tree.DefaultTreeCellRenderer;

/**
 * @see https://stackru.com/a/15738813/230513
 * @see https://stackru.com/q/15625424/230513
 */
public class Test {

    private static Icon one;
    private static Icon two;

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JTree tree = new JTree();
        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }
        final TreeRenderer renderer = new TreeRenderer();
        tree.setCellRenderer(renderer);
        tree.setCellEditor(new TreeEditor(tree, renderer));
        tree.setEditable(true);
        tree.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "startEditing");
        f.add(new JScrollPane(tree));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class TreeRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean sel, boolean exp, boolean leaf, int row, boolean hasFocus) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
            String s = node.getUserObject().toString();
            if ("colors".equals(s)) {
                setOpenIcon(one);
                setClosedIcon(one);
            } else if ("sports".equals(s)) {
                setOpenIcon(two);
                setClosedIcon(two);
            } else {
                setOpenIcon(getDefaultOpenIcon());
                setClosedIcon(getDefaultClosedIcon());
            }
            super.getTreeCellRendererComponent(
                tree, value, sel, exp, leaf, row, hasFocus);
            return this;
        }
    }

    private static class TreeEditor extends DefaultTreeCellEditor {

        public TreeEditor(JTree tree, DefaultTreeCellRenderer renderer) {
            super(tree, renderer);
        }

        @Override
        public Component getTreeCellEditorComponent(JTree tree, Object value,
            boolean isSelected, boolean exp, boolean leaf, int row) {
            Component c = super.getTreeCellEditorComponent(
                tree, value, isSelected, exp, leaf, row);
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
            String s = node.getUserObject().toString();
            if ("colors".equals(s)) {
                editingIcon = one;
            } else if ("sports".equals(s)) {
                editingIcon = two;
            }
            return c;
        }

        @Override
        protected boolean canEditImmediately(EventObject event) {
            if ((event instanceof MouseEvent)
                && SwingUtilities.isLeftMouseButton((MouseEvent) event)) {
                MouseEvent me = (MouseEvent) event;

                return ((me.getClickCount() >= 1)
                    && inHitRegion(me.getX(), me.getY()));
            }
            return (event == null);
        }
    }

    public static void main(String[] args) throws Exception {
        one = new ImageIcon(ImageIO.read(
            new URL("http://i.imgur.com/HtHJkfI.png")));
        two = new ImageIcon(ImageIO.read(
            new URL("http://i.imgur.com/w5jAp5c.png")));
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test().display();
            }
        });
    }
}

Я придумал что-то, что создает желаемое поведение и не использует TreeCellEditor совсем. Вместо этого дерево недоступно для редактирования и создается с пользовательским расширением JTree у которого есть processMouseEvent переопределены. Я получил эту идею здесь.

Кажется, что он работает идеально, но все же он немного хакерский (он выполняет цикл вычислений, чтобы определить, где находится начало древовидной ячейки, поскольку это может варьироваться в зависимости от отступа). Также я в значительной степени отключен mouseClicked а также mouseReleased типа событий, и я контролирую JTreeMod только с mousePressed События. Не уверен, что это укусит меня позже или это плохая практика, но мне не нравился мой пользовательский код, запускаемый 3 раза подряд для всех событий. Я также еще не смог протестировать на ОС, отличной от Windows.

Вот вывод консоли после нажатия, последовательно (1) изображение одно (2) текст одно (3) изображение два (4) текст два. Опять же, это прекрасно реализует мое желаемое поведение.

you clicked the image for row 1. this was detected, but no selection will happen!
you clicked the text for row 1. this was detected, and selection WILL happen!
SELECTION CHANGED!
you clicked the image for row 2. this was detected, but no selection will happen!
you clicked the text for row 2. this was detected, and selection WILL happen!
SELECTION CHANGED!

А вот и новый SSCCE:

package TreeTest;

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

@SuppressWarnings("serial")
public class TreeTest2 extends JComponent {

    private JFrame frame;
    private DefaultTreeModel treeModel;
    private DefaultMutableTreeNode root;
    private JTreeMod tree;

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(
                UIManager.getSystemLookAndFeelClassName());
        } catch (Throwable e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TreeTest2 window = new TreeTest2();
                    window.frame.setVisible(true);
                    window.frame.requestFocusInWindow();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TreeTest2() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame("Tree Test");
        frame.setBounds(400, 400, 250, 150);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        root = new DefaultMutableTreeNode("root");
        treeModel = new DefaultTreeModel(root);
        tree = new JTreeMod(treeModel);
        tree.setEditable(false);
        tree.getSelectionModel().setSelectionMode(
            TreeSelectionModel.SINGLE_TREE_SELECTION);
        tree.setRootVisible(false);
        tree.setShowsRootHandles(true);
        tree.setCellRenderer(new TreeRenderer());
        tree.putClientProperty("JTree.lineStyle", "None");
        tree.setBackground(Color.white);

        DefaultMutableTreeNode one = new DefaultMutableTreeNode("one");
        DefaultMutableTreeNode two = new DefaultMutableTreeNode("two");

        treeModel.insertNodeInto(one, root, 0);
        treeModel.insertNodeInto(two, one, 0);

        TreeNode[] nodes = treeModel.getPathToRoot(root);
        tree.expandPath(new TreePath(nodes));
        nodes = treeModel.getPathToRoot(one);
        tree.expandPath(new TreePath(nodes));
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                System.out.println("SELECTION CHANGED!");
            }
        });

        frame.getContentPane().add(tree);
    }

    public class TreeRenderer implements TreeCellRenderer {

        private ImageIcon oneIcon;
        private ImageIcon twoIcon;

        public TreeRenderer() {
            try {
                oneIcon = new ImageIcon(ImageIO.read(
                        new URL("http://i.imgur.com/HtHJkfI.png")));
                twoIcon = new ImageIcon(ImageIO.read(
                        new URL("http://i.imgur.com/w5jAp5c.png")));
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {
            JLabel numIcon = new JLabel();
            numIcon.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            numIcon.setAlignmentY(JLabel.CENTER_ALIGNMENT);
            numIcon.setBorder(new EmptyBorder(0, 0, 0, 4));

            JLabel numText = new JLabel();

            JPanel comp = new JPanel();
            comp.setLayout(new BoxLayout(comp, BoxLayout.X_AXIS));
            comp.add(numIcon);
            comp.add(numText);

            String str = (String) ((DefaultMutableTreeNode) value).getUserObject();
            if (str.equals("one")) {
                numIcon.setIcon(oneIcon);
                numText.setText("one");
            } else if (str.equals("two")) {
                numIcon.setIcon(twoIcon);
                numText.setText("two");
            }

            numText.setOpaque(true);
            if (selected) {
                numText.setBackground(new Color(209, 230, 255));
                numText.setBorder(new LineBorder(
                    new Color(132, 172, 221), 1, false));
            } else {
                numText.setBackground(Color.white);
                numText.setBorder(new LineBorder(Color.white, 1, false));
            }
            comp.setFocusable(false);
            comp.setBackground(Color.white);
            return comp;
        }
    }

    public class JTreeMod extends JTree {
        public JTreeMod(DefaultTreeModel treeModel) {
            super(treeModel);
        }

        @Override
        protected void processMouseEvent(MouseEvent e) {
            int type = e.getID();
            if (type == MouseEvent.MOUSE_CLICKED || type == MouseEvent.MOUSE_RELEASED) {
                // do nothing
            } else if (type == MouseEvent.MOUSE_PRESSED) {
                int x = e.getX();
                int y = e.getY();

                int row = this.getRowForLocation(x, y);
                if (row == -1) {
                    super.processMouseEvent(e);
                    return;
                }

                int xOffset = x;
                int row1 = row;
                while (row1 == row) {
                    xOffset--;
                    row1 = this.getRowForLocation(xOffset, y);
                }
                xOffset++;

                if (x - xOffset <= 16) {
                    System.out.println("you clicked the image for row " + (row + 1) +
                            ". this was detected, but no selection will happen!");
                    return;
                } else {
                    System.out.println("you clicked the text for row " + (row + 1) + 
                            ". this was detected, and selection WILL happen!");
                    super.processMouseEvent(e);
                }
            } else {
                super.processMouseEvent(e);
            }
        }
    }
}
Другие вопросы по тегам