【问题标题】:JTable: show data containing a ListJTable:显示包含列表的数据
【发布时间】:2015-10-12 03:10:03
【问题描述】:

我有一个名为“配置文件”的对象列表,每个配置文件都有一个功能列表(配置文件可以执行的操作)和与该配置文件关联的用户列表。

我想在 JTable 中显示此信息。首先,显示具有文件功能的配置文件,然后是该配置文件中的用户。像这样的:

------------------------------------
|Profile | Operation1 | Operation 2|
------------------------------------
P1       |     X      |            | <- users1 in P1 can do only Operation1
 --user1 |            |            | 
 --user2 |            |            | 
P2       |     X      |     X      |
 --user2 |            |            | 
 --user3 |            |            |
 --user4 |            |            | 
------------------------------------  

所以我首先实现了一个更智能的 getRowCount() 方法,然后是一个 getValueAt 方法,它在 JTable 中打印一个配置文件,并在其行下打印与其关联的所有用户。 事情似乎有效,但是当单击一行时,即使 isCellEditor() 返回始终为 false 并且未实现方法 setValueAt(..) 也已完成 JTable 修改(该行已更改,最后一个配置文件添加到 JTable 中) . 谁能告诉我为什么会这样?我认为,也许每次单击一行时都会调用 getValueAt(...) 方法,这会给我的数据结构带来麻烦! 而且,接下来,有一种方法可以告诉 JTable 列仅包含布尔值,该行是否与配置文件相关?提前谢谢你

接下来,代码: JFrame:

import it.Profile.Operation;
import java.awt.BorderLayout;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

public class JTableTest extends JFrame {

List<Profile> list_profiles = new LinkedList<Profile>();
List<User> list_users = new LinkedList<User>();

public JTableTest() {
    super();

    Profile admin = new Profile("P1");
    admin.addOp(Operation.OPERATION1);
    admin.addOp(Operation.OPERATION2);
    admin.addUser(new User("User 1"));
    list_profiles.add(admin);

    Profile p1 = new Profile("P2");
    p1.addOp(Operation.OPERATION2);
    p1.addUser(new User("User 2"));
    list_profiles.add(p1);

    Profile p2 = new Profile("P3");
    p2.addOp(Operation.OPERATION1);
    p2.addOp(Operation.OPERATION3);
    p2.addUser(new User("User 1"));
    list_profiles.add(p2);

    create_jframe();
}

private void create_jframe() {

    JTable profile_jtable = new JTable(new ProfileTableModel());
    DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) profile_jtable
            .getTableHeader().getDefaultRenderer();
    renderer.setHorizontalAlignment(0);

    this.getContentPane().add(new JScrollPane(profile_jtable),
            BorderLayout.CENTER);

}

public static void main(String[] args) {
    JFrame jframe = new JTableTest();
    jframe.pack();
    jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jframe.setVisible(true);
}

private class ProfileTableModel extends AbstractTableModel {

    /**
     * 
     */
    int riga = 0;
    private int users_number = 0;
    private Profile profilo = list_profiles.get(riga);
    private boolean show_profile = true;

    private static final long serialVersionUID = 7525220824319997602L;
    private String[] columns_name = { "User", "OPERATION 1", "OPERATION 2",
            "OPERATION 3" };

    public ProfileTableModel() {
        super();
    }

    @Override
    public int getColumnCount() {
        return columns_name.length;
    }

    @Override
    public int getRowCount() {
        int count = list_profiles.size();
        for (int i = 0; i < list_profiles.size(); i++) {
            count += list_profiles.get(i).getListUsers().size();
        }
        return count;
    }

    /*
     * @Override public Class<?> getColumnClass(int c) { if (c == 0) return
     * String.class; return Boolean.class; }
     */

    @Override
    public Object getValueAt(int row, int column) {

        if (show_profile) {
            if (column == 0)
                return profilo.getName();
            Operation f = null;
            switch (column) {
            case 1:
                f = Operation.OPERATION1;
                break;

            case 2:
                f = Operation.OPERATION2;
                break;

            case 3:
                f = Operation.OPERATION3;
                users_number = profilo.getListUsers().size();
                if (users_number != 0)
                    show_profile = false;
                break;
            }
            return list_profiles.get(riga).getOperations().contains(f);
        } else {

            if (column == 0) {
                users_number--;
                String nome = profilo.getListUsers().get(users_number)
                        .getName();
                if (users_number == 0 && riga < list_profiles.size() - 1) {
                    riga++;
                    profilo = list_profiles.get(riga);
                }
                return "---" + nome;
            }
            if (column == 3)
                show_profile = true;

        }
        return null;
    }

    @Override
    public String getColumnName(int i) {
        return columns_name[i];
    }

