How to count the number of rows of a JTable? - swing

There is a JTable. I want to know the number of rows of it. How to achieve that ?

You can use the getRowCount() method:
Returns the number of rows that can be shown in the JTable, given
unlimited space. If a RowSorter with a filter has been specified,
the number of rows returned may differ from that of the underlying
TableModel.
Here you have one example:
import javax.swing.JTable;
public class Main {
public static void main(String[] argv) throws Exception {
Object[][] cellData = { { "1-1", "1-2" }, { "2-1", "2-2" } };
String[] columnNames = { "col1", "col2" };
JTable table = new JTable(cellData, columnNames);
int rows = table.getRowCount();
int cols = table.getColumnCount();
System.out.println(rows);
System.out.println(cols);
}
}

DefaultTableModel t=(DefaultTableModel)jTable1.getModel();
int number_of_rows = t.getRowCount();
note : if empty rows number_of_rows=0

Related

How to define where to start retrieving data with Spring Data Pageable request?

Is there a way to aim where to apply a Page request with Spring Data? I have some trouble to find suitable solution to this problem:
I have an sql table and I would like to retrieve 3 rows from a given id. I tried something like that :
Pageable pageable = new PageRequest( 0, 3, Sort.Direction.DESC, "id_user" );
Page<User> users = userReposiotry.findById_user(20L,pageable);
I want to start from 20 to 18 but this gives me only one row.
How can I achieve that?
I could make an algorithm with a loop to retrieve these data but in some case the id_useris not ordering.
If it is not possible with this kind of solution, how would you proceed to retrieve 3 rows (or plus) from a given row?
The start row number is limited by page size for PageRequest.
Because Pageable.getOffset() and Pageable.getPageSize() are used to perform a SQL query like select * from userTable order by id_user limit 3 offset 17.
Pageable.getOffset() return the start row number, but it's calculated by pageNumber*pageSize in the default implementation. (#see AbstractPageRequest, the super class of PageRequest)
If you want to retrieve data by any row number, a solution is creating your own Pageable. Here is a sample:
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
public class MyPageable implements Pageable {
private final int offset;//first record is 0
private final int size;
private final Sort sort;
public MyPageable(int offset, int size, Sort sort) {
if (offset < 0) {
throw new IllegalArgumentException("Page offset must not be less than zero!");
}
if (size < 1) {
throw new IllegalArgumentException("Page size must not be less than one!");
}
this.offset = offset;
this.size = size;
this.sort = sort;
}
public int getPageNumber() {
int page = offset / size;//TBD
return page;
}
public Pageable next() {
return new MyPageable(offset+size, size, sort);
}
public Pageable previousOrFirst() {
int prevoffset = offset-size;//TBD
return new MyPageable((prevoffset<0?0:prevoffset), size, sort);
}
public Pageable first() {
return new MyPageable(0, size, sort);
}
public boolean hasPrevious() {
return offset > 0;
}
public int getOffset() {
return offset;
}
public int getPageSize() {
return size;
}
public Sort getSort() {
return sort;
}
userReposiotry.findById_user(20L, new MyPageable(18-1, 20-18+1, new Sort(Sort.Direction.DESC, "id_user"));
will return 18th to 20th rows as you wished.

Sorting data held by JTable after insertion

I populate a JTable from a database. The data in JTable is sorted based on the auto-generated primary key in descending order. The table looks like the following.
The data in the table is held by a list which contains a list of objects of a JPA entity - List<Country>.
Since I display data in descending order by countryId (primary key), the list needs to be sorted in descending by countryId after data is inserted and before the fireTableRowsInserted(size, size) method is executed.
After sorting this list in descending order by countryId, the table looks wonky as follows.
Values through the given text fields are submitted after validation, when the given add button is pressed.
The row is added to database and to the list and the list is also sorted as mentioned but the data in the table are not shown as they are in the list.
See the last two rows in the preceding snap shot. The actual row which is created is not displayed. The last row is duplicated instead which is different from the underlying list where the new object is added and the list sorted too.
My AbstractTableModel is as follows.
package admin.model;
import entity.Country;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import javax.swing.table.AbstractTableModel;
public final class CountryAbstractTableModel extends AbstractTableModel
{
private List<Country> countries;
private List<String> columnNames;
public CountryAbstractTableModel(List<Country> countries)
{
this.countries = countries;
columnNames=getTableColumnNames();
}
//This is the method which sorts the list after adding a JPA entity object.
public void add(Country country)
{
int size = countries.size();
countries.add(country);
Comparator<Country> comparator = new Comparator<Country>()
{
#Override
public int compare(Country o1, Country o2)
{
return o2.getCountryId().compareTo(o1.getCountryId());
}
};
Collections.sort(countries, comparator);
fireTableRowsInserted(size, size);
}
#Override
public String getColumnName(int column)
{
return columnNames.get(column);
}
#Override
public Class<?> getColumnClass(int columnIndex)
{
switch (columnIndex)
{
case 0:
return String.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return String.class;
default:
return String.class;
}
}
private List<String> getTableColumnNames()
{
List<String> names = new ArrayList<>();
names.add("Index");
names.add("Id");
names.add("Country Name");
names.add("Country Code");
return names;
}
#Override
public int getRowCount()
{
return countries.size();
}
#Override
public int getColumnCount()
{
return 4;
}
public void remove(List<Long>list)
{
Iterator<Country> iterator = countries.iterator();
while(iterator.hasNext())
{
Country country = iterator.next();
Iterator<Long> it = list.iterator();
while(it.hasNext())
{
if(country.getCountryId().equals(it.next()))
{
iterator.remove();
int index = countries.indexOf(country);
fireTableRowsDeleted(index, index);
break;
}
}
}
}
#Override
public Object getValueAt(int rowIndex, int columnIndex)
{
Country country = countries.get(rowIndex);
switch (columnIndex)
{
case 0:
return rowIndex+1;
case 1:
return country.getCountryId();
case 2:
return country.getCountryName();
case 3:
return country.getCountryCode();
}
return "";
}
#Override
public void setValueAt(Object value, int rowIndex, int columnIndex)
{
Country country = countries.get(rowIndex);
if(value instanceof String)
{
String stringValue = value.toString();
switch(columnIndex)
{
case 2:
country.setCountryName(stringValue);
break;
case 3:
country.setCountryCode(stringValue);
break;
}
}
fireTableCellUpdated(rowIndex, columnIndex);
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return columnIndex>1?true:false;
}
}
If I remove the given Comparator as in the add() method in the code snippet (i.e sorting is not done) then, the table is updated as it should be with the newly created row at the end of the table (which should be on top of the table. Hence sorting is necessary).
Why does this happen when the underlying list is sorted? (Again it doesn't happen, when the list is not sorted, it is left untouched.)
This is happening because you are telling the model that an element has been added at position 'size' (ie the last position in the list) but because you are sorting the list it is actually in the model at position 0 (in this example).
Probably the simplest way to fix this is to call fireTableDataChanged() and not worry about the index - I think your table would have to be pretty big for this to cause performance problems. Otherwise you could use list.indexOf() to find out where your new element ended up after sorting and call fireTableRowsInserted() with the correct indices.

Loading millions of DB row in wicket table through a list causing outofmemory error

I'm loading million lines of data by sortabledataprovider
.. the query returns a list(Arraylist) as I sent it to a Wicket ajax enabled table and pagination enable table.
So the problem is that - If there are concurrent queries - the application might get crashed.
I'm already getting Java heap space error with just 100,000 rows in DB.
So what I want to achieve is this - when a user click on next page or may be number 10th page - it will load only the number 10th pages data from the DB - not the whole query which might have million lines in it.
here is how I loading the list by query
final SyslogProvider<SyslogParsed> sysLogProviderAjax = new SyslogProvider<SyslogParsed>(new ArrayList<SyslogParsed>());
*
*
daoList = syslogParsedDao.findByDatesAndHostName(utcStartDate, utcEndDate, null);
sysLogProviderAjax.setList(daoList);
**
DB query returning the big list of all rows
public List<logParsed> findByDatesAndHostName() {
return getJpaTemplate().execute(new JpaCallback<List<SyslogParsed>>() {
return query.getResultList();
}
});
}
=========
my data provider
public class logProvider<logParsed> extends SortableDataProvider{
/**
*
*/
private static final long serialVersionUID = 1L;
#SpringBean(name="logParsedDao")
private logParsedDao logParsedDao;
class SortableDataProviderComparator implements Comparator<logParsed>, Serializable {
public int compare(logParsed log1, logParsed log2) {
PropertyModel<Comparable> model1 = new PropertyModel<Comparable>(log1, getSort().getProperty());
PropertyModel<Comparable> model2 = new PropertyModel<Comparable>(log1, getSort().getProperty());
int result = model1.getObject().compareTo(model2.getObject());
if (!getSort().isAscending()) {
result = -result;
}
return result;
}
}
private List<logParsed> list = new ArrayList<logParsed>();
private SortableDataProviderComparator comparator = new SortableDataProviderComparator();
public logProvider(List<logParsed> sentModel){
setSort("numberOfEntries",SortOrder.DESCENDING);
list = sentModel;
}
public Iterator<logParsed> iterator(int first, int count) {
//ArrayList<logParsed> newList = (ArrayList<logParsed>) logParsedDao.findAll();
//Collections.sort(newList, comparator);
Iterator<logParsed> iterator = null;
try {
if(getSort() != null) {
Collections.sort(list, new Comparator<logParsed>() {
private static final long serialVersionUID = 1L;
public int compare(logParsed sl1, logParsed sl2) {
int result=1;
PropertyModel<Comparable> model1= new PropertyModel<Comparable>(sl1, getSort().getProperty());
PropertyModel<Comparable> model2= new PropertyModel<Comparable>(sl2, getSort().getProperty());
if(model1.getObject() == null && model2.getObject() == null)
result = 0;
else if(model1.getObject() == null)
result = 1;
else if(model2.getObject() == null)
result = -1;
else
result = model1.getObject().compareTo(model2.getObject());
result = getSort().isAscending() ? result : -result;
return result;
}
});
}
if (list.size() > (first+count))
iterator = list.subList(first, first+count).iterator();
else
iterator = list.iterator();
}
catch (Exception e) {
e.printStackTrace();
}
return iterator;
}
public int size() {
// TODO Auto-generated method stub
return list.size();
}
public IModel<logParsed> model(final Object object) {
return new AbstractReadOnlyModel<logParsed>() {
#Override
public logParsed getObject() {
return (logParsed) object;
}
};
}
public void setList(List<logParsed> newList){
list = newList;
}
}
The problem with query.list() is it returns all rows at once.
Instead of query.list() you can use either:
query.scroll(), which returns the query results as ScrollableResults
query.iterate(), which returns the query results as an Iterator
Both of these options return one row at a time, which is what you need.
Note that the query remains "executing" for the duration of processing, so you may find that the tables are locked etc depending on the isolation level you've chosen.
You have to use a JPA query that sort and returns only the desired rows each time that iterator(int first, int count) of your IDataProvider is called.
Something similar to this:
public Iterator<logParsed> iterator(int first, int count) {
Query query = entityManager.createQuery("from LogParsed m ORDER BY m.numberOfEntries DESC", LogParsed.class);
List<LogParsed> output = query.setFirstResult(first).setMaxResults(count).getResultList();
return output.iterator();
}
Have a look at this question.

JComboBox Item Change

My JComboBox model contains item like item1, item2, item1. My problem is when I select third item (item1) in JComboBox and check getSelectedIndex() it always returns 0.
If the item is same in my model how can I get index of each item differently? Like:
item1 returns 0
item 2 returns 1
item1 returns 2
It returns index = 0. Because the method getSelectedIndex() use .equals on objects that are in the JComboBox and compare it with the selected one. In your case because item1 is also at index 0 it finds the condition true and returns 0. If you want to get different index then you have to override the getSelectedIndex() method.
An outline of default getSelectedIndex() method of JComboBox found at Java2s:
public int getSelectedIndex() {
Object sObject = dataModel.getSelectedItem();
int i, c;
Object obj;
for (i = 0, c = dataModel.getSize(); i < c; i++) {
obj = dataModel.getElementAt(i);
if (obj != null && obj.equals(sObject))
return i;
}
return -1;
}
You should have something [may be itemName if item object has a name or anything else] different in 2 entries to get desired result. Override getSelectedIndex() and compare the thing that is meant to be differ in all. If both entries are completely same then whats the point of adding it twice?
If two entries in the JComboBox correspond to the same Object, then even if you click item 3 the actual item that is selected will be the first entry of that object (i.e. the one with the lowest index)
I don't think that this will work for the same objects.
A JList has no problems with identical items.
import javax.swing.event.*;
import javax.swing.*;
class TestList {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final String[] items = {"item1", "item2", "item1"};
final JList list = new JList(items);
final JTextField output = new JTextField(15);
JPanel gui = new JPanel();
gui.add(list);
gui.add(output);
list.addListSelectionListener(new ListSelectionListener(){
public void valueChanged(ListSelectionEvent lse) {
int index = list.getSelectedIndex();
String outputText =
"Index: " +
index +
" Value: " +
items[index];
output.setText(outputText);
}
});
JOptionPane.showMessageDialog(null, gui);
}
});
}
}

