具有动态JTable的多行文本渲染器

时间:2013-07-09 13:40:34

标签: java swing jtable

我正在做一个java项目,其中我必须在JTable中显示一个使用jsoup从Web获取的文章列表。多行文本渲染器的问题并不新鲜,我已经在其他帖子中遇到过它(例如这个http://blog.botunge.dk/post/2009/10/09/JTable-multiline-cell-renderer.aspx)。但是在这个问题中,表是静态的,行数首先是固定的,并且保持不变。在我的项目中,初始行数为1,并在单元格(0,0)中编辑查询,表格应通过在新行中显示文章列表(包含标题,内容,数据和文章链接)来更新。 这是主类的代码:

public class ClientGrafico {
public static void main(String[] args) throws UnsupportedOperationException{

    JTable table = new JTable();
    table.setDefaultRenderer(String.class, new MultiLineTableCellRenderer1());
    table.setModel(TabellaDati.getTabellaDati());
    JFrame frame = new JFrame("TableDemo");
    frame.add(new JScrollPane(table), BorderLayout.CENTER);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //display the window
    frame.pack();
            frame.setVisible(true);
    }
 }

这是MultiLineTableCellRenderer1类的代码:

public class MultiLineTableCellRenderer1 extends JTextArea 
implements TableCellRenderer {
  private ArrayList<ArrayList<Integer>> rowColHeight = new ArrayList<ArrayList<Integer>>      ();

  public MultiLineTableCellRenderer1() {
    setLineWrap(true);
    setWrapStyleWord(true);
    setOpaque(true);
  }

  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row, int column) {
    if (isSelected) {
      setForeground(table.getSelectionForeground());
      setBackground(table.getSelectionBackground());
    } else {
      setForeground(table.getForeground());
      setBackground(table.getBackground());
    }
    setFont(table.getFont());
    if (hasFocus) {
      setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
      if (table.isCellEditable(row, column)) {
        setForeground(UIManager.getColor("Table.focusCellForeground"));
        setBackground(UIManager.getColor("Table.focusCellBackground"));
      }
    } else {
      setBorder(new EmptyBorder(1, 2, 1, 2));
    }
    if (value != null) {
      setText(value.toString());
    } else {
      setText("");
    }
    adjustRowHeight(table, row, column);
    return this;
  }

  /**
   * Calculate the new preferred height for a given row, and sets the height on the    table.*/
  private void adjustRowHeight(JTable table, int row, int column) {
    //The trick to get this to work properly is to set the width of the column to the 
    //textarea. The reason for this is that getPreferredSize(), without a width tries 
    //to place all the text in one line. By setting the size with the with of the  column, 
    //getPreferredSize() returnes the proper height which the row should have in
    //order to make room for the text.
    int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
    setSize(new Dimension(cWidth, 1000));
    int prefH = getPreferredSize().height;
    while (rowColHeight.size() <= row) {
      rowColHeight.add(new ArrayList<Integer>(column));
    }
    ArrayList<Integer> colHeights = rowColHeight.get(row);
    while (colHeights.size() <= column) {
      colHeights.add(0);
    }
    colHeights.set(column, prefH);
    int maxH = prefH;
    for (Integer colHeight : colHeights) {
      if (colHeight > maxH) {
        maxH = colHeight;
      }
    }
    if (table.getRowHeight(row) != maxH) {
      table.setRowHeight(row, maxH);
    }
  }
}

这是表格模型的代码:

public class TabellaDati extends AbstractTabellaDati{

  private EditListener listener;
  private WriteListener listener1;
  private String[] nomi_colonne;
  private ArrayList<Article> dati;

  public TabellaDati(){
    nomi_colonne = new String[]{"Titolo","Articolo","Data","Link all'articolo"};
    dati= new ArrayList<Article>();
    listener = new EditListener(this);
    listener1 = new WriteListener(this);
    //for(int i=0;i <20; i++)
    dati.add(new Article()); //aggiunta di un articolo vuoto per creare la prima riga della tabella
    this.setValueAt("PRESS TO UPDATE", 0, 1);
  }

  public static AbstractTabellaDati getTabellaDati()
  {
    return new TabellaDati();
  }

