Still a Java newbie here, trying to stuff far too advanced for my own good. Nevertheless, here's what I need done: A checkbox within a JXTreeTable. My main class:
package info.chrismcgee.sky.production;
import info.chrismcgee.sky.production.treetable.NoRootTreeTableModel;
import java.awt.Checkbox;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.swingx.JXTreeTable;
public class TestFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = -1899673458785493250L;
private JXTreeTable treeTable;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
TestFrame frame = new TestFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestFrame() {
setMinimumSize(new Dimension(600, 600));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 546, 600);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new MigLayout("", "[grow][grow][grow][100px:n,grow][grow][grow][grow]", "[][251.00,grow][]"));
List<Job> jobList = new ArrayList<Job>();
List<ItemDetail> itemList = new ArrayList<ItemDetail>();
itemList.add(new ItemDetail("N10", "N10", 2, 1000, PrintType.PAD, true));
itemList.add(new ItemDetail("N13", "N13", 2, 2000, PrintType.PAD, true));
// create and add the first job with its list of ItemDetail objects
jobList.add(new Job(new Checkbox("Print Solutions"), "123456", ShipDate.getDate("02/28/14"), itemList));
List<ItemDetail> itemList2 = new ArrayList<ItemDetail>();
itemList2.add(new ItemDetail("P12", "Green", 1, 250, PrintType.SCREEN, true));
itemList2.add(new ItemDetail("P12", "Purple", 1, 250, PrintType.SCREEN, true));
itemList2.add(new ItemDetail("P12", "Gray", 1, 250, PrintType.SCREEN, true));
// create and add a second job with its list of ItemDetail objects
jobList.add(new Job(new Checkbox("Innovators Inc"), "246801", ShipDate.getDate("03/10/14"), itemList2));
// we use a no root model
NoRootTreeTableModel noRootTreeTableModel = new NoRootTreeTableModel(jobList);
treeTable = new JXTreeTable(noRootTreeTableModel);
treeTable.setEditable(false);
treeTable.setRootVisible(false);
treeTable.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
treeTable.getTableHeader().setReorderingAllowed(false);
treeTable.getColumn(0).setPreferredWidth(200);
treeTable.getColumn(1).setPreferredWidth(75);
treeTable.getColumn(2).setPreferredWidth(15);
treeTable.getColumn(2).setMinWidth(15);
treeTable.getColumn(2).setMaxWidth(15);
treeTable.getColumn(3).setPreferredWidth(50);
treeTable.getColumn(3).setMaxWidth(50);
treeTable.getColumn(4).setPreferredWidth(25);
JScrollPane scrollPane = new JScrollPane(treeTable);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollPane, "cell 0 1 7 1,grow");
}
}
The Job class (Branches in the TreeTable):
package info.chrismcgee.sky.production;
import java.awt.Checkbox;
import java.util.List;
import org.joda.time.LocalDate;
public class Job {
private Checkbox cbJob;
private String idNumber;
private LocalDate shipDate;
private List<ItemDetail> itemList;
public Job(Checkbox cbJob, String idNumber, LocalDate shipDate, List<ItemDetail> itemList)
{
this.cbJob = cbJob;
this.idNumber = idNumber;
this.shipDate = shipDate;
this.itemList = itemList;
}
public List<ItemDetail> getItemList()
{
return itemList;
}
public void setItemList(List<ItemDetail> itemList)
{
this.itemList = itemList;
}
/**
* @return the cbJob
*/
public Checkbox getCbJob() {
return cbJob;
}
/**
* @param cbJob the cbJob to set
*/
public void setCbJob(Checkbox cbJob) {
this.cbJob = cbJob;
}
/**
* @return the idNumber
*/
public String getIdNumber() {
return idNumber;
}
/**
* @param idNumber the idNumber to set
*/
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
/**
* @return the shipDate
*/
public LocalDate getShipDate() {
return shipDate;
}
/**
* @param shipDate the shipDate to set
*/
public void setShipDate(LocalDate shipDate) {
this.shipDate = shipDate;
}
}
The OrderDetail class (Leaves in the TreeTable):
package info.chrismcgee.sky.production;
public class ItemDetail {
private String productId;
private String detail;
private long numColors;
private long numQuantity;
private PrintType printType;
private boolean active;
public ItemDetail(String productId, String detail, long numColors, long numQuantity, PrintType printType, boolean active)
{
this.productId = productId;
this.detail = detail;
this.numColors = numColors;
this.numQuantity = numQuantity;
this.printType = printType;
this.active = active;
}
/**
* @return the productId
*/
public String getProductId() {
return productId;
}
/**
* @param productId the productId to set
*/
public void setProductId(String productId) {
this.productId = productId;
}
/**
* @return the detail
*/
public String getDetail() {
return detail;
}
/**
* @param detail the detail to set
*/
public void setDetail(String detail) {
this.detail = detail;
}
/**
* @return the numColors
*/
public long getNumColors() {
return numColors;
}
/**
* @param numColors the numColors to set
*/
public void setNumColors(long numColors) {
this.numColors = numColors;
}
/**
* @return the numQuantity
*/
public long getNumQuantity() {
return numQuantity;
}
/**
* @param numQuantity the numQuantity to set
*/
public void setNumQuantity(long numQuantity) {
this.numQuantity = numQuantity;
}
/**
* @return the printType
*/
public PrintType getPrintType() {
return printType;
}
/**
* @param printType the printType to set
*/
public void setPrintType(PrintType printType) {
this.printType = printType;
}
/**
* @return the active
*/
public boolean isActive() {
return active;
}
/**
* @param active the active to set
*/
public void setActive(boolean active) {
this.active = active;
}
}
and, finally, the NoRootTreeTableModel class, which extends the AbstractTreeTableModel class, so that the root of the tree isn't shown:
package info.chrismcgee.sky.production.treetable;
import info.chrismcgee.sky.production.ItemDetail;
import info.chrismcgee.sky.production.Job;
import java.util.List;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
public class NoRootTreeTableModel extends AbstractTreeTableModel {
private final static String[] COLUMN_NAMES = {"Name/Product", "Job # / Detail", "T",
"Colors", "Quantity", "Total"};
private List<Job> jobList;
public NoRootTreeTableModel(List<Job> jobList)
{
super(new Object());
this.jobList = jobList;
}
@Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
@Override
public String getColumnName(int column)
{
return COLUMN_NAMES[column];
}
@Override
public boolean isCellEditable(Object node, int column)
{
return false;
}
@Override
public boolean isLeaf(Object node)
{
return node instanceof ItemDetail;
}
@Override
public int getChildCount(Object parent) {
if (parent instanceof Job) {
Job job = (Job) parent;
return job.getItemList().size();
}
return jobList.size();
}
@Override
public Object getChild(Object parent, int index) {
if (parent instanceof Job) {
Job job = (Job) parent;
return job.getItemList().get(index);
}
return jobList.get(index);
}
@Override
public int getIndexOfChild(Object parent, Object child) {
Job job = (Job) parent;
ItemDetail item = (ItemDetail) child;
return job.getItemList().indexOf(item);
}
@Override
public Object getValueAt(Object node, int column) {
if (node instanceof Job) {
Job job = (Job) node;
switch (column) {
case 0:
return job.getCbJob();
case 1:
return job.getIdNumber();
}
} else if (node instanceof ItemDetail) {
ItemDetail item = (ItemDetail) node;
switch (column) {
case 0:
return item.getProductId();
case 1:
return item.getDetail();
case 2:
return item.getPrintType();
case 3:
return item.getNumColors();
case 4:
return item.getNumQuantity();
case 5:
return item.getNumColors() * item.getNumQuantity();
}
}
return null;
}
}
I know that is a lot of code, but I couldn't think of a quick way to cut it down and still have it work the way I need it to. And actually, it's cut down quite a bit already. (I left out a bunch of stuff that is normally also in that JFrame.)
When the code is run, I don't get a checkbox for the branches; instead, I get what appears to be a String representation of the checkbox code: Checkbox in a TreeTable http://imageshack.com/a/img713/250/dl87.jpg
Huh? How did this happen and, more importantly, how can I get the checkbox to show up instead?
With a few minutes of googling, I found this CheckBox node tree sample and this blog post about JXTreeTable with CheckBoxes, as well as this very simple solution.
Is this not what you are looking for?
You should never add components to a model, instead you should be providing a
TreeCellRenderer
to render the value of the node. The Node is probably using thetoString
value of the user object assigned to it...Take a look at How to Use Trees and Customizing a Tree's Display for more details
Example Ripped Straight from Customizing a Tree's Display
I'll leave it up to you create the editor and determine how the check box should get selected
Sturm gives most of the solution.
The missing piece of the puzzle is that you can get the
JTree
from theJXTreeTable
like this:It's a bit of a hack, but I don't know if they have any better API to get at it.