Object with better efficiency than JTable - java

I would like to create visualization of database. It's a full-desktop application, and it looks similar to Excel. When i put into my JTable database visualization 100 rows, each one with 6 columns, the application is crushing down. Is there a better class for such a task? Or some other smarter way?
Thats the way i do it:
import PodklasyInterfejsu.Menu;
import javax.swing.*;
import java.awt.*;
public class OknoGlowne extends JFrame
{
public Okno()
{
// ustawienie rozmiaru okna na 100%
JFrame Okno = new JFrame();
Okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Okno.setTitle("Archiwum Stomatologiczne");
Toolkit zestaw = Toolkit.getDefaultToolkit();
Dimension rozmiarEkranu = zestaw.getScreenSize();
int wysEkranu = rozmiarEkranu.height;
int szerEkranu = rozmiarEkranu.width;
Okno.setSize(szerEkranu, wysEkranu - 60);
Container powZawartosci = getContentPane();
// Panel Górnego Menu:
Menu GorneMenu = new Menu();
Okno.setJMenuBar(GorneMenu);
// Wizualizacja bazy w tabeli:
JTable tabela = new JTable(komorki, nazwyKolumn);
tabela.setAutoCreateRowSorter(true);
Okno.add(new JScrollPane(tabela), BorderLayout.CENTER);
Okno.setVisible(true);
}
private Object[][] komorki = new Object [10][];
private String[] nazwyKolumn = {"Nazwisko", "Imię", "Pesel", "Płeć", "Data urodzenia", "Adres", "Kontakt"};
}

One problem in the code above is that your data 2-d Object[10][] array, komorki, doesn't match your column String[] array, nazwyKolumn. You have 7 columns and need 7 as the first array index for your Object array. Consider changing this:
private Object[][] komorki = new Object[10][];
private String[] nazwyKolumn = { "Nazwisko", "Imię", "Pesel", "Płeć",
"Data urodzenia", "Adres", "Kontakt" };
to this:
// !! private Object[][] komorki = new Object[10][];
private Object[][] komorki = new Object[10][7]; //!!
private String[] nazwyKolumn = { "Nazwisko", "Imię", "Pesel", "Płeć",
"Data urodzenia", "Adres", "Kontakt" };
for starters.