  public void riempi_tabella (String token)
  {
    /*rimuove tutte le righe tranne la prima*/
    int data_size = dati.size();
    for(int k=1; k< data_size;++k)
      dati.remove(1);
    Document ciao = null;
    estrazioneDati extr = new estrazioneDati();
    try {
      ciao=extr.connessione(token);
    } catch (IOException e) {
      e.printStackTrace();
    }

    ArrayList<String> a1= extr.titoli_articoli(ciao);
    ArrayList<String> a2= extr.parte_articoli(ciao);
    ArrayList<String> a3= extr.data_notizia(ciao);
    ArrayList<String> a4= extr.link_art(ciao);

    for(int j=0;j<extr.return_count();j++)
      this.addArticle(new Article(a1.get(j),a2.get(j),a3.get(j),a4.get(j)));

  }

  public void addArticle(Article c) {
    this.dati.add(c);
  }

  public boolean isCellEditable(int rowIndex,int columnIndex)
  {
    if(rowIndex==0)
      return true;
    else
      return false;
  }

  public int getRowCount()
  {
    return dati.size();
  } 

  public int getColumnCount()
  {
    return nomi_colonne.length;
  }

  public String getColumnName(int columnIndex)
  {
    return nomi_colonne[columnIndex];      
  }

  public Class<?> getColumnClass(int c) {
    return getValueAt(0, c).getClass();
  }

  public Object getValueAt(int rowIndex, int columnIndex){
    Article ar = dati.get(rowIndex);
    /*switch(columnIndex){
      case(0): 
        return ar.getTitle();
      case(1):
        return ar.getContent();
      case(2):
        return ar.getDate();
      case(3):
        return ar.getLink();
      default:
        return null;
      }*/

    if(columnIndex==0)
      return ar.getTitle();
    else if(columnIndex==1)
      return ar.getContent();
    else if(columnIndex==2)
      return ar.getDate();
    else if(columnIndex==3)
      return ar.getLink();
    return null;


  }

  public void setValueAt(Object aValue, int rowIndex, int columnIndex){
    Article ar = dati.get(rowIndex);
    String str = (String)aValue;
    /*switch(columnIndex){
      case(0): 
        ar.setTitle(str);
        break;
      case(1):
        ar.setContent(str);
        break;
      case(2):
        ar.setDate(str);
        break;
      case(3):
        ar.setLink(str);
          break;
      }*/

    if(columnIndex==0)
      ar.setTitle(str);
    else if(columnIndex==1)
      ar.setContent(str);
    else if(columnIndex==2)
      ar.setDate(str);
    else if(columnIndex==3)
      ar.setLink(str);


    /*---Con TableModelListener---*/
    TableModelEvent event = new TableModelEvent(this, rowIndex, rowIndex, columnIndex, TableModelEvent.UPDATE);
    if(rowIndex+columnIndex==0) 
      listener.tableChanged(event);


    /*---Con ChangeListener---*/
    /*ChangeEvent event = new ChangeEvent(this);
      if(rowIndex+columnIndex==0)
        listener1.stateChanged(event);*/

  }

  public void addTableModelListener(TableModelListener l){
  }

  public void removeTableModelListener(TableModelListener l){
  }
}

这是AbstractTabellaDati类的代码:

 public abstract class AbstractTabellaDati implements TableModel{
/* Da utilizzare per creare oggetti (no costruttori) */
public static AbstractTabellaDati getTabellaDati() {
    throw new UnsupportedOperationException("da implementare");
}

/* Restituisce true se la cella in posizione
(rowIndex,columnIndex) è modificabile. Deve restituire sempre true
per tutte le celle con rowIndex == 0 */
abstract public boolean isCellEditable(int rowIndex, int columnIndex);
}

