This a variant for the classic "wait rpc call problem" in GWT.
I have done a complete CRUD screen in GWT, calling RPC to atack an Oracle database. It has one panel for the search criteria and the results table, and other for the detail fields. I swap the visiblity of both as i need to.
The results table is a CellTable and i call the "setVisibleRangeAndClearData" method to get the table populated, which that takes care for paging, column sort and so on (for example when i come back from an update RPC call i keep the range i came from).
I use to make the "synchro" by putting the "after code" in the "onSuccess" block of the RPC call (i.e. swaping the panels), but when calling "setVisibleRangeAndClearData", the cellTable by itself launches another RPC call to get new data which is out of my control. So, what happens is that i swap the panels (wich is immediate) and after that, the user sees the table data update, which is ugly.
So the question is: How can i control that? How can i wait or get called when the "setVisibleRangeAndClearData" is finisehd?
Thanks in advance,
David
Showing the table right away and then populating it with data is not ugly - in fact, it's the right solution from a UI perspective. Users expect immediate result of their actions, and showing them a loading indicator immediately after they press the button is the right approach.
CellTable has two methods you may find useful:
setLoadingIndicator() - your table should display it until the data arrives;
onLoadingStatusChange().
Related
There is a usability issue when you have a JTable with a huge number of rows in conjunction with the normal TableRowSorter. Sorting on any column will fetch all the values for that column. This is all done on the EDT, which freezes the application for potentially a very long time. It's doubly-bad because it also does the sorting on the EDT even though it doesn't have to.
So I'm wondering whether there is a right way to do this.
I already have a thread-safe TableModel which is safe to call on a background thread. Is there an elegant way to have it fetch the values on another thread instead of doing it on the EDT?
But really, eventually I would like to do the sort at the backend, so perhaps there is an elegant way to hook the table's row sorter up to changing the actual query being used to fetch the data? It's something that I thought was being worked on in some jdesktop project in the past, but I don't think I ever saw what came from that.
In both these situations, there is an associated usability issue of indicating that a sort has been specified but hasn't completed yet, which I'm not entirely sure the JTable look and feel will display, but who knows, maybe it will.
My question in its simplest form: Is it possible to determine the subset of items (or the indices of the corresponding items) currently being displayed in a JavaFX TableView?
The reason I'm asking is that I want to implement lazy loading. Therefore, I subclass ObservableList and implement the code that fetches new items from the database in the overriden E get(int index) (using prefetch/cache). However, the entity objects might be changed by the user and are therefore observed by the database backend. That's why I'd like to detach them as soon as they are not displayed any more.
Many thanks in advance for any suggestions.
You can use VirtualFlow to get the indizes of the first and the last visible cell: Scroll TableView via a Button
However, as I understood it, this is more a hack then a real part of the API. Also you might run into trouble if you have more tables around, it will be triggered each time a table changes.
My program uses Swing table to display data stored in MySQL, while the data is dynamic. I use a thread to repeatedly fetch data from database and refresh the table. I wonder if there are other much wiser methods to do this. Thanks for any suggestion.
as you said, using a single thread to query database and update the UI
is appropriate, am I right?
not, couldn't be true, or yes, everything depends of latency and accessibily of data source(s)
be sure that you'll update only visible Rectangle, cell in the JViewport, on periodical bases, other changes only to notify separatelly (JLabel, ToolTip, SystemTray e.g. ....)
example about JTable and Performance, called as ChristmastTree (lost somwhere after Oracle cleanup Suns tutorial and codesources in last year), bases on standard Workers Thread (before SwingWorker...)
I wonder if there are other much wiser methods to do this.
as I already commnented there are Database notifiers thata firing event when add/ delete/ change is triggered in DB Engine, never tried, can't suggest if use that or not
I have an application in which there are 5 tabs. Each tab has a datagrid. The dataprovider to the datagrid in 1st tab is the common dataprovider to datagrids in other tabs. data in each of the tab varies based on status except for the 1st tab where i display all the data. Now the data for main tab is refreshed every minute using a timer to fetch new data from the backend[Use Blazeds to interact with server side code i.e Java].
After i perform any operation on any of the row in any of the tab other than the 1st one i need to delete the row from that datagrid. I am able to do that by removing the entry from the dataprovider but as soon as i go back to the main tab and return to the tab where i had done the operation i find the deleted entry back. The point to note here is that the entry is not there in the main tab nor it is in the tab where i performed the operation but as soon as i navigate between the tabs it is shown in the UI. But if i do a refresh using F5 it behaves normally.
I was just wondering whether this issue is due to the data caching on the client side and if so what can be a solution to this ?
After you delete the object from the arrayCollection / data - run a collectionName.refresh() on it.
That said, my best guess is that I think you're running into a situation where you're updating a pointer or copy ref rather than the actual data and it's getting reset into that pointer with binding or similar.
If you add a binding listener / change watcher on the object that is bound to the datagrid that traces to console when it gets a CHANGE event, I bet you get a surprise!
(btw, this is how to debug this type of issue quickly).
From your situation its very hard to say without looking at your code. I do agree with the comments passed by the Flextras.
once you deleted it does not show in the tab and when you navigate
to Main tab it does not either show
there and only when you come back
again to the the same tab it does not
get reflected.
It seems there could be an issue with your DB Queries [May be]. Why don't you recheck with your queries where once the delete operation is performed, does the DB tables get reflected or not.
If the above turns out to be false, then get back to the next step.
What does trace() of the dataprovider
give you. I mean what does it
contain? Try this on the select event
of the tab.
Your dataprovider May be holding previous values, though the item from
the grid being deleted is not reflecting the dataprovider. Did you
try to refresh the datagrid or why don't you call invalidateProperties()
method to check.
Once again a some piece of code tabs
could help you and us a lot of time in giving a correct riposte to the question.
I am using 2 Tables (JTable) with their DefaultTableModels.
The first table is already populated.
The second table is populated for each row of the first table (using an SQL Query).
My purpose is to export every line of the first table with it's respective lines of the second in an Excel File.
I am doing it with a for (for each line of 1st table), in which I write a line of the 1st table in the Excel File, then I populate the 2nd table (for this line of 1st Table), I get every line from the Table (from it's Model actually) and put it in the Excel File under the current line of 1st table.
This means that if I have n lines in first table I will clear and populate again the second table n times.
All this code is called in a seperate thread.
THE PROBLEM IS:
Everything works perfectly fine ecxept that I am getting some exceptions.
The strange thing is that I'm not getting anything false in my result.
The Excel file is perfect.
Some of the lines of the exceptions are:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
at java.util.Vector.elementAt(Vector.java:427)
at javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:632)
at javax.swing.JComponent.paint(JComponent.java:1017)
at javax.swing.RepaintManager.paint(RepaintManager.java:1220)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:803)
I am assuming that the problem lies in the fact that the second table needs some more time to be populated before I try to get any data from it. That's why I see RepaintManager and paintDirtyRegions in my exceptions.
Another thing I did is that I ran my program in debug mode and I put a breakpoint after each population of the 2nd table. Then I pressed F5 to continue for each population of 2nd table and no exception appeared. The program came to it's end without any exceptions.
This is another important fact that tells me that maybe in this case I gave the table enough time to be populated.
Of course you will ask me:
If your program works fine, why do you care about the exceptions?
I care for avoiding any future problems and I care to have a better understanding of Java and Java GUI and threads.
Why do you depend on a GUI component (and it's model) to get your information and why don't you recreate the resultset that populates your tables using an SQL Query and get your info from the resultset?
That would be the best and the right way. The fact is that I have the tables code ready and it was easier for me to just get the info from them. But the right way would be to get everything direct from database. Anyway what I did brought out my question, and answering it would help me understand more things about java. So I posted it.
The Swing API is not thread-safe except for a few method calls: repaint, revalidate, and invalidate. All other calls unless otherwise noted for a specific class must be made on the Event Dispatch Thread.
Transferring such call processing from a spawned background/worker thread can be done via SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait().
There is also some specific discussion regarding both JTable and any TableModel that has been attached to an instance of it in the javax.swing package summary javadocs. Neither is thread-safe, so any calls accessing data from them must be performed on the Event Dispatch Thread.
This is the most probable cause of the exceptions you are encountering, and the different behavior that you experience when running in a debugger is a classic sign of a race condition. There is also no reliable way to hack around this via introducing your own locks, etc. Such practices invariably lead to trouble (such as deadlocks with the Event Dispatch Queue lock deep inside the Swing library) in the long run since Swing really, truly was not designed to be thread-safe.
The exception is happening because one of the table models is returning null for a getValueAt(int row,int column) call. The reason for this is probably an internal issue in swing or the data model due to the fact that you are using a secondary thread to access the data models. The swing api specifically states that you can not use a secondary thread in the way you described.
The following article provides further details on the single thread rule in swing.
http://java.sun.com/products/jfc/tsc/articles/threads/threads3.html