2010-01-29 4 views
11

Comment dois-je détecter que l'action déplacée par colonne est terminée dans JTable? J'ai ajouté columnModeListener à mon modèle de colonne, mais le problème est que la méthode columnMoved est appelée chaque fois qu'une colonne se déplace (par certains pixels). Je ne veux pas de ce comportement. Je veux juste détecter quand le déplacement de la colonne est terminé.Colonne déplacée événement [terminé] dans JTable

columnModel.addColumnModelListener(new TableColumnModelListener() { 

      public void columnAdded(TableColumnModelEvent e) { 
      } 

      public void columnRemoved(TableColumnModelEvent e) { 
      } 

      public void columnMoved(TableColumnModelEvent e) { 
       //this is called so many times 
       //I don't want this, but something like column moved finished event 
       System.out.println("Moved "+e.getFromIndex()+", "+e.getToIndex()); 
      } 

      public void columnMarginChanged(ChangeEvent e) { 
      } 

      public void columnSelectionChanged(ListSelectionEvent e) { 
      } 
     }); 

J'espère que ce que je cherche est clair. Merci.

+0

Doit-vous quand l'utilisateur a terminé en faisant glisser une colonne, ou serait-il suffit de savoir quand l'ordre des colonnes a réellement changé (mais l'utilisateur peut encore faire glisser davantage)? –

+0

Je veux juste savoir quand l'utilisateur a fini de faire glisser une colonne. Que diriez-vous de la notification de changement de commande de colonne Comment devrais-je l'implémenter? – ashokgelal

+0

http://stackoverflow.com/questions/1543981/is-there-an-event-called-when-a-column-is-moved-in-a-jtable – Ben

Répondre

14

C'est ce que j'ai fini par faire. Je sais qu'il est sale, mais il convient pour ce que je suis à la recherche:

boolean dragComplete = false; 
     apTable.getTableHeader().addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseReleased(MouseEvent e) { 
       if (dragComplete) { 
        System.out.println("Drag completed"); 
       } 
       dragComplete = false; 
      } 
     }); 
     columnModel.addColumnModelListener(new TableColumnModelListener() { 

      public void columnAdded(TableColumnModelEvent e) { 
      } 

      public void columnRemoved(TableColumnModelEvent e) { 
      } 

      public void columnMoved(TableColumnModelEvent e) { 
       dragComplete = true; 
      } 

      public void columnMarginChanged(ChangeEvent e) { 
      } 

      public void columnSelectionChanged(ListSelectionEvent e) { 
      } 
     }); 
+1

+1 sale ou pas, cela fonctionne vraiment très bien pour mon application actuelle, qui (comme l'application de tout le monde le fait aussi) enregistre la largeur, l'ordre, et les informations de tri dans un fichier prefs. Je sauvegarde le fichier chaque fois que la souris est libérée dans l'en-tête, et tous les fluffs tout en faisant glisser et déplacer et autres choses n'affectent plus cette sauvegarde. – Ben

+1

Je nommerais le "dragging" booléen ou similaire, le nom que vous avez choisi est un peu déroutant ... :-) Merci d'avoir posé cette question de toute façon. – PhiLho

+0

Je fais de même, bien que j'ai ma propre classe d'en-tête de table, mais le concept est le même, et cela fonctionne. – DejanLekic

0

Si je vous comprends bien, peut-être que vous voulez regarder les écouteurs de la souris. Peut-être l'événement MOUSE_RELEASED?

+0

Comment devrais-je faire cela? MOUSE_RELEASED sur quoi? table? – ashokgelal

+0

Cliquez-vous et faites-vous glisser une colonne? À un certain point, cette action déclenchera les événements de souris appropriés. Il se peut que MouseListener ne sache pas exactement ce que vous faites glisser, mais vous le faites, et vous pouvez simplement écouter le bouton pour qu'il ne soit pas compressé. – Jon

+0

Je pense que votre suggestion implique l'ajout d'un MouseListener à la JTable. Mais avec cela les méthodes dans MouseListener sont invoquées même lorsque la colonne n'est pas déplacée. – sateesh

4

Voici une classe interne que j'utilise pour déterminer quand l'ordre des colonnes a changé. Notez que l'utilisateur n'a peut-être pas lâché la souris à ce stade, donc le glissement peut continuer plus loin.

private class ColumnUpdateListener implements TableColumnModelListener { 

    int lastFrom = 0; 
    int lastTo = 0; 

