1

I am having trouble selecting and deselecting rows in my custom JTable class.

My custom class extends JTable and implements MouseListener and MouseMotionListener. When I press a row, I want that row to be selected; if a nonselected row is pressed, I want it to be deselected; the code for selecting and deselecting rows is currently located in the overrided changeSelection method.

import javax.swing.*;
import javax.swing.table.TableModel;
import java.awt.event.*;

public class SelectFRCTable extends JTable implements MouseListener, MouseMotionListener {

  private boolean isPressed;
  private boolean isReleased;
  private boolean isDragged;

  public SelectFRCTable(TableModel model) {
    //Register for mouse events on the table.
    this.setModel(model);
    addMouseListener(this);
    addMouseMotionListener(this);
  }

  public void mousePressed(MouseEvent e) {
    System.out.println("Mouse Pressed: " + e.getClickCount());
    isPressed = true;
    isReleased = false;
  }

  public void mouseReleased(MouseEvent e) {
    System.out.println("Mouse Released: " + e.getClickCount());
    isPressed = false;
    isDragged = false;
    isReleased = true;
  }

  public void mouseEntered(MouseEvent e) {}

  public void mouseExited(MouseEvent e) {}

  public void mouseClicked(MouseEvent e) {
    System.out.println("Mouse Clicked: " + e.getClickCount());
  }

  public void mouseDragged(MouseEvent e) {
    System.out.println("Mouse Dragged: " + e.getClickCount());
    isDragged = true;
  }

  public void mouseMoved(MouseEvent e) {}

  @Override
  public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
    ListSelectionModel selectionModel = getSelectionModel();
    boolean selected = selectionModel.isSelectedIndex(rowIndex);

    if (selected) {
      selectionModel.removeSelectionInterval(rowIndex, rowIndex);
      getValueAt(rowIndex, columnIndex);
    } else if (!selected) {
      selectionModel.addSelectionInterval(rowIndex, rowIndex);
    }
  }
}
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.util.Vector;

public class TableExample extends JFrame{

  public TableExample() {
    JFrame frame = new JFrame("Custom JTable Example");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(925,700);
    frame.setLayout(new GridBagLayout());

    // Create a table with all the events
    Vector<String> columns = new Vector<String>();
    Vector<Vector<String>> rows = new Vector<Vector<String>>();
    columns.add("Column 1");

    // Get information about each event and store it in a vector to eventually be loaded into a
    // table model.
    for (int i=0; i<30; i++) {
      String info = "Hello World";
      Vector<String> data = new Vector<String>();
      data.add(info);
      rows.add(data);
    }

    // Create table model and configure it so that none of the cells are editable.
    TableModel model = new DefaultTableModel(rows, columns) {
      public Class getColumnClass(int column) {
        Class returnValue;
        if ((column >= 0) && (column < getColumnCount())) {
          returnValue = getValueAt(0, column).getClass();
        } else {
          returnValue = Object.class;
        }
        return returnValue;
      }
      public boolean isCellEditable(int row, int column) {
        return false; //This causes all cells to be not editable
      }
    };

    // Create custom table
    SelectFRCTable table = new SelectFRCTable(model);

    // Add the table to a scrollable pane
    JScrollPane scrollPane = new JScrollPane(table);
    add(scrollPane, BorderLayout.CENTER);

    pack();
    setVisible(true);
  }
}

The current code works to a certain extent. It selects a row if the user presses said row and deselects a selected row if the user presses said row again. However, if the user presses a row and selects it, then continues to hold down the left mouse button and move the cursor after selecting it, the row is then deselected and then selected again and then deselected again and so on and so forth until the user releases the left mouse button.

This is a result of the current conditions being used to execute the if/else-if statements in the changeSelection method. I've tried various other conditions that also use a combination of the global boolean variables isPressed, isReleased, and isDragged, but so far I haven't been able to find a solution that works.

Does anyone have any ideas?

Any help is greatly appreciated, thanks in advance.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Chris C.
  • 21
  • 2

1 Answers1

1

I've found a solution to my initial problem that also works with drag enabled:

import javax.swing.*;
import javax.swing.table.TableModel;
import java.awt.event.*;

public class SelectFRCTable extends JTable implements MouseListener, MouseMotionListener {

  private boolean selectionDetermined;
  private boolean isSelecting;
  private boolean isDeselecting;

  public SelectFRCTable(TableModel model) {
    //Register for mouse events on the table.
    this.setModel(model);
    addMouseListener(this);
    addMouseMotionListener(this);
  }

  public void mousePressed(MouseEvent e) {}

  public void mouseReleased(MouseEvent e) {
    selectionDetermined = false;
    isSelecting = false;
    isDeselecting = false;
  }

  public void mouseEntered(MouseEvent e) {}

  public void mouseExited(MouseEvent e) {}

  public void mouseClicked(MouseEvent e) {}

  public void mouseDragged(MouseEvent e) {}

  public void mouseMoved(MouseEvent e) {}

  @Override
  public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
    ListSelectionModel selectionModel = getSelectionModel();
    boolean selected = selectionModel.isSelectedIndex(rowIndex);

    if (selected && !selectionDetermined) {
      selectionDetermined = true;
      isSelecting = false;
      isDeselecting = true;
    } else if (!selected && !selectionDetermined) {
      selectionDetermined = true;
      isSelecting = true;
      isDeselecting = false;
    }

    if (isSelecting && !selected) {
      selectionModel.addSelectionInterval(rowIndex, rowIndex);
    } else if (isDeselecting && selected) {
      selectionModel.removeSelectionInterval(rowIndex, rowIndex);
    }
  }
}

Flags are set when the mouse is released and those flags are used in the changeSelection() method as conditions for the if\else-if statements.

Chris C.
  • 21
  • 2