How can I print three different tables side by side or add them together in one printing? since the following code prints separately and in different pages.
I have little knowledge with the printing aspect of JTable's.
I am using NetBeans 8.0.
Or could I instead import the data to an excel file and print it from there? Is that plausible?
edit: All three tables must be together, side by side when it print, regardless if its portrait or landscape. Even better if all the tables or joined and is represented by multiple columns instead of three separate tables.
PrinterJob job = PrinterJob.getPrinterJob();
PrintRequestAttributeSet asset = new HashPrintRequestAttributeSet();
PageFormat pf = job.pageDialog(asset);
job.setPrintable(new recording_system(), pf);
boolean ok = job.printDialog(asset);
if (ok) {
try {
jTstudents.print(JTable.PrintMode.NORMAL);
jTscores.print(JTable.PrintMode.NORMAL);
jTresults.print(JTable.PrintMode.NORMAL);
} catch (PrinterException ex) {
/* The job did not successfully complete */
}
}
The tables look like this
Implement a TableModel class that combines all models.
TableModel model = new ParallelTableModel(jTStudents.getModel(),
jTScores.getModel(),
TResults.getModel());
JTable totalTable = new JTable(model);
Copy table header.
And then totalTable.getPrintable for printing.
/**
* Table Model composed from side-by-side table models.
*/
public class ParalleTableModel extends AbstractTableModel {
private final TableModel[] models;
public ParalleTableModel(TableModel... models) {
this.models = models;
}
#Override
public int getRowCount() {
return models[0].getRowCount();
}
#Override
public int getColumnCount() {
int count = 0;
for (TableModel model : models) {
count += model.getColumnCount();
}
return count;
}
#Override
public String getColumnName(int columnIndex) {
int count = 0;
for (TableModel model : models) {
int n = model.getColumnCount();
if (columnIndex < count) {
return model.getColumnName(columnIndex - count);
}
count += n;
}
throw new IndexOutOfBoundsException();
}
#Override
public Class<?> getColumnClass(int columnIndex) {
int count = 0;
for (TableModel model : models) {
int n = model.getColumnCount();
if (columnIndex < count) {
return model.getColumnClass(columnIndex - count);
}
count += n;
}
throw new IndexOutOfBoundsException();
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
int count = 0;
for (TableModel model : models) {
int n = model.getColumnCount();
if (columnIndex < count) {
return model.isCellEditable(rowIndex, columnIndex - count);
}
count += n;
}
throw new IndexOutOfBoundsException();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
int count = 0;
for (TableModel model : models) {
int n = model.getColumnCount();
if (columnIndex < count) {
return model.getValueAt(rowIndex, columnIndex - count);
}
count += n;
}
throw new IndexOutOfBoundsException();
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
int count = 0;
for (TableModel model : models) {
int n = model.getColumnCount();
if (columnIndex < count) {
model.setValueAt(aValue, rowIndex, columnIndex - count);
}
count += n;
}
throw new IndexOutOfBoundsException();
}
}
Related
I have a ArrayList<String[]> data which I place values into at a different point in the program, I have made it a variable of MyTable which extends AbstractTableModel. But I don't know how to place it into the table.
I have previously put a String[][] into the table, but I am not sure how that would work with ArrayList class.
For getRowCount() I can do newStringArr.length and for getColumnCount I can do newStringArr[0].length and for getValueAt(int row, int column) I can return newStringArr[row][column] for a String[][] type. What would be the equal of those functions for an ArrayList?
Here is a good example using AbstractTableModel.
In your case, MyTable can be defined as:
class MyTable extends AbstractTableModel {
private final int numRows;
private final int numColumns;
private List<String[]> data = new ArrayList<String[]>();
public MyTable(int numColumns, int numRows) {
this.numColumns = numColumns;
this.numRows = numRows;
init();
}
public int getColumnCount() {
return data.get(0).length;
}
public int getRowCount() {
return data.size();
}
public Optional<String> getValueAt(int row, int col) {
if(isNotValidEntry(row, col)) {
throw new RuntimeException("Out of bound row or col");
}
return Optional.ofNullable(data.get(row - 1)[col -1]);
}
public void setValueAt(String value, int row, int col) {
if(isNotValidEntry(row, col)) {
throw new RuntimeException("Out of bound row or col");
}
data.get(row - 1)[col - 1] = value;
fireTableCellUpdated(row, col);
}
private void init() {
IntStream.range(0, numRows)
.forEach(r -> data.add(new String[numColumns]));
}
private boolean isNotValidEntry(int row, int col) {
return numRows <= row - 1 || numColumns <= col - 1;
}
}
I add items to a model that is linked to a table. When I select an item in this table, things happen depending on what item it is. For now I just have a System.out telling me the items name.
If I have two items called 'A' and 'B', when I select either their respective name is written to the console as expected, however, if I sort them by name, so that 'B' is placed in the row over 'A', the sorting never happened internally but only visually. So if I now select 'A', the console prints out 'B', and vice versa.
The sorter is declared in the mainclass, itemList is a JTable itemList.setAutoCreateRowSorter(true);
Apparently I must have failed to include some default method that's needed for this sorterfunctionality. "default methods" is declared towards the end in the code-snippet, from and after the method 'getColumnName'.
class ItemModel extends AbstractTableModel
{
ArrayList<MCItem> items = new ArrayList<MCItem>();
private int currentMaxRows = 0;
private String[] columnNames = {"Item", "Total Units", "In Sorter"};
private Class[] types = {String.class, Integer.class, Integer.class};
private Object[][] data = new Object[currentMaxRows][getColumnCount()];
public ArrayList<MCItem> getItems()
{
return items;
}
public void readdItems(Main m, ArrayList<MCItem> tempItems)
{
for(MCItem mci : tempItems)
{
mci.setMain(m);
addRow(mci);
}
}
public void emptyMe()
{
currentMaxRows = 0;
items.clear();
data = new Object[currentMaxRows][getColumnCount()];
fireTableDataChanged();
}
public boolean isDuplicate(String s)
{
for(MCItem ci : items)
if(ci.getName().equalsIgnoreCase(s))
return true;
return false;
}
public void updateItem(String id)
{
try
{
int foundRow = -1;
for(int i = 0;i < currentMaxRows;i++)
if(getValueAt(i, 0).toString().equalsIgnoreCase(id))
{
foundRow = i;
break;
}
for(MCItem ii : items)
if(ii.getName().equalsIgnoreCase(id))
{
setItem(foundRow, ii);
fireTableDataChanged();
return;
}
}
catch(NullPointerException e){}
}
public void addRow(MCItem item)
{
//check if we need to expand the dataArray
if(currentMaxRows == items.size())
{
if(currentMaxRows == 0)
data = new Object[++currentMaxRows][getColumnCount()];
else
{
Object[][] tempArr = data;
data = new Object[++currentMaxRows][getColumnCount()];
for(int x = 0; x < tempArr.length; x++)
for(int y = 0; y < getColumnCount(); y++)
data[x][y] = tempArr[x][y];
}
}
setItem(items.size(), item);
items.add(item);
fireTableDataChanged();
}
public void changeItem(int row, String name)
{
String originalName = (String) data[row][0];
data[row][0] = name;
for(MCItem ii : items)
if(ii.getName().toString().equalsIgnoreCase(originalName))
{
ii.setName(name);
return;
}
fireTableDataChanged();
}
public void removeItem(String id)
{
for(MCItem ii : items)
if(ii.getName().toString().equalsIgnoreCase(id))
{
items.remove(ii);
redoList();
return;
}
fireTableDataChanged();
}
private void redoList()
{
ArrayList<MCItem> tempArr = (ArrayList<MCItem>) items.clone();
emptyMe();
for(MCItem ii : tempArr)
addRow(ii);
}
private void setItem(int row, MCItem item)
{
int counter = 0;
data[row][counter++] = item.getName();
data[row][counter++] = item.getCount();
data[row][counter++] = item.getSorterCount();
fireTableDataChanged();
}
MCItem getMCItem(String name)
{
for(MCItem i : items)
if(i.getName().equals(name))
return i;
return null;
}
public String getColumnName(int col)
{
return columnNames[col].toString();
}
public int getRowCount()
{
return data.length;
}
public int getColumnCount()
{
return columnNames.length;
}
public Object getValueAt(int row, int col)
{
return data[row][col];
}
public Class getColumnClass(int columnIndex)
{
return this.types[columnIndex];
}
public boolean isCellEditable(int row, int col)
{
return false;
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
* Answer *
The issue was never the tablemodel, but the JTable itself. When I want to present information based on the item selected, I called
currentMCItem = model.getMCItem(model.getValueAt(itemList.getSelectedRow(), 0).toString());
which returned the index in the JTable correctly, however when sorting all the indexes gets messed up and it's only the view that changes, so I had to redo that line to
currentMCItem = model.getMCItem(model.getValueAt(itemList.convertRowIndexToModel(itemList.getSelectedRow()), 0).toString());
So, the key is to call JTable.convertRowIndexToModel(SELECTED INDEX IN TABLE) in order to get the correct index, and use that as if it was the selectedRow.
You have a set of convert methods in JTable that you need to use. For example, convertColumnIndexToModel takes a view index and gives you back a corresponding column index in the model. Convert them and then get the values.
I'm trying to read a csv file and get it setup to convert into another format to save some time at work, but the JTable i'm loading it into throws an exception when a row has a length less than the expected column. Is there a method to create an empty cell if row length < column length?
here is the table model:
private class CSVTableModel extends AbstractTableModel{
private ArrayList<String[]> list;
private String[] columns;
public CSVTableModel() {
this.list = p.getData();
this.columns = p.getHeaders();
}
#Override
public String getColumnName(int col) {
return columns[col];
}
#Override
public int getRowCount() {
return list.size();
}
#Override
public int getColumnCount() {
return columns.length;
}
#Override
public Object getValueAt(int row, int col) {
return list.get(row)[col];
}
#Override
public void setValueAt(Object value, int row, int col) {
list.get(row)[col] = (String) value;
this.fireTableCellUpdated(row, col);
}
}
So you can see with the getValueAt(int row, int col) method it will cause an error if the col exceeds the String[].length.
I literally solved it after posting. Rubber duck debugging.
#Override
public Object getValueAt(int row, int col) {
if ( col < list.get(row).length ) {
return list.get(row)[col];
} else {
return "";
}
}
added a condition and works fine now. Should've seen it before.
I am trying to substitute the null value of VCID and VCIDBACKUP for "Dont Have". Here is my code:
if (controladorExcel == false) {
WritableWorkbook workbookVazio = Workbook.createWorkbook(file);
WritableSheet sheet1 = workbookVazio.createSheet("First Sheet", 0);
TableModel model = table.getModel();
for (int i = 0; i < model.getColumnCount(); i++) {
Label column = new Label(i, 0, model.getColumnName(i));
sheet1.addCell(column);
System.out.println(column.getContents());
}
int j = 0;
for (int i = 0; i < model.getRowCount(); i++) {
for (j = 0; j < model.getColumnCount(); j++) {
System.out.println(model.getRowCount());
System.out.println(model.getColumnCount());
if(model.getValueAt(i, j) == null){ //At this point I verify if the value is null
model.setValueAt("Nao possui", i, j);
}
Label row = new Label(j, i + 1, //I got NULL POINTER here
model.getValueAt(i, j).toString());
System.out.println(row.getContents());
sheet1.addCell(row);
}
}
workbookVazio.write();
workbookVazio.close();
Here is the code of my AbstractTableModel:
public class MacroTableModel extends AbstractTableModel {
private String[] colunas;
private List<Macro> linhas;
public MacroTableModel(List<Macro> lista){
this.colunas = new String[]{"VPN Name", "VCID", "VCID BACKUP"};
this.linhas = new ArrayList<Macro>(lista);
}
public String getColumnName(int index) {
return colunas[index];
}
public int getRowCount(){
return linhas.size();
}
public int getColumnCount(){
return colunas.length;
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex){
Macro macro = new Macro();
switch(columnIndex){
case 0:
macro.setVpnName(aValue.toString());
break;
case 1:
macro.setVcid(aValue.toString());
break;
case 2:
macro.setVcid_BackUp(aValue.toString());
break;
}
fireTableCellUpdated(rowIndex,columnIndex);
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Macro macro = linhas.get(rowIndex);
switch(columnIndex){
case 0:
return macro.getVpnName();
case 1:
return macro.getVcid();
case 2:
return macro.getVcid_BackUp();
}
return null;
}
public void setColunas(String[] colunas) {
this.colunas = colunas;
}
public String getColunas(int i) {
return colunas[i];
}
}
When I debug the setValueAt method I get the correct value, but I still get the same error.
I might forgot some implementation in my AbstractModel class, I dont know exactly. Can someone help, please ?
The following two lines
public void setValueAt(Object aValue, int rowIndex, int columnIndex){
Macro macro = new Macro();
should be replaced by
public void setValueAt(Object aValue, int rowIndex, int columnIndex){
Macro macro = linhas.get(rowIndex);
Otherwise, you're modifying a new Macro that is not even part of the model, and this new Macro becomes eligible to GC right after the setValueAt() method returns. You want to change the value of the Macro that is in the model, at this row index.
That said, I find it a bit strange to modify the model when exporting it to Excel. Why doesn't the model do the substitution by itself:
public Object getValueAt(int rowIndex, int columnIndex) {
Macro macro = linhas.get(rowIndex);
switch(columnIndex){
case 0:
return valueOrDontHave(macro.getVpnName());
break;
case 1:
return valueOrDontHave(macro.getVcid());
case 2:
return valueOrDontHave(macro.getVcid_BackUp());
}
return null;
}
private valueOrDontHave(Object value) {
return value == null ? ""Nao possui" : value;
}
I have a JTable for which I have made a table model. But on passing the column names to table model, it is not updating the column names. Can someone tell me why?
class MyTableModelTwo extends AbstractTableModel {
private Object[][] data;
private String[] columnNames = {"Name", "ID Number", "CGPA"};
public MyTableModelTwo(Object[][] data) {
this.data = data;
}
#Override
public int getRowCount() {
return data.length;
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
#Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
#Override
public boolean isCellEditable(int rowIndes, int columnIndex) {
return false;
}
#Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
data[rowIndex][columnIndex] = value;
fireTableCellUpdated(rowIndex, columnIndex);
}
}
class MyTableTwo extends JPanel implements TableModelListener {
private JTable table;
private Object[][] data;
private JTextField t;
public MyTableTwo() {
data = new Object[3][3];
t = new JTextField();
for (int i = 0; i < noElements; i++) {
data[i][0] = "Kaushik";
data[i][1] = "2008A3";
data[i][2] = "7.79";
}
MyTableModelTwo m = new MyTableModelTwo(data);
table = new JTable(m);
}
#Override
public void tableChanged(TableModelEvent e) {
int row = table.getRowCount();
double sum = 0, d = 0;
for (int i = 0; i < row; i++) {
double c = (Double) table.getValueAt(i, 16);
sum += c;
}
t.setText("" + sum);
t.setHorizontalAlignment(JTextField.RIGHT);
}
}
You need to override getColumnName(int index) in your TableModel.
#Override
public String getColumnName(int index) {
return columnNames[index];
}