Line Wrapping Cell Renderer - Java

I am having trouble implementing a custom cell renderer which will wrap message content when it extends past one line in length. The following is what I have:
public class MessageTable extends JTable
{
private static MessageTable messageTable;
private DefaultTableModel model = new DefaultTableModel();
private String[] emptyData = {};
private TreeMap<Integer, String> messages = null;
public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
this.setText((String)value);
this.setWrapStyleWord(true);
this.setLineWrap(true);
this.setBackground(Color.YELLOW);
int fontHeight = this.getFontMetrics(this.getFont()).getHeight();
int textLength = this.getText().length();
int lines = textLength / this.getColumns() +1;//+1, because we need at least 1 row.
int height = fontHeight * lines;
table.setRowHeight(row, height);
return this;
}
}
public MessageTable()
{
super();
messageTable = this;
this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
model.addColumn("Message Number", emptyData);
model.addColumn("Message Content", emptyData);
this.setModel(model);
this.setFont(MappingView.theFont);
this.setDefaultRenderer(String.class, new LineWrapCellRenderer());
}
/**
* Set the current messages.
* #param messages
*/
public void setCurrentMessages(TreeMap<Integer, String> messages)
{
clearCurrentMessages();
this.messages = messages;
if (messages != null)
{
for (Integer key : messages.keySet())
{
String[] row = { key.toString(), messages.get(key).toString() };
model.addRow(row);
}
}
}
For some reason, the LineWrapCellRenderer is never used and the rows only ever contain one line of text.
What am I doing wrong?
Your cellrenderer is not used because the default table model returns Object.class for any column (it does not override AbstractTableModel's implementation):
public Class<?> getColumnClass(int columnIndex) {
return Object.class;
}
So either override the method yourself for the model or assign the renderer to Object.class.