As mentioned by others: have you tried profiling ? I personally have good experiences with JProfiler.
Although we do not yet know whether the JTable is the actual problem, I had performance problems with JXTables (note: the SwingX version of JTable) in combination with large TableModels where the table would iterate over all elements to determine the column size before painting it.
This was solved by setting a prototype value for each column (using TableColumnExt#setPrototypeValue). I am not sure whether a regular JTable contains this logic as well, but it might be worth a try to replace your JTable by a JXTable and set the prototype.

Related

Can not display contents of Arraylist n JTable

I can't figure this out (have been trying to fix this for the past 2-3 hours).
I would like to display the contents of an arraylist, but they do not appear in the table and also there are NO errors, they simply do not appear. Here is my code:
private class examinations{
private int id;
private int candidate_id;
private String date;
private String exam;
private String examNumber;
public examinations(int id, int student_id, String date, String exam, String examNumber) {
this.id = id;
this.student_id = student_id;
this.date = date;
this.exam= exam;
this.examNumber= examNumber;
}
public ArrayList ListExams(){
ArrayList<exams> list = new ArrayList<exams>();
return list;
}
public void addRollToTable(){
DefaultTableModel model = (DefaultTableModel)tableExams.getModel();
ArrayList<exams> list = ListExams();
Object rowData[] = new Object[5];
for(int i = 0; i < list.size(); i++) {
rowData[0] = list.get(i).id;
rowData[1] = list.get(i).student_id;
rowData[2] = list.get(i).date;
rowData[3] = list.get(i).exam;
rowData[4] = list.get(i).examNumber;
model.addRow(rowData);
}
}
}
I tested this loop and the variables coming out of the other list are there, so a System.out.println(list.get(i).exam); will display the correct thing i typed. However the table will NOT display whatever I add in the rowData. It gives, again, no errors. Let me show you the DefaultTableModel code. This code is in the private void initComponents() of my class...
Object [][] data = {};
String[] columnNames = {"Id", "Student_Id", "Date", "Exam",
"Exam_number"};
tableExams= new javax.swing.JTable();
DefaultTableModel model = new DefaultTableModel(data, columnNames);
tableExams.setModel(model);
tableExams.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
jScrollPane4.setViewportView(tableExams);
I've been reading this: DefaultTableModel Class Overview But I still can't find where I am going wrong... Could anyone give a tip?
First of all learn and use Java naming conventions:
Classs names SHOULD start with an upper case character. Can you show me a class in the JDK that does not?
Method should should NOT start with an upper case character. Again, can you show me a method in the JDK the does?
Learn by example and don't make up your own conventions.
so a System.out.println(list.get(i).exam); will display the correct thing i typed
I don't know how this is possible. Your code is as follows:
a) First, you retrieve the ArrayList from the "listExams() method.
ArrayList<exams> list = ListExams();
b) But in the "listExams()" method all you do is create an empty ArrayList.
ArrayList<exams> list = new ArrayList<exams>();
So you are missing the logic that actually adds data to the ArrayList.
Based on the logic provided, you don't even need the ArrayList. Just take the data from the Examination class and add it to the TableModel:
Object rowData[] = new Object[5];
rowData[0] = id;
rowData[1] = student_id;
rowData[2] = date;
rowData[3] = exam;
rowData[4] = examNumber;
model.addRow(rowData);
For a different solution you could create a custom TableModel to hold your "Examination" objects. Check out Row Table Model for a step-by-step example of how this can be done.
OK, I solved it, even though this was just a work around, I'd accept it.
All I did was use this.setVisible(false) and then entered the information in the other JFrame. Clicking add, i make an object of the first JFrame, passed all the variables, used this.dispose() and then called .setVisible(true) to return to the table, which displayed the information. LOL that was a long testing and re-writing of code to actually realize it was something that small...
I am sorry, I did not know where the actual problem was, and yeah thanks a lot for that simple suggestion there camickr. I tried it in the same JFrame and it worked, then I tried it between 2 JFrames and I realized the JFrame with the table DID NOT update the table. repaint() also didn't work. You quite literally helped me out with that small tip, which is all i needed. THANKS!!!!!!

Sort the contents of a JTable

