1

I've a collection of Stock objects that I'm updating about 10/15 variables for in real-time. I'm accessing each Stock by its ID in the collection. I'm also trying to display this in a JTable and have implemented an AbstractTablemodel. It's not working too well.

I've a RowMap that I add each ID to as Stocks are added to the TableModel. To update the prices and variables of all the stocks in the TableModel, I want to send a Stock object to an updateModel(Stock s) method. I can find the relevant row by searching the map, but how do I handle this nicely, so I don't have to start iterating through table columns and comparing the values of the cells to the variables of the object to see whether there are any differences??

Basically, i want to send a Stock object to the TableModel and update cells if there are changes and do nothing if there aren't.

Any ideas about how to implement a TableModel that might do this? Any pointeres at all would be appreciated.

Thanks.

Edit:

'import javax.swing.table.AbstractTableModel; import ppwebsitemonitor.views.OrderTableModel.*;

public final class QuoteTableModel extends AbstractTableModel {

// Attributes
String[] columnName = new String[]{"Stock", "Quantity", "Price", "Side", "Status"};
Class[] columnClass =
        new Class[]{String.class, Integer.class, Double.class, String.class, String.class};
Object[][] rows = null;

public QuoteTableModel() {
}

public QuoteTableModel(Object[][] orders) {
    this.rows = orders;
}

public int getColumnCount() {
    return columnName.length;
}

public boolean isNew(int row) {
    return rows[row][4].equals(OrderStatus.NEW);
}

public boolean isFilled(int row) {
    return rows[row][4].equals(OrderStatus.FULLY_FILLED);
}

public boolean isCancelled(int row) {
    return rows[row][4].equals(OrderStatus.CANCELLED);
}

public void updateOrderPrice(int row, Double newPrice) {

    Object[] order = rows[row];
    order[2] = newPrice;
    super.fireTableRowsUpdated(row, row);
}

public void updateOrderStatus(int row, int status) {

    Object[] order = rows[row];
    order[4] = OrderStatus.States[status];
    super.fireTableRowsUpdated(row, row);
}

public Object getValueAt(int row, int col) {
    return rows[row][col];
}

public int getRowCount() {
    return rows.length;
}

public String getColumnName(int col) {
    return columnName[col];
}

public Class getColumnClass(int col) {
    return columnClass[col];
}

}'

1 Answers1

0

Instead of storing the stock ID's in your table model you can store the Stock objects themselves. The same ones that you are holding onto in your master collection. Then send a refresh to the table UI every time you do an update to a stock value (or put it on a timed refresh or whatever your program requires).

Edit

I am including some code to illustrate what I meant. It's barely above pseudo-code, you will have to adapt it to your situation.

This is to emulate your stock order object:

import java.io.Serializable;

public class StockOrder implements Serializable{
    public final class OrderStatus {
        public static final String NEW = "NEW";
        public static final String FULLY_FILLED = "FULLY_FILLED";
        public static final String SHIPPED = "SHIPPED";
        public static final String CANCELLED = "CANCELLED";
    }

    private static final long serialVersionUID = -3627357348101499053L;

    private String ticker;
    private Integer quantity;
    private Double price;
    private String side;
    private String status;

    public StockOrder() {
        super();
    }

    public StockOrder(String ticker, Integer quantity, Double price, String side, String status) {
        this();
        setTicker(ticker);
        setQuantity(quantity);
        setPrice(price);
        setSide(side);
        setStatus(status);
    }

    public Double getPrice() {
        return price;
    }

    public Integer getQuantity() {
        return quantity;
    }

    public String getSide() {
        return side;
    }

    public String getStatus() {
        return status;
    }

    public String getTicker() {
        return ticker;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }

    public void setSide(String side) {
        this.side = side;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public void setTicker(String ticker) {
        this.ticker = ticker;
    }
}

Your custom model would look something like this:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.table.AbstractTableModel;

import misc.test.StockOrder.OrderStatus;

public class QuoteTableModel extends AbstractTableModel {

    private static final long serialVersionUID = -8683294701374710538L;

    // Attributes
    String[] columnName = new String[] { "Stock", "Quantity", "Price", "Side",
            "Status" };
    Class<?>[] columnClass = new Class[] { String.class, Integer.class,
            Double.class, String.class, String.class };
    private List<StockOrder> rows = null;
    private Map<String, Integer> orderMap = null;

    public QuoteTableModel() {
        super();
        setRows(new ArrayList<StockOrder>(8));
    }

    public QuoteTableModel(Collection<StockOrder> orders) {
        super();
        if(orders != null) {
            setRows(new ArrayList<StockOrder>(orders));
        } else {
            setRows(new ArrayList<StockOrder>(8));
        }
    }

    public int getColumnCount() {
        return columnName.length;
    }

