2016-08-25 20 views
2

RenderersとEditorsのようにシンプルで、ダースにもかかわらずSOのブックマークにもかかわらず、同様の問題に関して私は何か初心者が不足しています。古いテキストファイルを2列のJTableにドラッグし、最初の列にファイル名を表示させ、2行目にドラッグされたファイルの内容に依存するオプションのJComboBoxを含めます。JTableのJComboBoxに選択項目が表示されない

これは、コンボボックスから選択するまではすべて正常に動作します。選択は表示されません。コンボボックスだけが正しく入力されていますが、選択は行われません。私はそれがレンダリング/編集者の私の誤用に関係するものでなければならないことを知っているが、少なくとも2週間のフレアリングの後、私は専門的な助けを求めている。そしてレンダラーや編集者が書かれている方法について私がボートを完全に見逃してしまったと思うなら、私はあなたが私の以前の試みを見ていないことをうれしく思っています。

このコードはSSCCEの資格を持つことを願っています。私が持ってはならないものが含まれていれば誠に申し訳ありません。私はいくつかの意味がある場合に備えて、DnDのものを保持しています。

各JComboBoxにはさまざまなオプションがあり、同様にTableCellEditorsが含まれているため、静的リストのComboBoxModels(行ごとに1つ)を使用します(これは正しい方法であるかどうかわかりませんが)。

これを実行するには、表示されるテーブルに任意のファイルをドラッグし、右側の列のJComboBoxから選択して無視してください。あなたがこれを実行する手間をかけずにいくつかのアドバイスを持っていても、ありがとう。

のJava 1.7/OS X 10.9.5/EclipseのMars.2

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.datatransfer.Transferable; 
import java.awt.datatransfer.UnsupportedFlavorException; 
import java.io.File; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import javax.swing.AbstractCellEditor; 
import javax.swing.DefaultCellEditor; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.MutableComboBoxModel; 
import javax.swing.SwingUtilities; 
import javax.swing.TransferHandler; 
import javax.swing.event.ListDataListener; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableColumnModel; 

public class Main extends JFrame { 

    static List<AComboBoxModel> priceComboModels = new ArrayList<AComboBoxModel>(); 
    static List<DefaultCellEditor> editors = new ArrayList<DefaultCellEditor>(); 

    public Main() { 
     setLayout(new BorderLayout()); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setPreferredSize(new Dimension(500, 400)); 
     JPanel panel = new JPanel(new BorderLayout()); 
     JTable table = new JTable(0, 2) { 
      public TableCellEditor getCellEditor(int rinx, int cinx) { 
       if (cinx == 0) { 
        return super.getCellEditor(rinx, cinx); 
       } 
       return editors.get(rinx); 
      } 
     }; 
     table.setPreferredScrollableViewportSize(new Dimension(360, 80)); 
     table.setTransferHandler(new ATransferHandler()); 
     table.setModel(new ATableModel()); 
     TableColumnModel tcm = table.getColumnModel(); 
     tcm.getColumn(0).setHeaderValue("File Name"); 
     tcm.getColumn(1).setHeaderValue("Selection"); 
      TableColumn column = tcm.getColumn(1); 
      column.setCellRenderer(new ACellRenderer()); 
      column.setCellEditor(new ACellEditor()); 
     table.setDragEnabled(true); 
     table.setFillsViewportHeight(true); 

     JScrollPane sp = new JScrollPane(
      table, 
      JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
      JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED 
     ); 

     panel.add(sp, BorderLayout.CENTER); 
     panel.setPreferredSize(new Dimension(200, 300)); 
     add(panel, BorderLayout.CENTER); 
     pack(); 
    } 

    public static int addComboModel(AComboBoxModel model) { 
     priceComboModels.add(model); 
     return priceComboModels.size() - 1; 
    } 

    public static AComboBoxModel getComboModelAt(int inx) { 
     return priceComboModels.get(inx); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       new Main().setVisible(true); 
      } 
     }); 
    } 
} 
class ATableModel extends DefaultTableModel { 
    List<ARecord> data = new ArrayList<ARecord>(); 

    public void addRow(ARecord row) { 
     data.add(row); 
     fireTableRowsInserted(data.size() - 1, data.size() - 1); 
    } 

    @Override 
    public int getRowCount() { 
     return data == null ? 0 : data.size(); 
    } 

    @Override 
    public int getColumnCount() { 
     return 2; 
    } 

    public void setValueAt(Object value, int rinx, int cinx) { 
     ARecord row = data.get(rinx); 

     switch (cinx) { 
     case 0: 
      row.setFilename((String) value); 
      break; 
     case 1: 
      row.setCbox((JComboBox) value); 
      break; 
     } 
    } 