这是类文章的代码:

 public class Article {

private String title;
private String content;
private String date;
private String link;

public Article()
{
    this("", "", "","");
}

public Article(String title, String content, String date, String link)
{
    this.title = title;
    this.content = content;
    this.date = date;
    this.link = link;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getContent() {
    return content;
}

public void setContent(String content) {
    this.content = content;
}

public String getDate() {
    return date;
}

public void setDate(String date) {
        this.date = date;
}

public String getLink() {
    return link;
}

public void setLink(String link) {
        this.date = link;
}
}

这是EditListener类的代码:

 public class EditListener implements TableModelListener 
 /*per la gestione degli eventi tramite TableModelListener*/
 {
private TabellaDati tab;

public EditListener(TabellaDati tab){
    this.tab=tab;
}

public void tableChanged(TableModelEvent e) {
    //if(e.getColumn() + e.getFirstRow() ==0) {
        String keyword= tab.getValueAt(0,0).toString();
        System.out.println(keyword);
        tab.riempi_tabella(keyword);
    //}
    //TabellaDati.getTabellaDati();
}

}

这是类estrazioneDati的代码:

import org.jsoup.Jsoup;
import org.jsoup.nodes.*;
import java.io.IOException;
import java.util.ArrayList;
import org.jsoup.select.Elements;

public  class estrazioneDati {   

  private int count;
  private ArrayList<String> titolo_pronto;
  private ArrayList<String> testo_articolo;
  private ArrayList<String>  dataEora;
  private ArrayList<String> link_articolo;

  public estrazioneDati(){
    count=0;
    titolo_pronto= new ArrayList<String>();
    testo_articolo=new ArrayList<String>();
    dataEora=new ArrayList<String>();
    link_articolo=new ArrayList<String>();
  }

  public Document connessione(String richiesta) throws IOException
  {

    if(richiesta.equalsIgnoreCase("Sport")){
      Document doc= Jsoup.connect("http://www.unionesarda.it/sport").get();
      return doc;
    }
    else if(richiesta.equalsIgnoreCase("Sardegna")){
      Document doc= Jsoup.connect("http://www.unionesarda.it/cronaca_sardegna").get();
      return doc;
    }
    else if(richiesta.equalsIgnoreCase("Cronaca")){
      Document doc= Jsoup.connect("http://www.unionesarda.it/cronaca_italiana").get();
      return doc;
    }
    else if(richiesta.equalsIgnoreCase("Spettacolo")){
      Document doc= Jsoup.connect("http://www.unionesarda.it/spettacoli_e_cultura").get();
      return doc;
    }
    else if(richiesta.equalsIgnoreCase("Politica")){
      Document doc=
          Jsoup.connect("http://www.unionesarda.it/politica_italiana").get();
      return doc;
    }
    else if(richiesta.equalsIgnoreCase("Esteri") || richiesta.equalsIgnoreCase("Estero")){
      Document doc= Jsoup.connect("http://www.unionesarda.it/notizie_mondo").get();
      return doc;
    }
    else if(richiesta.equalsIgnoreCase("Economia")){
      Document doc= Jsoup.connect("http://www.unionesarda.it/notizie_economia").get();
      return doc;
    }
    return null;
  }

  public ArrayList<String> titoli_articoli(Document doc)
  {
    Elements titoli=doc.select("[class^=box_elenco_titolo] > a");
    for(Element titolo : titoli) {
      titolo_pronto.add(titolo.attr("title"));
      count ++;
    }

    return titolo_pronto;
  }

  public ArrayList<String> parte_articoli(Document doc) 
  {
    Elements parte_articolo= doc.select("[class^=georgia font15 interlinea20]");
    for(Element titolo : parte_articolo)
      testo_articolo.add(titolo.text());

    return testo_articolo;
  }     

  public ArrayList<String> data_notizia(Document doc)
  {
    Elements data_ora= doc.select("span.ora_notizia");
    for(Element time : data_ora)
      dataEora.add(time.text());

    return dataEora;  
  }

  public ArrayList<String> link_art(Document doc)
  {
    Elements link=doc.select("[class^=box_elenco_titolo] > a");
    for(Element colleg : link )
      link_articolo.add(colleg.attr("href"));

    return link_articolo;
  }

  public int return_count()
  {
    return count;
  }     
}

软件运行正常,但是我无法更新表格,以至于新行显示在ArrayList dati中显示dati,只要执行单元格(0,0)中的查询,就会更新。 有人有想法吗?

2 个答案:

答案 0 :(得分:0)

我同意Jonathan的观点,我在代码中没有看到添加行的位置。

添加行后,尝试在代码中添加以下行。 tableModel.fireTableRowsInserted(tableData.size() - 1,tableData.size() - 1);

答案 1 :(得分:0)

如果我不使用自定义渲染器,那么该软件效果很好,但当然我无法获取单元格内的包装文本。所以问题似乎出现在自定义渲染器中,在这种情况下在MultiLineTableRenderer类中实现。使用自定义渲染器时,Jtable似乎不明白行的行数会改变。