I am working with a JTable That schould display Some informations sorted By the last two columns. The problem is the last two columns are filled with strings, one of them are Days of the Weak(Monday-Friday) the others are Hours(HH:mm), i would like to sort them going from Monday-Friday and if there are more elements of the same Day they schould be sorted by the Erliest Hour. Until now google was not a realy big help since it schows only ways to sorte something Alphabetically ore in Ascendant/descendant order for numbers, but i dont need an Alphabetically ordered JTable. Does anyone have an idea?
public class ScheduleFrame extends JFrame {
private JPanel contentPane;
private static JTable table;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScheduleFrame frame = new ScheduleFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
* #throws Exception
*/
public ScheduleFrame(){
setTitle("Schedule");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 627, 405);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
table = new JTable();
scrollPane.setViewportView(table);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
table.setModel(new DefaultTableModel(
new Object[][] {
},
new String[] {
"Course Name", "Course Room","Course Day", "Course Hour"
}
));}
public static void loadTable()throws Exception{
DefaultTableModel tm = (DefaultTableModel) table.getModel();
BufferedReader bfw = new BufferedReader(new FileReader("Schedulecourses.txt"));
String line;
while( (line = bfw.readLine() ) != null ) {
tm.addRow( line.split("\t") );
}
bfw.close();
}
}
This is how it schould look like
one of them are Days of the Weak(Monday-Friday)
So the data in the TableModel could be stored as an Integer to represent the day of the week. Then you use a custom renderer to convert the Integer value to a descriptive value.
Read the section from the Swing tutorial on Using Custom Renderers for an example.
In your case the code in the setValue(...) method would be something like:
int dayOfWeek = (Integer)value;
switch (dayOfWeek)
{
case 1: setText("Monday"); break;
case 2: setText("Tuesday"); break;
case 3: ...
default: value.toString();
}
the others are Hours(HH:mm),
In this case you are storing two pieces of information. So this means you need to parse the data into two times and then create a custom Comparator to sort based on the first time.
Another option might be to create two columns: "Start Time", "End Time". Then you could store Date objects in the TableModel and then just use the default Comparator that will sort by Date.
Simply implement it yourself. Use some basic sorting algorithm, like quick sort, bubble sort or merge sort (as found on wikipedia), and create your own comparison function to put the entries in order, like, in pseudo code:
bool is_smaller(entry_1, entry_2){
if (entry_1.weekday < entry_2.weekday) return true;
if (entry_1.weekday > entry_2.weekday) return false;
if (entry_1.course hour < entry_2.course_hour) return true;
if (entry_1.course hour > entry_2.course_hour) return false;
return false;
}
(of course with another comparison function for weekday and course hour)
I suggest you try and map the data that you read from the file to some kind of a model object that you can later sort. For example:
public class Course implements Comparable<Course> {
private String name;
private String room;
private String day;
private String hour;
// constructor and getters are omitted. you can add setters as well, but it's best that you keep this class immutable
#Override
public int compareTo(Course course) {
// here you implement the logic of your comparison
}
}
The benefit here is that, by implementing the Comparable<T> interface provided by the Java API, you specify that the instances of your Course class have a natural ordering. Then you can use Collections.sort() and your list of courses will be automatically sorted in the way you want. Then you can use it to back your table model and render it in the table.
Edit 1:
A bit of a clarification on my suggestion:
Right now you read text data from a file, transform each row into an array of strings and pass it to a DefaultTableModel that supplies data to your JTable.
Instead of doing this, you can a bit more complexity to the code, but end up with a better solution from an architectural point of view. What are the steps:
Define a model class (like the example Course class) that will hold the data that is saved in your text file. Implement logic to transform each row of the file into an instance of the Course class. This instances will represent your data and you will use them to populate your table with data.
Implement your own TableModel that holds a sorted list of Course instances (those are the instances you read from the file). Use the implemented model to supply data to your JTable.

Jtable dynamical fixed columns problems