    @Override 
    public Object getValueAt(int rinx, int cinx) { 
     Object returnValue = null; 
     ARecord row = data.get(rinx); 

     switch (cinx) { 
     case 0: 
      returnValue = row.getFilename(); 
      break; 
     case 1: 
      returnValue = row.getCbox(); 
      break; 
     } 
     return returnValue; 
    } 

    // I assume this is unnecessary since column 1 defaults to text 
    // and column 2 is handled by ACellRenderer. I think. 
// @Override 
// public Class getColumnClass(int cinx) { 
//  return cinx == 0 ? String.class : JComboBox.class; 
// } 
} 
////////////////////////////////////////////////////////////////////////////////// 

// This class handles the drag and drop. 
class ATransferHandler extends TransferHandler { 

    int getSourceActions(JList<String> lst) { 
     return TransferHandler.COPY; 
    } 

    Transferable createTransferable(JList<String> list) { 
     return null; 
    } 

    void exportDone(JList<String> lst, Transferable data, int action) { 
    } 

    public boolean canImport(TransferHandler.TransferSupport info) { 
     return true; 
    } 

    ////////////////////////////////////////////////////////////////////////// 
    // This is the method of interest where the dropped text file is handled. 
    ////////////////////////////////////////////////////////////////////////// 

    public boolean importData(TransferHandler.TransferSupport info) { 
     if (! info.isDrop()) return false; 
     JTable table = (JTable)info.getComponent(); 
     Transferable tr = info.getTransferable(); 
     List<File> files = null; 
     try { 
      files = (List<File>)tr.getTransferData(DataFlavor.javaFileListFlavor); 
     } catch(UnsupportedFlavorException | IOException e) { 
     } 

     ATableModel tm = (ATableModel)table.getModel(); 
     String[] options; 

     // For each dropped text file... 

     for (File fl : files) { 
      String fname = fl.getName(); 

      // Just fill the JComboBox with some unique options for now 
      // (in practice this comes from the dropped text file contents). 
      String dummyText = fname.substring(0, 5); 
      options = new String[] { dummyText + "_A", dummyText + "_B", dummyText + "_C" }; 

      // Create a ComboBoxModel for this JComboBox containing the selection options. 
      AComboBoxModel cboModel = new AComboBoxModel(options); 

      // Create the combo box itself. 
      JComboBox<String> cbox = new JComboBox<String>(); 

      // Assign the model to the box. 
      cbox.setModel(cboModel); 

      // Create and add to the editor list the table cell editor. 
      Main.editors.add(new DefaultCellEditor(cbox)); 

      // Also add the ComboBoxModel to the model list. 
      Main.addComboModel(cboModel); 

      // Add the row to the model data. 
      tm.addRow(new ARecord(fname, cbox));    
     } 
     return true; 
    } 
} 
/////////////////////////////////////////////////////////////////////////////////////////// 
class ARecord { 
    String filename; 
    JComboBox cbox; 

    // Just a bean to describe a table row (a filename and a JComboBox). 
    public ARecord(String filename, JComboBox cbox) { 
     super(); 
     this.filename = filename; 
     this.cbox = cbox; 
    } 
    public String getFilename() { 
     return filename; 
    } 
    public void setFilename(String filename) { 
     this.filename = filename; 
    } 
    public JComboBox getCbox() { 
     return cbox; 
    } 
    public void setCbox(JComboBox cbox) { 
     this.cbox = cbox; 
    } 
} 
/////////////////////////////////////////////////////////////////////////////////////////// 

// This is the model for the JComboBoxes. A different model is instantiated 
// for each row since each one has different contents. 
class AComboBoxModel implements MutableComboBoxModel { 
    List<String> items = new ArrayList<String>(); 

    public AComboBoxModel(String[] items) { 
     this.items = Arrays.asList(items); 
    } 
    @Override 
    public int getSize() { 
     return items.size(); 
    } 
    @Override 
    public Object getElementAt(int index) { 
     return items.get(index); 
    } 
    @Override 
    public void addListDataListener(ListDataListener l) {  
    } 
    @Override 
    public void removeListDataListener(ListDataListener l) {   
    } 
    @Override 
    public void setSelectedItem(Object anItem) { 
    } 
    @Override 
    public Object getSelectedItem() { 
     return null; 
    } 
    @Override 
    public void addElement(Object item) { 
    } 
    @Override 
    public void removeElement(Object obj) { 
    } 
    @Override 
    public void insertElementAt(Object item, int index) { 
    } 
    @Override 
    public void removeElementAt(int index) { 
    } 
} 
////////////////////////////////////////////////////////////////////////////////////// 

