JTable:显示包含列表的数据
JTable: show data containing a List
我有一个名为 "Profile" 的对象列表,每个配置文件都有一个功能列表(配置文件可以做的事情)和一个与该配置文件关联的用户列表。
我想在 JTable 中显示此信息。首先,显示具有 le 功能的配置文件,然后是该配置文件中的用户。像这样:
------------------------------------
|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() return 始终为 false 并且方法 setValueAt(..) 未实现,JTable 也已完成修改(该行随着添加的最后一个配置文件而更改)进入 JTable)。
谁能告诉我为什么会这样?我想,也许每次单击一行时都会调用 getValueAt(...) 方法,这会给我的数据结构带来麻烦!
并且,接下来,有一种方法可以告诉 JTable 列仅包含 Boolean 行是否与 Profile 相关?提前谢谢你
接下来是代码:
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 class 用户 {
public String getName() {
return name;
}
private String name;
public User (String name) {
this.name=name;
}
}
Upolad 图片让你明白我的问题:
单击之前,当一切似乎正常时
点击后,当我的梦想破灭时: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;
}
问题出在您在 getValueAt()
方法中所做的事情。基本上,您正在使用 riga
、show_profile
、profilo
和 users_number
.
字段更改 table 模型的状态
您假设 Swing 总是以正确的顺序调用 getValueAt()
(第 1 行,第 1 列,然后是第 1 行,第 2 列,依此类推)。这第一次有效,但在您单击 table 后,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
}
}
}
And, next, there is a way to tell to JTable that the columns contain Boolean only is the row is related to a Profile?
我认为如果您 return 一个 Boolean
而不是 getValueAt()
中的 String
,Swing 将正确显示它 JTable
。您还需要为 column==0
和 Boolean.class
覆盖 getColumnClass()
方法和 return String.class
,否则。 (返回 null
将显示一个空单元格,当前就是这种情况)
注意:也许考虑在您的用例中使用 TreeTable(这将使您的模型更易于实现,因为您的数据自然具有树结构)。 SwingX 有一个 really good implementation.
我有一个名为 "Profile" 的对象列表,每个配置文件都有一个功能列表(配置文件可以做的事情)和一个与该配置文件关联的用户列表。
我想在 JTable 中显示此信息。首先,显示具有 le 功能的配置文件,然后是该配置文件中的用户。像这样:
------------------------------------
|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() return 始终为 false 并且方法 setValueAt(..) 未实现,JTable 也已完成修改(该行随着添加的最后一个配置文件而更改)进入 JTable)。 谁能告诉我为什么会这样?我想,也许每次单击一行时都会调用 getValueAt(...) 方法,这会给我的数据结构带来麻烦! 并且,接下来,有一种方法可以告诉 JTable 列仅包含 Boolean 行是否与 Profile 相关?提前谢谢你
接下来是代码: 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 class 用户 {
public String getName() {
return name;
}
private String name;
public User (String name) {
this.name=name;
}
}
Upolad 图片让你明白我的问题: 单击之前,当一切似乎正常时
点击后,当我的梦想破灭时: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;
}
问题出在您在 getValueAt()
方法中所做的事情。基本上,您正在使用 riga
、show_profile
、profilo
和 users_number
.
您假设 Swing 总是以正确的顺序调用 getValueAt()
(第 1 行,第 1 列,然后是第 1 行,第 2 列,依此类推)。这第一次有效,但在您单击 table 后,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
}
}
}
And, next, there is a way to tell to JTable that the columns contain Boolean only is the row is related to a Profile?
我认为如果您 return 一个 Boolean
而不是 getValueAt()
中的 String
,Swing 将正确显示它 JTable
。您还需要为 column==0
和 Boolean.class
覆盖 getColumnClass()
方法和 return String.class
,否则。 (返回 null
将显示一个空单元格,当前就是这种情况)
注意:也许考虑在您的用例中使用 TreeTable(这将使您的模型更易于实现,因为您的数据自然具有树结构)。 SwingX 有一个 really good implementation.