I created a class that can dynamically to lock and unlock columns .
In my program i create two tables with the same tablemodel.
One is in the Jviewport of the scrollpane, the other in the RowHeaderView.
The problem is when you unlock all the locked columns
and you want to start to lock again, doesn't work. There are no errors but it's like the event doesn't answer.
Steps to produce the problem:
Try the code,
put all the columns in the fixed table,
then unlock with right double click,
then start again to lock, and unlock
Do this procedure and you can see that the mouse event doesnt answer anymore
public class Prova extends JFrame{
private JTable mainTable,fixedTable;
private JScrollPane scrollPane;
private JTableHeader mainTableHeader;
private TableColumnModel originalColumnModel,mainColumnModel,fixedColumnModel;
private TableColumn[] columns;
private int ncols,counter;
public Prova(){
counter = 0;
TableModel mainTableModel = new DefaultTableModel(5, 10);
scrollPane = new JScrollPane();
mainTable = new JTable(mainTableModel);
mainColumnModel = mainTable.getColumnModel();
fixedTable = new JTable();
fixedTable.setAutoCreateColumnsFromModel(false);
fixedTable.setModel(mainTable.getModel() );
ncols = mainTableModel.getColumnCount();
columns = new TableColumn[ncols];
for (int i=0;i<ncols;i++){
columns[i] = mainColumnModel.getColumn(i);
}
mainColumnModel = mainTable.getColumnModel();
fixedColumnModel = fixedTable.getColumnModel();
mainTableHeader = mainTable.getTableHeader();
mainTableHeader.addMouseListener( new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent me){
if (SwingUtilities.isRightMouseButton(me)){
if (ncols - counter>1){
counter ++;
int col = mainTable.columnAtPoint(me.getPoint());
TableColumn column = mainColumnModel.getColumn(col);
mainColumnModel.removeColumn(column);
fixedTable.getColumnModel().addColumn(column);
scrollPane.setRowHeaderView(fixedTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
}
}
}
});
fixedTable.getTableHeader().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me){
if (SwingUtilities.isRightMouseButton(me) && me.getClickCount()== 2 ){
while (mainColumnModel.getColumnCount() > 0){
mainColumnModel.removeColumn(mainColumnModel.getColumn(0));
}
while (fixedColumnModel.getColumnCount() > 0){
fixedColumnModel.removeColumn(fixedColumnModel.getColumn(0));
}
for(int i=0;i<ncols;i++){
mainColumnModel.addColumn(columns[i]);
}
scrollPane.setRowHeaderView(null);
}
}
});
scrollPane.setViewportView(mainTable);
add(scrollPane, BorderLayout.CENTER);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Prova().setVisible(true);
}
});
}
}
A few pointers when posting a SSCCE:
for (int i=0;i<ncols;i++){
Don't be afraid to use whitespace in you code to make it more readable be separating the 3 statements of the for statement.
for (int i = 0; i < ncols; i++){
Keep the code simple and directly related to the problem:
TableModel mainTableModel = new EmployeeTableModel(listEmployees);
You question is about "moving columns", not about the data in the table so there is no need for a special TableModel and the Employee class. Just use the DefaultTableModel:
TableModel mainTableModel = new DefaultTableModel(5, 10);
Your current code won't compile because you didn't include the Employee class. By using JDK classes the code is smaller and easier to read.
The problem is when you unlock all the locked columns and you want to start to lock again, doesnt work
Your looping code is wrong. I didn't bother to figure out what was wrong. Instead I made the code simpler:
//for(int i=0;i<(ncols-counter);i++){
while (mainColumnModel.getColumnCount() > 0)
{
mainColumnModel.removeColumn(mainColumnModel.getColumn(0));
}
//for(int i=0;i<counter;i++){
while (fixedColumnModel.getColumnCount() > 0)
{
fixedColumnModel.removeColumn(fixedColumnModel.getColumn(0));
}
Another problem is your fixed table doesn't have a header so you don't know what the columns are. This is fixed by using:
scrollPane.setRowHeaderView(fixedTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());
Now that you have a header you need to add the MouseListener to the header, not the scrollpane:
//scrollPane.addMouseListener(new MouseAdapter() {
fixedTable.getTableHeader().addMouseListener(new MouseAdapter() {
Edit:
You have a similar problem to what I fixed above. That is don't keep using variable to track values when you can use the component itself.
if (ncols - counter>1){
You never reset the value of the counter so the if condition won't be true the second time.
As I did above just use the value from the column model:
//if (ncols - counter>1){
if (mainColumnModel.getColumnCount() > 1) {
This is just basic problem solving. Put a display statement in the block of code to see if it executes when you have problems.

Dynamically updating a JTable from a vector<vector<string>>

I have a function called FetchInbox() which fetches the header information (Sender, subject, date sent) of an email and then adds it to a Vector of String Vectors.
What I want to be able to do is to refresh this table as new emails come in and update the table by first running FetchInbox() again, and then using this to repopulate the table.
I know this can be done using a TableModel, but I have yet to find a example which uses Vectors and not Object[][]. Any assistance with this would be appreciated.
DefaultTableModel has constructors and methods that take Vectors instead of Object[]s.
The old version of DefaultTableModel only used Vectors, the Object[] parameters are newer methods that were added around the time Generics came to Java.
http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
When you create a table without providing it a model, it will have DefaultTableModel as it's default model. This model has two function:
setDataVector(Vector dataVector, Vector columnIdentifiers): Where dataVector is a Vector(which represents the data rows of table) of Vector and comlumnIdentifiers is Vector containing identifiers. It will show your table as you are providing the Vector.
addRow(Vector dataRow): it will add a data row to your dataVector as defined above.
So it is really simple to get the model and invoke these function:
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setDataVector(dataVector, comlnIdentifiers);
In your context, dataVector has the type vector<vector<string> >. But depending on Vector is not really a good choice. It is much safer and effective if your directly work with Object[]. The DefaultTableModel has similar function with Object array too.
setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
addRow(Object[] rowData)
Check out the Tutorial page: How to Use Table to know many more things you can do with table and it's model.
This should work, but #jzd's answer is probably what you want, with the caveat that, according to the documentation, the column Vectors might be truncated or padded if their length does not match the number of columns you want in your table.
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
class test{
public static void main(String[] _) {
// Test data.
final Vector<Vector<String>> rows = new Vector<Vector<String>>();
for (int i = 0; i < 4; i++) {
Vector<String> row = new Vector<String>();
for (int j = 0; j < 5; j++) {
row.add(String.format("%s, %s", i, j));
}
rows.add(row);
}
// With AbstractTableModel, you only need to implement three methods.
TableModel model = new AbstractTableModel() {
public int getRowCount() {
return rows.size();
}
public int getColumnCount() {
return rows.elementAt(0).size();
}
public Object getValueAt(int row, int column) {
return rows.elementAt(row).elementAt(column);
}
};
// Test the TableModel in a JTable.
JFrame jf = new JFrame("test");
jf.setSize(512, 384);
jf.setContentPane(new JScrollPane(new JTable(model)));
jf.show();
}
}
have a look at GlazedLists - it'll save you a ton of time.
with it you can dynamically bind a JTable to a List of objects such that any change in the objects is reflected in the table and vice-versa.

Problems with JScrollPane -- Trying to Update it on Model Changes

I'm writing a fairly complex program, so I'll try to explain it only in terms of where the problem is occurring.
In my view, I create a JScrollPane to display a list of courses that a student is registered for:
registeredPane = new JScrollPane(); registeredPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
registeredPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
c.gridx = 2;
c.gridwidth = 1;
c.gridheight = 2;
c.weightx = 1;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
layout.setConstraints(registeredPane, c);
Then I, in my controller, change the model to reflect the courses the currently active student is registered in by calling this function in my model:
public void updateCurrentStudentCourses() {
ArrayList<String> courseNames = new ArrayList<String>();
for (Course c: currentStudent.getRegCourses()) {
courseNames.add("" + c.getDepartment().getId() + c.getCode());
}
System.out.println(courseNames);
}
Then I, again in my controller, update the view to reflect these changes by adding the
ArrayList to the JScrollPane:
public void updateView() {
view.getNameField().setText(model.getCurrentStudent().getName());
view.getRegisteredPane().removeAll();
view.getRegisteredPane().getViewport().add(model.getCurrentStudentCourses());
view.getRegisteredPane().repaint();
}
The scrollbars disappear, but that's it. The list items (which I know are in the ArrayList) are not displayed. What am I doing wrong?
EDIT
If model.getCurrentStudentCourses() is returning an ArrayList then you can put the contents of ArrayList within JTextArea and then set the viewport of JScrollPane to be that JTextArea. You can proceed as follows:
your updateView() method should be like this:
JTextArea ta = new JTextArea(30,100);
public void updateView() {
ta.setText("");
for (String course : model.getCurrentStudentCourses())
ta.append(course+"\n");
view.getNameField().setText(model.getCurrentStudent().getName());
view.getRegisteredPane().setViewportView(ta);
}
To set the view of a scrollpane, use setViewportView(). Manipulating the child components of the scrollpane directly will cause problems (for example, you're removing the scroll bars as well).
Scrollpanes have their own layout manager which only knows about the components created by the scrollpane (the various viewports, the scrollbars, the corners). So, any component you add will not appear unless you manually set its position.

Categories