    public boolean isNew(int row) {
        StockOrder order = getRows().get(row);
        return OrderStatus.NEW.equals(order.getStatus());
    }

    protected List<StockOrder> getRows() {
        return rows;
    }

    protected void setRows(List<StockOrder> rows) {
        this.rows = rows;
        this.orderMap = new HashMap<String, Integer>((rows != null) ? rows.size() : 8);

        if(rows != null) {
            int i = 0;
            for(StockOrder order: rows) {
                orderMap.put(order.getTicker(), new Integer(i++));
            }
        }
    }

    public boolean isFilled(int row) {
        StockOrder order = getRows().get(row);
        return OrderStatus.FULLY_FILLED.equals(order.getStatus());
    }

    public boolean isCancelled(int row) {
        StockOrder order = getRows().get(row);
        return OrderStatus.CANCELLED.equals(order.getStatus());
    }

    public void updateOrderPrice(int row, Double newPrice) {
        StockOrder order = getRows().get(row);
        if( order != null ) {
            order.setPrice(newPrice);
            super.fireTableRowsUpdated(row, row);
        }
    }

    public void updateOrderPrice(String ticker, Double newPrice) {
        Integer idx = getOrderMap().get(ticker);
        if(idx != null) {
            updateOrderPrice(idx, newPrice);
        }
    }

    public void updateOrderPrice(String ticker, String newStatus) {
        Integer idx = getOrderMap().get(ticker);
        if(idx != null) {
            updateOrderStatus(idx, newStatus);
        }
    }

    public void updateOrderStatus(int row, String newStatus) {
        StockOrder order = getRows().get(row);
        if( order != null ) {
            order.setStatus(newStatus);
            super.fireTableRowsUpdated(row, row);
        }

    }

    public Object getValueAt(int row, int col) {
        StockOrder order = getRows().get(row);
        if(order != null) {

            switch(col) {
                case 0: return order.getTicker() ;
                case 1: return order.getQuantity() ;
                case 2: return order.getPrice() ;
                case 3: return order.getSide() ;
                case 4: return order.getStatus() ;
                default: return "";
            }
        }

        return "";
    }

    public int getRowCount() {
        return getRows().size();
    }

    public String getColumnName(int col) {
        return columnName[col];
    }

    public Class<?> getColumnClass(int col) {
        return columnClass[col];
    }

    protected Map<String, Integer> getOrderMap() {
        return orderMap;
    }

    protected void setOrderMap(Map<String, Integer> orderMap) {
        this.orderMap = orderMap;
    }

}

You can use this to test:

import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.TableModel;

import misc.test.StockOrder.OrderStatus;

public class QuoteTableApp {
    public static void main(String[] args) {
        QuoteTableApp app = new QuoteTableApp();
        System.out.println(app);
    }

    private JFrame frame = null;

    public QuoteTableApp() {
        super();
        setFrame(new JFrame("Quotes"));
        getFrame().setLocation(500, 300);
        getFrame().setSize(500, 400);

        List<StockOrder> orders = new ArrayList<StockOrder>(4);
        orders.add(new StockOrder("YHOO", 20, 73.50, "UP", OrderStatus.NEW));
        orders.add(new StockOrder("MSFT", 40, 42.00, "UP", OrderStatus.NEW));
        orders.add(new StockOrder("IBM", 100, 126.75, "UP", OrderStatus.NEW));
        orders.add(new StockOrder("CSCO", 5, 29.32, "UP", OrderStatus.NEW));

        TableModel model = new QuoteTableModel(orders);
        JTable table = new JTable(model);

        getFrame().getContentPane().add(table);
        getFrame().setVisible(Boolean.TRUE);

        ((QuoteTableModel) model).updateOrderPrice("CSCO", 31.20);
    }

    protected void setFrame(JFrame frame) {
        this.frame = frame;
    }

    protected JFrame getFrame() {
        return frame;
    }
}

This code doesn't take into account any sorting you might need to do. But the basic concepts are there. Hopefully this helps.

Perception
  • 79,279
  • 19
  • 185
  • 195
  • Thanks for that. But I don't want to refresh the full collection each time. What if I have 100 stocks with 20 columns for each? I'd rather be called FireCellChanged rather than FireTableChanged. Am I on the right tracK? –  Jun 24 '11 at 15:20
  • Whats in your row map right now? And whats in your concrete implementation of AbstractTableMap? For some reason I got the impression you were storing stock ID's in the table map but now it sounds like its the other way around - you are storing row ID's in the row map. – Perception Jun 24 '11 at 15:33
  • Ok. I suppose the question I'm asking is this: How do I implement an AbstractTableModel that uses a HashTable rather than an object array? I need to be able to add objects to the hashtable on-the-fly and also be able to update objects in the hashtable wihtout knowing the row number. –  Jun 29 '11 at 14:18