I have created a database in Neo4j and I have a query that displays two terms that occur together in the database. Now I can do this in Neo4j and it displays in a table for me but I am creating an application in java and I want to display it in a JTable. This is what I have so far:
public void dataList(){
ArrayList<Data> dataList = new ArrayList<>();
try {
// code
if(result.length>0)
{ for (int i = 0; i < results.length; i++)
{ neoQuery.set("query"+results[i]);
neoQuery.add ("query"); //etc
//Get Result like this
results[results.length-1]=recordVariable.get("recordVariable.get("recordNumbers").asInt();
}//end for each record
neoQuery.set("query"{+word1+"#"+word2+""})");
neoQuery.add("query"); //etc
//and result for strings which I want in another column like this
resultString = session.run(neoQuery.get()).next().get("result").asString();
Data data;
while(resultVariable.next() != null){
data = new Data((ResultSet) resultVariable).getInt("c4"), ((ResultSet) resultVariable).getString("w4"));
dataList.add(data);
}
}
}
}
} catch (Exception e){
System.out.println(e);
}
}
I also have another class for how I want to display the data. This is the code.
public class Data {
private int c4;
private String w4;
public Data(int c4, String w4)
{
this.c4=c4;
this.w4=w4;
}
public int getc4() {
return c4;
}
public String getw4() {
return w4;
}
So now that I have this code I want to display the data in two columns with unlimited rows. So far I have tried this.
public void show_data() {
ArrayList<Data> list = dataList();
DefaultTableModel model = (DefaultTableModel) jTable_Display_Data.getModel();
I have done research but just find resources for SQL. Now I can do this for a limited number of rows but I am not so sure how to write the rest for an unlimited number of rows. How can I do this for Neo4j?
Related
I have a JFrame which has a JTable and it can represent data from database. Everything is fine but I want to load or refresh it from another class after a delete operation.
I have already done the delete operation but I can not load the JTable from another class. My code is below:
scrollPane = new JScrollPane();
add(scrollPane, BorderLayout.CENTER);
DefaultTableModel model=null;
try {
model = makeTableModel();
} catch (SQLException | IOException e) {
e.printStackTrace();
}
table = new JTable(model);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
int row = table.getSelectedRow();
String getvalue = (table.getModel().getValueAt(row, 4).toString());
PopulatePhotographerClass pp=new PopulatePhotographerClass(getvalue);
}
});
table.setRowHeight(200);
scrollPane.setViewportView(table);
Here is my makeTableModel method:
public static DefaultTableModel makeTableModel() throws SQLException, IOException {
DefaultTableModel model = new DefaultTableModel(new String[]{"Image", "Name","Address","mobile-Number","NID"}, 0) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 0 ? Icon.class : super.getColumnClass(columnIndex);
}
};
String cmd = "select * from photographer_lookup";
try (Connection con =database.DbConnect.getconnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
String name = rs.getString(3);
Blob blob = rs.getBlob(1);
String address=rs.getString("address");
String mobile=rs.getString("mobile_number");
String nid=rs.getString("Nid");
ImageIcon icon = null;
try (InputStream is = blob.getBinaryStream()) {
BufferedImage img = ImageIO.read(is);
icon = new ImageIcon(img);
}
model.addRow(new Object[]{icon,name,address,mobile,nid});
}
}}}
return model;
}
This is my code that I wrote. Now I want to define a method that does all work which is mentioned above and also it will be called by another class.
First off, you are making a mistake in using view indices to index the model. Listeners and all methods from JTable that return row or column indices will report view indices (except convertXXXIndexToModel methods).
As the table is sorted or columns are moved around, view indices will differ from model indices. JTable will not sort the model or rearrange columns in the model, rather it will change its mapping to the model.
If what you have is view indices and you want to look up cell values, either
Use JTable.getValueAt, which takes view indices
First convert view indices to model indices using JTable.convertRowIndexToModel and JTable.convertColumnIndexToModel before indexing in the model (JTable.getModel()).
Your mouse listener should read:
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
int row = table.getSelectedRow();
if( row < 0 ) return; // check if a row is selected first!
String getvalue = table.getValueAt(row, table.convertColumnIndexToView( 4 ) ).toString(); // use table.getValueAt, this getter takes view indices! Use convertColumnIndexToView to get a view index from a model index!
PopulatePhotographerClass pp=new PopulatePhotographerClass(getvalue);
}
});
Better still would be to implement a ListSelectionListener to listen for selection events, rather than using a MouseListener to act on selection events (thanks #mKorbel for pointing that out). This way you would be notified directly on list selection changes.
If you want operations to be done from another class, write a public method in your class that extends JFrame that does this work. If you have an instance to this class in another class, simply call this newly created public method.
Suppose your JFrame class is called MyFrameWithJTable
public class MyFrameWithJTable extends JFrame {
public void doSomeWork( /*parameters required in the operation*/ ) {
// Does the work you want to call from another class
// Eg the updates you want done in the JTable's model
}
}
Then in another class, if you have an instance of the MyFrameWithJTable class you can do
public class AnotherClass {
private MyFrameWithJTable instance;
public AnotherClass( MyFrameWithJTable instance ) {
this.instance = instance;
}
public void someMethod( ) {
instance.doSomeWork( /*supply parameters*/ );
}
}
In one of our applications we use the lazy query container to browse a potentially very large dataset. This works great. However, it is possible to select an arbitrary number of rows when using a multi-select table.
In our case, this can lead to selecting up to 500.000 rows (Vaadin limit) and then crash the VM.
Is there a way to limit the number of selected rows?
Here is a sample that shows the problem:
public class UIImpl extends UI {
private int SIZE = 500000;
#Override
protected void init(VaadinRequest request) {
// add a large table
LazyQueryContainer lqc = new LazyQueryContainer(
new QueryFactory() {
public Query constructQuery(QueryDefinition qd) {
return new Query() {
#Override
public int size() {
return SIZE;
}
#Override
public void saveItems(List<Item> addedItems, List<Item> modifiedItems, List<Item> removedItems) { }
#Override
public List<Item> loadItems(int startIndex, int count) {
List<Item> r = new ArrayList<>(count);
for (int i = startIndex; i<startIndex+count;i++) {
PropertysetItem item = new PropertysetItem();
item.addItemProperty("name", new ObjectProperty(i));
r.add(item);
}
return r;
}
#Override
public boolean deleteAllItems() {
return false;
}
#Override
public Item constructItem() {
return null;
}
};
}
},
null,
20,
false
);
lqc.addContainerProperty("name", Integer.class, null);
Table table = new Table();
table.setContainerDataSource(lqc);
table.setMultiSelect(true);
table.setSelectable(true);
table.setImmediate(true);
table.setVisibleColumns("name");
table.setSizeFull();
table.addValueChangeListener(new Property.ValueChangeListener() {
public void valueChange(Property.ValueChangeEvent event) {
System.err.println(event.getProperty().getValue());
}
});
setContent(table);
}
}
If you want to limit the number of rows a user is able to select you can use something similar to the following code:
public class TableWithSelectionLimit extends Table {
private final int maxSelections= -1;
private String[] lastSelected;
public TableWithSelectionLimit(int maxSelections) {
this.maxSelections = maxSelections;
}
#Override
public void changeVariables(Object source, Map<String, Object> variables) {
String[] selected = (String[]) variables.get("selected");
if (selected != null && selected.length > maxSelections) {
if (lastSelected != null) {
variables.put("selected", lastSelected);
} else {
variables.remove("selected");
}
markAsDirty();
} else {
lastSelected = selected;
}
super.changeVariables(source, variables);
}
}
This is of course optimizable, but it gives you an idea on how you could do it.
Update
For handling also selections produced using "Shift"+Click one has to handle/update these selection ranges additionally inside the method mentioned above.
Those can be retrieved using variables.get("selectedRanges") that will return a String[] containing items like "8-10" whereas the
first number is: the start index of the selection range
second number is: the amount of items selected starting at this index
Using this information it should be possible to update those values as wished and put them back into the variables using variables.put("selectedRanges", updatedRanges).
Attention: do not forget to call markAsDirty() if the values are changed, as otherwise the changes won't be propagated to the client side.
Im developing a app for ordeing system and i have to set data into JTabels.
And this code is successfully working.I wanted to know what the importance of and whats happen in this class?
Why we need to import AbstractTabelModel.class?
OrderTabelModel Class:-
public class OrderTableModel extends AbstractTableModel{
protected static final String[] COLUMN_NAMES={"Item","Qty","Amount"};
private List<Order> rows;
public OrderTableModel(List<Order> rows){
this.rows = new ArrayList<>(rows);
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
#Override
public String getColumnName(int column) {
return COLUMN_NAMES[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object value = null;
Order row = rows.get(rowIndex);
switch (columnIndex) {
case 0:
value = row.getItem();
break;
case 1:
value = row.getQty();
break;
case 2:
value = row.getAmount();
break;
}
return value;
}
}
this is other class
private void tblOrderListMouseClicked(java.awt.event.MouseEvent evt) {
int raw = tblOrderList.getSelectedRow();
Order or;
String item;
Double qty,amount,total;
ArrayList<Order> arrOrder = new ArrayList<Order>();
String selectedRaw = tblOrderList.getModel().getValueAt(raw, 0).toString();
System.out.println("order id : "+selectedRaw);
String sql = "select item,qty,amount from orderdetails where orderid='"+selectedRaw+"'";
con = new DBconnector().connect();
try {
Statement ps =con.createStatement();
ResultSet rs2 = ps.executeQuery(sql);
while(rs2.next()){
or = new Order();
or.setItem(rs2.getString("item"));
System.out.println("Item :" +rs2.getString("item"));
or.setQty(rs2.getDouble("qty"));
or.setAmount(rs2.getDouble("amount"));
arrOrder.add(or);
}
rs2.close();
ps.close();
OrderTableModel tblModel = new OrderTableModel(arrOrder);
tblOrderItems.setModel(tblModel);
} catch (Exception e) {
e.printStackTrace();
}
}
Can some one explain me the process of this please?
It is not always mandatory to extend the AbstractTableModel. You can simply extend the DefaultTableModel and only override the getValueAt() method if you have to.
But most of the time for simple usages it is not even needed to override the getValueAt() method either.
By using the DefaultTableModel, you have a limitation for the converting you data (imported from DB) to an object[][] or Vector types which may be a little boring.
But you asked what is the importance of using AbstractTabelModel?
In this case I can say when JTable is started to being rendered, it needs to determine the number of rows and number of the columns and also it needs to know which data should be renedered in each cell and so on. Based on this, JTable ask for this Information from the underlying TableModel. So it is needed for your TableModel(any child or implementation of TableModel) to have those methods which are used by JTable to retrieve the needed information.
Hope this would be helpful.
Good Luck.
My explanation below rambles, boiling down, is there a way I can add a Row without firing off an event, such that I can add multiple rows and fire an event to update all of them at once? Without having to add code to contain the table data in the custom model?
I have a custom TableModel which extends from DefaultTableModel so that I can use DefaultTableModel to keep track of data for me, whilst still having some custom methods of my own.
The issue is, I was thinking it might be faster for me to have an "addRows(String[][] val)" method, when I wish to add multiple rows. I could then fire a single event, probably fireTableDataChanged() to update the rows all at once. For example, my current method:
JTable table1 = new JTable(new dgvTableModel(new String[] {<values>},0, new String[] {<values>}));
table1.addRow(new String[] {<values here>});
table1.addRow(new String[] {<values here>});
table1.addRow(new String[] {<values here>});
I would then repeat the above as many times as necessary. The issue is, each of those will fire off a seperate event. It would be much faster (I think), if I could do this using my custom table model:
JTable table1 = new JTable(new dgvTableModel(new String[] {<values>},0, new String[] {<values>}));
table1.addRows(new String[][] {{<values1 here}, {values2 here}, . . .}});
and then in the table model:
public void addRows(String[][] values) {
for (String[] vals : values)
super.addRow(vals);
}
fireTableDataChanged();
}
I can code this in easily. The issue is again, that "super.addRow(vals);" line will fire an event each time through. Is there a way, without adding code to have my model contain the table data itself, to prevent that event being fired each time I add a row? Such that it waits for the fireTableDataChanged() call in the addRows method?
For reference, the code for my custom table model:
import java.awt.Color;
import java.util.ArrayList;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
public class dgvTableModel extends DefaultTableModel {
//private DataTable tableVals = new DataTable();
private ArrayList<Color> rowColors;
//private ArrayList<Object[]> data = new ArrayList<>();
//default constructor has no data to begin with.
private int[] editableColumnNames;
public dgvTableModel(String[] colNames, int rowCount)
{
super(colNames, rowCount);
}
public dgvTableModel(String[] colNames, int rowCount, String[] editableColNames)
{
super(colNames, rowCount);
//this.tableVals.setColNames(colNames);
if (editableColNames!=null && editableColNames.length >0)
{
editableColumnNames = new int[editableColNames.length];
int count = 0;
for (int i =0; i< editableColNames.length;i++)
{
for (String val : colNames)
{
if (val.equalsIgnoreCase(editableColNames[i]))
{
editableColumnNames[count] = i;
count+=1;
break;
}
}
}
}
}
public dgvTableModel(String[] colNames, int rowCount, String[] editableColNames, boolean colorChanges)
{
super(colNames, rowCount);
Color defColor = UIManager.getDefaults().getColor("Table.background");
if (editableColNames!=null && editableColNames.length >0)
{
editableColumnNames = new int[editableColNames.length];
int count = 0;
if (colorChanges)
{
rowColors = new ArrayList<>();
}
for (int i =0; i< colNames.length;i++)
{
if (colorChanges)
{
rowColors.add(defColor);
}
for (String val : editableColNames)
{
if (val.equalsIgnoreCase(colNames[i]))
{
editableColumnNames[count] = i;
count+=1;
break;
}
}
}
}
else if (colorChanges)
{
rowColors = new ArrayList<>();
for (String val : colNames)
{
rowColors.add(defColor);
}
}
}
#Override
public boolean isCellEditable(int row, int column)
{
if(editableColumnNames!=null && editableColumnNames.length >0)
{
for (int colID : editableColumnNames)
{
if (column==colID)
return true;
}
}
return false;
}
public void setRowColor(int row, Color c)
{
rowColors.set(row, c);
fireTableRowsUpdated(row,row);
}
public Color getRowColor(int row)
{
return rowColors.get(row);
}
#Override
public Class getColumnClass(int column)
{
return String.class;
}
#Override
public String getValueAt(int row, int column)
{
return super.getValueAt(row, column).toString();
}
}
Surely firing one event to display every row, is faster than firing one event for each row?
'AbstractTableModel.fireTableDataChanged()' is used to indicate to the model (and the JTable UI which is notified by the model) that all possible data in the table may have changed and needs to be checked. This can (with emphasis on can) be an expensive operation. If you know which rows have been added, just use the 'AbstractTableModel.fireTableRowsInserted(int firstRow, int lastRow)' method instead. This will ensure only the effect rows are seen as changed. Take a look at all the fire* methods in AbstractTableModel. You can really exercise fine grained control over which rows, cells, etc are seen as dirty.
Then again what your doing might be premature optimalization. Unless you have fiftythousand records in your JTable this is probably not going to be noticable. But if you have a massive amount of records in your JTable you might be beter of lazy loading them anyway.
I am planning to implement server-side sorting and paging for a data table to be shown on the webpage. The data table is a Javascript managed HTML table with external CSS. Data will be pulled from the server-side by Ajax. I am thinking about creating a class on the server-side to represent the data table but have no idea how to implement the sorting on different columns. The sorting should be general enough for any class that backs up the table.
Edit: a backup class such as this:
public class Inventory
{
private int itemsLeft = 0;
private float price = 0.0f;
private boolean status = false;
private int itemsSold = 0;
public int getItemsSold()
{
return itemsSold;
}
public void setItemsSold(int itemsSold)
{
this.itemsSold = itemsSold;
}
//... and other getters and setters
}
Each of the private field will be one of the column for the data table and the whole table will be represented as an ArrayList of Inventory. Each instance of the back up class consists of one database table row.
When the header of any sortable column is clicked, the index or name of the column will be sent to the server for sorting data according to the selected column.
I am now stuck at how to make a general sorting function for any back up class. Your suggestions will be much appreciated.
Implement different Comparators for the columns you want to sort on. You can then use Collections.sort or similar to sort on the server.
Thanks to Amir and cuberoot, after some work, I finally come up with this:
import java.util.Comparator;
import java.lang.reflect.Method;
public class ObjectComparator<T> implements Comparator<T>{
private String field;
private String order;
private Method method;
private Class<T> cls;
public ObjectComparator(String field, String order, Class<T> c){
this.field = field;
this.order = order;
this.cls = c;
init();
}
private void init(){
String field_name = "get"+field.substring(0,1).toUpperCase()+field.substring(1);
try{
method = cls.getDeclaredMethod(field_name,new Class[]{});
}
catch(Exception ex){
System.err.println("No Such Method Found!");
}
}
#SuppressWarnings("unchecked")
public int compare(T o1, T o2) {
try{
Object o1_ = method.invoke(o1,new Object[]{});
Object o2_ = method.invoke(o2,new Object[]{});
//Move all objects with null field values
//to the end of the list regardless of sorting order.
if(o1_== null) return 1;
else if(o2_== null) return -1;
//////////////////////////////////
if (order.equalsIgnoreCase("asc"))
return ((Comparable<Object>)o1_).compareTo(o2_);
else
return ((Comparable<Object>)o2_).compareTo(o1_);
}
catch (Exception ex)
{
System.err.println("error sorting");
return 0;
}
}
}
This can be used as:
List<Inventory> list = new ArrayList<Inventory>();//populate list
Collections.sort(list, new ObjectComparator<Inventory>(field_name, order, Inventory.class));
Here field_name is the name of the field to be sorted on. It is sent to the server as a request parameter when the header of the table is clicked. There is a requirement with this approach: all the sortable fields in the domain object must implement Comparable interface. Also there must be JavaBean style getter and setter methods for the fields of interests.