Как сделать так, чтобы JTable кликнул по невыбранному, перетаскивал вместо выделения - PullRequest
4 голосов
/ 11 мая 2011

Если для JTable установлено значение table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION), а затем вы щелкаете мышью по строке, которая еще не выбрана, она начинает выделять несколько строк.Мы не хотим такого поведения.Мы хотим, чтобы, если вы щелкнете по узлу, даже если он еще не выбран, он начнет его перетаскивать.

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

Обновление: на данный момент, похоже, потребуется некрасивый взлом, поскольку логика находится в закрытом методе BasicTableUI $ Handler.canStartDrag

Ответы [ 5 ]

3 голосов
/ 20 октября 2012

К сожалению, ни один из других ответов не сработал для меня.

Поэтому я сделал свой собственный взлом / исправление проблемы (я публикую его здесь для других с такой же проблемой):

public class SFixTable extends JTable {
private static final long serialVersionUID = 1082882838948078289L;

boolean pressed = false;
int  currSRow = -100;

public SFixTable(TableModel dm) {
    super(dm);
}

public SFixTable() {
    super();
}

public SFixTable(Vector<?> rowData, Vector<?> columnNames) {
    super(rowData, columnNames);
}

@Override
protected void processMouseEvent(MouseEvent e) {
    int row = rowAtPoint(e.getPoint());
    int col = columnAtPoint(e.getPoint());
    if (SwingUtilities.isLeftMouseButton(e) && !e.isShiftDown() && !e.isControlDown()) {
        boolean isDragRelease = (e.getID() == MouseEvent.MOUSE_RELEASED) && row != currSRow;
        boolean isStartClick = (e.getID() == MouseEvent.MOUSE_PRESSED);

        if (row >= 0 && col >= 0) {
            if (isStartClick) {
                super.changeSelection(row, col, false, false);
            } else if (isDragRelease) {
                super.changeSelection(currSRow, col, false, false);
            }
        }
        pressed = (e.getID() == MouseEvent.MOUSE_PRESSED);
        if (pressed) {
            currSRow = row;
        } else {
            currSRow = -100;
        }
    }

    super.processMouseEvent(e);
}

@Override
public boolean isCellSelected(int row, int col) {
    return (pressed)? (row == currSRow) : super.isCellSelected(row, col);
}

}
3 голосов
/ 12 мая 2011

Я нашел одно возможное решение.Вы заключаете в скобки слушателей мыши, так что вы можете лгать при вызове isCellSelected во время вызова canStartDrag.

Подкласс JTable (или в моем случае JXTreeTable).В конструкторе вызовите это:

private void setupSelectionDragHack()
{
    // Bracket the other mouse listeners so we may inject our lie
    final MouseListener[] ls = getMouseListeners();
    for (final MouseListener l : ls)
    {
        removeMouseListener(l);
    }
    addMouseListener(new MouseAdapter()
    {
        @Override
        public void mousePressed(final MouseEvent e)
        {
            // NOTE: it might not be necessary to check the row, but... I figure it's safer maybe?
            mousingRow = rowAtPoint(e.getPoint());
            mousingInProgress = true;
        }
    });
    for (final MouseListener l : ls)
    {
        addMouseListener(l);
    }
    addMouseListener(new MouseAdapter()
    {
        @Override
        public void mousePressed(final MouseEvent e)
        {
            mousingInProgress = false;
        }
    });
}

И тогда вам понадобится это:

@Override
public boolean isCellSelected(final int row, final int column)
{
    if (mousingInProgress && row == mousingRow)
    {
        // Only lie to the canStartDrag caller. We tell the truth to everyone else.
        final StackTraceElement[] elms = Thread.currentThread().getStackTrace();
        for (int i = 0; i < 3; i++)
        {
            if (elms[i].getMethodName().equals("canStartDrag"))
            {
                return mousingInProgress;
            }
        }
    }
    return super.isCellSelected(row, column);
}

Это уродливый хак во многих отношениях, но ... пока что это работает.

1 голос
/ 17 декабря 2015

Если вам нужно перетащить невыбранную строку в таблицу выбора single , установки модели выбора таблицы в режим SINGLE_SELECTION недостаточно, вам также необходимо установить режим выбора модели столбца.

JTable table = new JTable();
table.getSelectionModel()
     .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getColumnModel().getSelectionModel()
     .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
1 голос
/ 05 декабря 2011

Аналогичен ответу Клеопатры, но, похоже, это решает несколько проблем с предыдущим: вы можете удерживать нажатой клавишу «Control», чтобы добавлять и удалять элементы из множественного выбора, и вы можете успешно перетаскивать группу с множественным выбором.Я проверял это только с ETable / Outline от NetBeans, но должен работать с обычным JTable.

table = new JTable() {
    private boolean inPress = false;

    @Override protected void processMouseEvent(MouseEvent e) {
        inPress = e.getID() == MouseEvent.MOUSE_PRESSED && e.getButton() == MouseEvent.BUTTON1 && !e.isShiftDown() && !e.isControlDown();
        try {
            super.processMouseEvent(e);
        } finally {
            inPress = false;
        }
    }

    @Override public boolean isCellSelected(int row, int col) {
        boolean selected = super.isCellSelected(row, col);
        if (inPress) {
            if (!selected)
                clearSelection();
            return true;
        }

        return selected;
    }
};
1 голос
/ 12 мая 2011

Это ошибка:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6349223

и, как вы уже предполагали, требует некрасивого взлома. Вот один из них (не от меня, а от пользователя Aephyr на старых форумах Sun, который не пережил миграцию в OTN)

    table = new JTable() {
        // fix for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6349223
        // requirement is the option to turn off drag-selection if dragEnabled
        // fix posted in sun dev forum by Aephyr
        // http://forums.sun.com/thread.jspa?threadID=5436355&tstart=0
        private boolean pressed;

        @Override
        protected void processMouseEvent(MouseEvent e) {
                pressed = e.getID() == MouseEvent.MOUSE_PRESSED;
                if (pressed && !e.isShiftDown() && !e.isControlDown())
                        clearSelection();
                try {
                        super.processMouseEvent(e);
                } finally {
                        pressed = false;
                }
        }

        @Override
        public boolean isCellSelected(int row, int col) {
                return pressed ? true : super.isCellSelected(row, col);
        }

    };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...