    @Override
    public boolean isCellEditable(int row, int column) {
        if (row == 0 || row == 1)
            return false;
        return true;
    }

   }
}

简介:

import java.util.LinkedList;
import java.util.List;

public class Profile {

public enum Operation {
    OPERATION1, OPERATION2, OPERATION3 
}

private List<Operation> list_operations;
private String name;
private List<User> list_users;

public Profile (String name) {
    this.name=name;
    this.list_operations=new LinkedList<Operation>();
    this.list_users=new LinkedList<User>();
}

public Profile (String name, List<Operation> list_operation) {
    this.name=name;
    this.list_operations=list_operations;
}

public void addOp(Operation new_function) {
    this.list_operations.add(new_function);
}

public void removeOp(Operation op) {
    this.list_operations.remove(op);
}

public String getName() {
    return name;
}

public List<Operation> getOperations() {
    return this.list_operations;
}

public void setName(String name) {
    this.name=name;
}

public void addUser(User user) {
    this.list_users.add(user);
}

public List<User> getListUsers() {
    return list_users;
}
}

用户: 公共类用户{

public String getName() {
    return name;
}

private String name;


public User (String name) {
    this.name=name;
}
}

Upolid 图片让你明白我的问题: 在点击之前,当一切似乎正常时

点击后,当我的梦想破灭:P

点击后可以看到jTable结构被修改了。

编辑:根据 Eric 先生的提示修改 getValueAt

@Override
    public Object getValueAt(int row, int column) {
        int cpt = 0;
        int profile = 0;
        int user = 0;
        for (Profile p : list_profiles) {
            if (cpt++ == row) {
                if (column == 0)
                    return list_profiles.get(profile).getName();
                Operation f = null;
                switch (column) {
                case 1:
                    f = Operation.OPERATION1;
                    break;

                case 2:
                    f = Operation.OPERATION2;
                    break;

                case 3:
                    f = Operation.OPERATION3;
                    profile++;
                    break;
                }
                return list_profiles.get(profile).getOperations()
                        .contains(f);
            } else {
                String nome;
                for (User u : p.getListUsers()) {
                    if (cpt++ == row) {
                        if (column == 0) {
                            return list_profiles.get(profile)
                                    .getListUsers().get(user).getName();
                        }
                    }
                }
            }
        }
        return null;
    }

【问题讨论】:

  • 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)或SSCCE(简短、自包含、正确示例)。
  • 我仍然不明白点击时会发生什么,以及您的预期。你能发布一个 MCVE 吗?
  • 我添加了两张图片(在点击事件之前和之后),所以如果你想自己运行我的示例,你可以看到发生了什么以及我的类代码。

标签: java swing jtable


【解决方案1】:

问题来自您在 getValueAt() 方法中所做的事情。基本上,您正在使用字段rigashow_profileprofilousers_number 更改表模型的状态。

您假设 Swing 始终以正确的顺序调用getValueAt()(第一行、第一列、然后是第一行、第二列,依此类推)。这是第一次工作,但在您单击表格后,Swing 可能需要再次为特定单元格调用getValueAt(),这完全与您的模型混淆。 相反,您应该假设 Swing 会随时调用getValueAt(),以任何顺序。

因此,您应该摆脱这些字段,并应用无状态逻辑。例如,要知道在给定行显示什么,您可以浏览列表并停在正确的行:

int cpt = 0
for(Profile p : list_profiles){
   if(cpt++ == row){
      // return value corresponding to profile      
   }else{
      for(User u: p.getListUsers()){
         if(cpt++ == row)
             // return value corresponding to user     
      }
   }
}

接下来,有一种方法可以告诉 JTable,列仅包含布尔值,行是否与 Profile 相关?

我认为如果你在getValueAt() 中返回Boolean 而不是String,Swing 将正确地显示JTable。您还需要覆盖 getColumnClass() 方法并为 column==0Boolean.class 返回 String.class 否则。 (返回null 将显示一个空单元格,目前是这样)

注意:也许考虑为您的用例使用 TreeTable(这将使您的模型更易于实现,因为您的数据自然具有树结构)。 SwingX 有一个really good implementation

【讨论】:

  • 感谢您的回答。对不起,但我不明白你方法中的逻辑。变量 cpt 如何理解是否必须显示个人资料或用户?
  • cpt 只是一个您递增的计数器,直到您到达正确的行。如果您只有个人资料而没有用户,您将只显示list_profiles.get(row)。但是由于您还显示用户,因此您需要这种技巧来知道哪个对象对应于特定的row
猜你喜欢
  • 1970-01-01
  • 2013-12-10
  • 1970-01-01
  • 1970-01-01
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-05
相关资源
最近更新 更多