    private void verifyChange(int from, int to) { 
     if (from != lastFrom || to != lastTo) { 
     lastFrom = from; 
     lastTo = to; 

     /////////////////////////////////////// 
     // Column order has changed! Do something here 
     /////////////////////////////////////// 
     } 
    } 

    public void columnMoved(TableColumnModelEvent e) { 
     verifyChange(e.getFromIndex(), e.getToIndex()); 
    } 

    public void columnAdded(TableColumnModelEvent e) { 
     verifyChange(e.getFromIndex(), e.getToIndex()); 
    } 

    public void columnRemoved(TableColumnModelEvent e) { 
     verifyChange(e.getFromIndex(), e.getToIndex()); 
    } 

    public void columnMarginChanged(ChangeEvent e) {} 
    public void columnSelectionChanged(ListSelectionEvent e) {} 

}

Il a bien fonctionné pour moi.

+1

C'est mieux que le comportement par défaut mais toujours l'ordre des colonnes change plus fréquemment. J'ai juste besoin d'observer la fin de la traînée parce que j'ai besoin de sauvegarder l'ordre de toutes les colonnes dès que le glissement est terminé (je ne veux pas appeler ma méthode d'économie coûteuse si souvent). Je poste ce que j'ai fini par faire. Merci d'avoir écrit les codes. Peut être utile pour quelqu'un qui vient pour une fonctionnalité similaire. – ashokgelal

+0

+1 étant donné que nous ne pouvons pas ajouter un écouteur de souris à la colonne, cela me semble un moyen astucieux de détecter que le déplacement de la colonne est terminé. – sateesh

+0

Compréhensible. J'ai écrit le code ci-dessus, car l'enregistrement de l'ordre des colonnes dans les préférences de chaque événement columnMoved() était en train de ronger le processeur. Je pense que le TableColumnModelListener manque. –

2

Cela pourrait être une meilleure approche:

table.setTableHeader(new JTableHeader(table.getColumnModel()) { 

     @Override 
     public void setDraggedColumn(TableColumn column) { 
     boolean finished = draggedColumn != null && column == null; 
     super.setDraggedColumn(column); 
     if (finished) { 
      onColumnChange(table); // Handle the event here... 
     } 
     } 
    }); 
+0

Bonne idée, car l'en-tête a déjà ses propres écouteurs de souris, même si JavaDoc dit "Le code de l'application ne l'utilisera pas méthode explicitement "... :-) Peut-être doit être combiné avec l'événement columnMoved pour obtenir les valeurs from et to. – PhiLho

1

C'est ce qui fonctionne pour moi (les deux mouvements de la colonne et redimensionne de marge):

Je tends la table et passer outre les columnMoved et columnMarginChanged méthodes de la façon suivante:

... d'abord ajouter s les variables ertains pour l'état garder

private int lastMovementDistance = 0; 
private boolean bigMove = false; 
private boolean resizeBegan = false; 

...

@Override 
public void columnMarginChanged(ChangeEvent e) { 
    super.columnMarginChanged(e); 
    if (isShowing()){ 
     resizeBegan = true; 
    } 
} 

@Override 
public void columnMoved(TableColumnModelEvent e) { 
    super.columnMoved(e); 

    //this will be set to 0 when the column is dragged 
    //to where it should begin if released  
    lastMovementDistance = Math.abs(getTableHeader().getDraggedDistance()); 


    if (e.getFromIndex() != e.getToIndex()){ 
    //note, this does not guarantee that the columns will be eventually 
    //swapped - the user may move the column back. 
    //but it prevents us from reacting to movements where 
    //the user hasn't even moved the column further then its nearby region. 
    //Works for me, because I don't care if the columns stay the same 
    //I only need the updates to be infrequent and don't want to miss 
    //changes to the column order 
bigMove = true; 
    } 
} 

... puis dans le constructeur de ma table je fais ceci:

public MyTable(){ 

    ... 

getTableHeader().addMouseListener(new MouseAdapter(){ 

    public void mouseReleased(MouseEvent evt) { 
     if (bigMove && lastMovementDistance == 0){ 
     //react! the tables have possibly switched! 
     } 

      else if (resizeBegan){ 
    //react! columns resized 
     } 

     resizeBegan = false; 
     bigMove = false; 
} 
}); 
    ... 
} 

Il est un peu comme un hack, Mais cela fonctionne pour moi.

-1

Toutes les réponses échouent à un cas d'utilisation: si la table est dans une disposition remplissant toute la fenêtre, le redimensionnement de la fenêtre redimensionne la table et donc ses colonnes. En observant les événements de la souris sur les en-têtes de colonne, nous ne recevons pas l'événement lorsque l'utilisateur redimensionne la fenêtre.

J'ai regardé le code source JTable & et la méthode columnMarginChanged() est toujours appelée dans une sous-sous-sous-fonction ... appelée par JTable.doLayout(). Ensuite, ma solution est de surveiller les appels à doLayout() qui déclenchent au moins un columnMarginChanged().

En fait, columnMarginChanged() est appelé pour chaque colonne.

Voici ma solution:

private class ResizableJTable extends JTable { 

    private TableColumnModelListener columnModelListener; 

    private boolean columnsWereResized; 

    @Override 
    public void setColumnModel(TableColumnModel columnModel) { 
     if (getColumnModel() != null) { 
      getColumnModel().removeColumnModelListener(columnModelListener); 
      columnModelListener = null; 
     } 

     if (columnModel != null) { 
      columnModelListener = new TableColumnModelListener() { 

       public void columnSelectionChanged(ListSelectionEvent e) { 
        // Nothing to do 
       } 

       public void columnRemoved(TableColumnModelEvent e) { 
        // Nothing to do 
       } 

       public void columnMoved(TableColumnModelEvent e) { 
        // Nothing to do 
       } 

       public void columnMarginChanged(ChangeEvent e) { 
        columnsWereResized = true; 
       } 

       public void columnAdded(TableColumnModelEvent e) { 
        // Nothing to do 
       } 
      }; 

      columnModel.addColumnModelListener(columnModelListener); 
     } 

     super.setColumnModel(columnModel); 
    } 

    @Override 
    public void doLayout() { 
     columnsWereResized = false; 
     super.doLayout(); 
     if (columnsWereResized) { 
      onColumnsResized(); 
     } 
    } 

    /** 
    * Sub-classes can override this method to 
    * get the columns-were-resized event. 
    * By default this method must be empty, 
    * but here we added debug code. 
    */ 
    protected void onColumnsResized() { 
     int[] columnSizes = getColumnSizes(); 
     String sizes = ""; 
     for (int i : columnSizes) { 
      sizes += i + " "; 
     } 
     System.out.println("COLUMNS RESIZED: [ " + sizes + "]"); 
    } 

    protected int[] getColumnSizes() { 
     TableColumnModel columnModel = getTableHeader().getColumnModel(); 
     int columnCount = columnModel.getColumnCount(); 
     int[] columnSizes = new int[columnCount]; 

     for(int i = 0; i < columnCount; i++) { 
      TableColumn column = columnModel.getColumn(i); 
      columnSizes[i] = column.getWidth(); 
     } 

     return columnSizes; 
    } 
} 
+0

Je ne suis pas sûr de ce que vous essayez de dire, mais je pense que vous pourriez vous tromper. Le redimensionnement d'une colonne ne déplace pas la colonne. Après le redimensionnement, l'index de la colonne est le même. L'OP voulait savoir si l'événement "Column Moved" était terminé. – hfontanez

1

Belle réponse sur votre question ashokgelal. Juste un peu d'amélioration je pense. Votre code se déclenche également en un seul clic sur l'en-tête. En utilisant un drapeau supplémentaire, vous pouvez empêcher le déclencheur 'dragComplete' quand la colonne n'a pas vraiment changé. Code modifié:

boolean mDraggingColumn = false; 
    boolean mColumnCHangedIndex = false; 

    tblObjects.getTableHeader().addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (mDraggingColumn && mColumnCHangedIndex) { 
       System.out.println("Column changed"); 
      } 
      mDraggingColumn = false; 
      mColumnCHangedIndex = false; 
     } 
    }); 
    tblObjects.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 
     @Override 
     public void columnAdded(TableColumnModelEvent e) {} 
     @Override 
     public void columnRemoved(TableColumnModelEvent e) {} 
     @Override 
     public void columnMoved(TableColumnModelEvent e) { 
      mDraggingColumn = true; 
      if (e.getFromIndex() != e.getToIndex()) { 
       mColumnCHangedIndex = true; 
      } 
     } 
     @Override 
     public void columnMarginChanged(ChangeEvent e) {} 
     @Override 
     public void columnSelectionChanged(ListSelectionEvent e) {} 
    });