// I won't pretend that I'm confident as to how this should work. My guess is that 
// I should just retrieve the appropriate ComboBoxModel, assign it and return. 
class ACellRenderer extends JComboBox implements TableCellRenderer { 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, 
      int rinx, int cinx) {  
     setModel(Main.getComboModelAt(rinx)); 
     return this; 
    } 
} 
///////////////////////////////////////////////////////////////////////////////////////// 

class ACellEditor extends AbstractCellEditor implements TableCellEditor { 

    static JComboBox box = null; 

    // This is where I think I'm actually lost. I don't understand the significance of 
    // returning a JComboBox when one was already created when the text file was 
    // dropped. Is it correct to just assign the appropriate ComboBoxModel to a JComboBox 
    // and return it here? 
    public Component getTableCellEditorComponent(JTable table, 
      Object value, 
      boolean isSelected, 
      int rinx, 
      int cinx) { 

     box = (JComboBox)(table.getModel().getValueAt(rinx, cinx)); 
     box.setModel(Main.getComboModelAt(rinx)); 
     return box; 
    } 

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

答えて

2

右側の列にするJComboBoxから選択して、

何かが間違っている、それはあなたを無視見ますあなたのカスタムエディタと私は何がわからない。エディタのデータとしてJComboBoxを使用しようとしている点で大きな問題があります。これは完全に間違っています。

ただし、カスタムレンダラやカスタムエディタを使用する必要はありません。

TableModelにJComboBoxを格納しないでください。コンボボックスから選択した項目の文字列を保存するだけです。 (これは、デフォルトのコンボボックスエディタによって自動的に行われます)。

テーブルにドラッグされたすべてのファイルに対して新しいエディタを作成する必要はありません。

第二は、そのオプションドラッグファイル

の内容によって異なりますので、カスタマイズする必要があるテーブルの一部のみがgetCellEditor(...)方法でするJComboBoxを含んでいます。

特定のファイル拡張子に対して別のエディタを使用すると思います。

int modelColumn = convertColumnIndexToModel(column); 

if (modelColumn == 1) 
{ 
    String file = getModel.getValueAt(row, 0); 

    if (file.endsWith(".txt")) 
     return txtEditor; 
    else if (file.endsWith(".html")) 
     return htmlEditor; 
} 

return super.getCellEditor(row, column); 

チェックアウト:ワーキング例えば How to add unique JComboBoxes to a column in a JTable (Java)

だから、基本的なコードは次のようになるかもしれません。その投稿のロジックには、デモンストレーションの目的でのみ行ごとに別々のエディタがあります。この例は、コードがデフォルトのレンダラーとエディタで動作することを示しています。必要なのは、各コンボボックスエディタの項目を用意することだけです。

エディタはファイルタイプに基づいているため、ロジックは最初の列のデータをテストする必要があります。

注:ネストされたif/elseステートメントは良い解決策ではありません。ファイルタイプ/エディタのハッシュマップを使用することができます。次に、ファイルのファイルタイプを抽出すると、getCellEditor(...)メソッドはハッシュマップルックアップになります。

ドラッグするコードは、テーブルのエディタとは関係ありません。どのファイルタイプをサポートするかを事前に把握し、これらのファイルタイプごとに有効な項目を定義する必要があります。

また、TableModelはDefaultTableModelを拡張しないでください。独自のデータストレージを提供し、すべてのメソッドを実装しているので、AbstractTableModelを拡張するだけです。

+0

@camrickr - 私は1マイル離れていると思っていました。 SSCCEのドロップされたアイテムの有効性をチェックするためのコードを取り除きました。私のライブバージョンにはそれが含まれています。タブ区切りのファイルになります。そのファイルの最初の行は、コンボオプションを構成する一連の列ヘッダーです。私はconvertColumnIndexToModelをインクルードしましたが、データモデルとテーブルが一致してから削除しましたが、私もそれを誤解している可能性があります。とにかく今日は仕事から外れていますが、この夕方にこの情報をすべて適用することに専念します - ありがとうございます。 – regger

+0

@regger、 'convertColumnIndexToModelをインクルードしましたが、データモデルとテーブルが一致してから削除しました。 ' - ユーザーは、テーブルのヘッダーで列の並び替えを無効にしていない限り、列を新しい位置にドラッグして並べ替えることができます)。 – camickr

+0

@camrickr - ちょうど私がひどくたくさんの上で私をまっすぐに設定し、あなたにそれが今働いていると多くの感謝を言いたいと思った。それを完全に理解するためにあなたの説明を完全に理解することの問題です。しかし、DefaultTableModelを拡張することは私の鍵でした。カスタムレンダリングが必要な場合はまだ明確ではありませんが、ここでは重要ではありません。とても感謝しております。 – regger

関連する問題