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

Java 具有动态JTable的多行文本渲染器,java,swing,jtable,Java,Swing,Jtable,我正在做一个java项目,在这个项目中,我必须在JTable中显示一个使用jsoup从web上获取的文章列表。多行文本渲染器的问题并不新鲜,我已经在其他文章中遇到过(例如本文)。但在这个问题中,表是静态的,行数一开始是固定的,并且保持不变。在我的项目中,初始行数为1,编辑单元格(0,0)中的查询时,表格应通过在新行中显示文章列表(标题、内容、数据和文章链接)进行更新。 以下是主类的代码: public class ClientGrafico { public static void main(S

我正在做一个java项目,在这个项目中,我必须在JTable中显示一个使用jsoup从web上获取的文章列表。多行文本渲染器的问题并不新鲜,我已经在其他文章中遇到过(例如本文)。但在这个问题中,表是静态的,行数一开始是固定的,并且保持不变。在我的项目中,初始行数为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);
    }
 }
下面是MultiletableCellRender1类的代码:

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 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;
  }     
}
import org.jsoup.jsoup;
导入org.jsoup.nodes.*;
导入java.io.IOException;
导入java.util.ArrayList;
导入org.jsoup.select.Elements;
公共类estrazioneDati{
私人整数计数;
私人ArrayList titolo_pronto;
私人ArrayList testo_articolo;
私有ArrayList dataEora;
私人ArrayList link_articolo;
公共教育{
计数=0;
titolo_pronto=新数组列表();
testo_articolo=新数组列表();
dataEora=新的ArrayList();
link_articolo=新ArrayList();
}
公共文档连接(字符串richiesta)引发IOException
{
如果(richiesta.equalsIgnoreCase(“运动”)){
Document doc=Jsoup.connect(“http://www.unionesarda.it/sport).get();
退货单;
}
else if(richiesta.equalsIgnoreCase(“Sardegna”)){
Document doc=Jsoup.connect(“http://www.unionesarda.it/cronaca_sardegna).get();
退货单;
}
else if(richiesta.equalsIgnoreCase(“Cronaca”)){
Document doc=Jsoup.connect(“http://www.unionesarda.it/cronaca_italiana).get();
退货单;
}
else if(richiesta.equalsIgnoreCase(“Spettacolo”)){
Document doc=Jsoup.connect(“http://www.unionesarda.it/spettacoli_e_cultura).get();
退货单;
}
否则如果(richiesta.equalsIgnoreCase(“Politica”)){
文件文件=
Jsoup.connect(“http://www.unionesarda.it/politica_italiana).get();
退货单;
}
else if(richiesta.equalsIgnoreCase(“Esteri”)| richiesta.equalsIgnoreCase(“Estero”)){
Document doc=Jsoup.connect(“http://www.unionesarda.it/notizie_mondo).get();
退货单;
}
else if(richiesta.equalsIgnoreCase(“Economia”)){
Document doc=Jsoup.connect(“http://www.unionesarda.it/notizie_economia).get();
退货单;
}
返回null;
}
公共阵列列表titoli_Articioli(文件文档)
{
元素titoli=doc.select(“[class^=box\u elenco\u titolo]>a”);
对于(元素titolo:titoli){
titolo_pronto.add(titolo.attr(“标题”);
计数++;
}
立即返回titolo_;
}
公共阵列列表parte_articoli(文件文档)
{
元素parte_articolo=doc.select(“[class^=15 interlinea20]”);
对于(元素标题:parte_articolo)
testo_articolo.add(titolo.text());
返回testo_articolo;
}     
公共阵列列表数据_notizia(文档文档)
{
元素数据=文件选择(“span.ora\u notizia”);
for(元素时间:数据)
dataEora.add(time.text());
返回数据EORA;
}
公共阵列列表链接(文档文档)
{
元素链接=doc.select(“[class^=box\u elenco\u titolo]>a”);
用于(元件集合:链接)
链接_articolo.add(colleg.attr(“href”);
返回链接_articolo;
}
公共整数返回_计数()
{
返回计数;
}     
}
软件运行正常,但我无法更新表,无法使新行显示ArrayList dati中的dati,只要执行单元格(0,0)中的查询,就会更新该dati。
有人有想法吗?

我同意Jonathan的观点,在代码中我看不到在哪里添加行

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

如果我不使用自定义渲染器,软件工作得很好,但当然我无法获得单元格中的包装文本。因此,问题似乎出现在自定义渲染器中,在本例中,该渲染器是在类multilitablerenderer中实现的。使用自定义渲染器时,Jtable似乎不理解行的行数会发生动态变化

为了更快地获得更好的帮助,请发布一个。我在您的代码中没有看到的唯一一件事是您告诉您的表您在其中添加了数据。正如Andrew所说,SSCE将大有帮助。您的设置看起来很可疑:editListener正在侦听(确切地说是什么?)并更新tableModel(通常,模型关心自己)。editListener方法tableChanged()仅在单元格(0,0)发生更改时从setValueAt调用,并调用方法riempi_tabella()以更新ArrayList dati。是否有其他方法实现侦听器?tableChanged是TableModel侦听器的一种方法,而不是TableModel-模型本身的任务是在setValueAt上发送TableModelEvent,侦听器不得更改发送器源的状态。是时候退一步,阅读一些教程了,f.i.swing标记wikino中引用的在线教程,永远不要代表模型进行任何激发,这是模型本身的固有任务,也就是模型方法中的某个地方,实际上要插入行,必须调用fireInserted,Tabella dati类实现了接口TableModel,而不是AbstractTableModel,因此我不能使用fireTableRowsInserted。但是,我尝试更改AbstractTableModel中的接口,但没有成功anyway@hellbago如果您坚持要自己实现这些(或类似的)方法,那么不从AbstractTableModel进行扩展(因为它提供了自定义实现可以用来正确通知其侦听器的方法)是相当不理想的。这意味着复制代码,总是一个s
 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();
}

}
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;
  }     
}