So I'm making a little sample application that displays train times.
Right now the JTable in which the trains are displayed isn't dynamic.
What I'd like, is for the time to be checked every 30 secs or minute and the table would eliminate a train that "should have arrived".
I'm stuck however at the constantly checking time part. I've created a TimeChecker class to run in the background but it's not much use as when I put a infinite loop or thread into my JPanel class, the user interface doesn't show.
Here's my TimeChecker:
package controller;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class TimeChecker extends Thread {
private String timeStamp;
public String getTimeStamp() {
return timeStamp;
}
public void run() {
while(true) {
try {
Thread.sleep(2000);
String dateStamp = new SimpleDateFormat(
"yyyyMMdd_HHmmss").format(
Calendar.getInstance().getTime());
timeStamp = dateStamp.substring(9,13);
System.out.println(timeStamp);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
and here's my Panel class:
package view;
import java.awt.GridLayout;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import controller.*;
public class Panel extends JPanel {
/* JPanel containing the JTabbedPane stuff */
JTabbedPane jtp = new JTabbedPane();
TimeChecker tc = new TimeChecker();
public Panel() {
super(new GridLayout(1,0));
Table t = new Table("Haymarket");
jtp.add(t);
jtp.setTitleAt(0, "Haymarket");
add(jtp);
tc.setDaemon(true);
tc.start();
}
public void addTrain(String d, String c, String dep, String a) {
/*
* Receives 4 parameters to control
* the new entry required for a train
*/
Table t = (Table) jtp.getComponentAt(jtp.getSelectedIndex());
t.addTrain(d,c,dep,a);
}
public void addStation(String s) {
/*
* Adds a station, after prompting the
* user for a station name
*/
jtp.add(new Table(s));
jtp.setTitleAt(jtp.getTabCount()-1, s);
jtp.setSelectedIndex(jtp.getTabCount()-1);
}
public void addStation(Table t) {
jtp.add(t);
jtp.setTitleAt(jtp.getTabCount()-1,t.getStation());
}
public void removeAllStations() {
jtp.removeAll();
}
public void removeStation() {
/*
* Removes currently selected station
*/
jtp.remove(jtp.getSelectedIndex());
}
public void removeTrain() {
/*
* WIP: Removes a train
*/
Table t = (Table) jtp.getComponentAt(jtp.getSelectedIndex());
t.removeTrain();
}
}
Sounds like you want a javax.swing.Timer to fire every 30 seconds.
Alternatively, use a timer in a background thread (e.g. via a ScheduledExecutorService) - then fetch the information and only get the UI involved when you actually need to update the UI.
You've created a thread from the UI, which means that the thread will run with the same priority as the UI. You should not do that, but use SwingUtilities instead.
Related
Greetings dear Stackoverflowians,
A couple of months ago I was dealing with a ILazyTreeContentProvider, and finally fixed it as per Eclipse RCP - ILazyTreeContentProvider implementation is unexpectedly eager
But I am facing the exact same problem with a ILazyContentProvider, and despite having followed similar steps as with the tree, I am at a loss.
In this table I am adding around 1000 elements per second in the table, and triggering a refresh via setItemCount() on the viewer every 100 ms.
The window size is smaller than 100 rows, and hence the updateElement() method should not start from the first index every time I call setItemCount() on the viewer.
Unfortunately, though, it does. It updates from 0 till the last index, each time.
Here's the code:
package manyelementscontentprovider;
import java.util.List;
import java.util.Vector;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class LargeDataSetTable {
private class MyContentProvider implements ILazyContentProvider {
private TableViewer viewer;
public List<MyEntity> elements;
private int lastIndex=0;
public MyContentProvider(TableViewer viewer) {
this.viewer = viewer;
}
public void dispose() {
}
#SuppressWarnings("unchecked")
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.elements = (List<MyEntity>) newInput;
}
#Override
public void updateElement(int index) {
System.out.println(index);
if (!viewer.isBusy())
viewer.replace(elements.get(index), index);
}
}
public static class MyEntity {
public int counter;
public MyEntity(int counter) {
this.counter = counter;
}
public String toString() {
return "Item " + this.counter;
}
}
List<MyEntity> model;
private int counter;
private Display display;
private TableViewer v;
public LargeDataSetTable(Shell shell, Display display) {
model = createModel();
this.display=display;
v= new TableViewer(shell, SWT.VIRTUAL);
v.setLabelProvider(new LabelProvider());
v.setContentProvider(new MyContentProvider(v));
v.setInput(null);
v.setUseHashlookup(true);
counter = 0;
v.setInput(model);
v.setItemCount(model.size());
v.getTable().setLinesVisible(true);
}
private void startSomeShit() {
final Runnable gooeiUpdate = new Runnable() {
#Override
public void run() {
long timeA = System.currentTimeMillis();
v.setItemCount(counter);
v.setSelection( new StructuredSelection( model.get(counter-1) ), true );
v.setSelection(null);
long timeB = System.currentTimeMillis();
System.out.println("Paint lasted:"+(timeB-timeA));
}
};
Runnable addThingsToModel = new Runnable() {
public void run() {
long currentTime=System.currentTimeMillis();
long howManyGotIn =0;
while (counter<4000000) {
for (int i = 0; i< 10; i++){
final MyEntity m = new MyEntity(counter);
model.add(m);
counter++;
}
if (System.currentTimeMillis()-currentTime>100) {
howManyGotIn=counter - howManyGotIn;
display.syncExec(gooeiUpdate);
currentTime=System.currentTimeMillis();
System.out.println("How many got in = "+howManyGotIn);
howManyGotIn=counter;
}
try {
Thread.sleep(0,25);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread th = new Thread(addThingsToModel);
th.start();
}
private List<MyEntity> createModel() {
List<MyEntity> list = new Vector<MyEntity>(4000000);
return list;
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
LargeDataSetTable viewerCica = new LargeDataSetTable(shell,display);
shell.open();
viewerCica.startSomeShit();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Any sort of suggestions, opinions and options are very appreciated. You guys rock!
The javadoc for
TableViewer.setSelection(ISelection selection, boolean reveal)
states the following:
Sets a new selection for this viewer and optionally makes it visible. The TableViewer implementation of this method is inefficient for the ILazyContentProvider as lookup is done by indices rather than elements and may require population of the entire table in worse case.
Use Table#setSelection(int[] indices) and Table#showSelection() if you wish to set selection more efficiently when using a ILazyContentProvider.
Therefore, you could write something like this:
v.getTable().setSelection(counter - 1);
v.getTable().showSelection();
Using this approach, the paint operation takes an average time of 10ms.
Here is some code snippet from the AbstractTableViewer#virtualSetSelectionToWidget(List list, boolean reveal), which is called, when you use v.setSelection(new StructuredSelection(model.get(counter - 1)), true);:
if (getContentProvider() instanceof ILazyContentProvider) {
ILazyContentProvider provider = (ILazyContentProvider) getContentProvider();
// Now go through it again until all is done or we are no longer
// virtual
// This may create all items so it is not a good
// idea in general.
// Use #setSelection (int [] indices,boolean reveal) instead
for (int i = 0; virtualElements.size() > 0 && i < doGetItemCount(); i++) {
provider.updateElement(i);
Item item = doGetItem(i);
if (virtualElements.contains(item.getData())) {
indices[count++] = i;
virtualElements.remove(item.getData());
if (firstItem == null) {
firstItem = item;
}
}
}
}
as you can see it always iterates over all elements (confessing, that It might not be the best idea), as per Eclipse 3.x. Tree viewer has different implementation (which is actually understandable, that there you actually have kind of visibility levels and in table you don't have those).
I think, that refreshing of elements in general could be handled without dependency on content provider, so that only visible elements are refreshed (at least on demand).
I have the following method within a thread, and it works 100%, but once I remove System.out.println("here"); the code stops doing what it was doing. There are no errors, it just has the appearance of not doing anything. What this does is brightens the colors of an image, with the debug line in it brightens, without it, it doesn't brighten. Why is it causing that?
The thread Class:
package pocketshop.threads;
import com.jogamp.opencl.CLBuffer;
import java.awt.Container;
import java.awt.image.BufferedImage;
import java.nio.FloatBuffer;
import pocketshop.Canvas;
import pocketshop.graphics.CL;
import pocketshop.graphics.Preview;
/**
*
* #author Ryan
*/
public class AdjustThread extends Thread {
protected float amount = 0;
protected CLBuffer<FloatBuffer> buffer;
protected String adjustment;
protected Container parent;
public AdjustThread(Container parent, String adjustment) {
this.parent = parent;
this.adjustment = adjustment;
}
public void setAmount(float amount){
this.amount = amount;
}
public CLBuffer<FloatBuffer> getBuffer() {
return buffer;
}
public void run() {
float cAmount = 0;
while(true){
System.out.println("here");
if(cAmount != this.amount){
cAmount = this.amount;
CL.start(adjustment, this.amount);
buffer = CL.getBuffer();
float[] pixels = CL.getPixels();
BufferedImage newimage = new BufferedImage(Canvas.image.getWidth(), Canvas.image.getHeight(), BufferedImage.TYPE_INT_RGB);
buffer.getBuffer().get(pixels).rewind();
newimage.getRaster().setPixels(0, 0, Canvas.image.getWidth(), Canvas.image.getHeight(), pixels);
Preview.setImage(newimage);
Canvas.preview = Preview.getImage();
parent.repaint();
}
}
}
}
And the Dialog box relevant code:
package pocketshop.dialogs;
import java.awt.image.BufferedImage;
import pocketshop.Canvas;
import pocketshop.graphics.adjustments.Contrast;
import pocketshop.threads.AdjustThread;
/**
*
* #author Ryan
*/
public class BrightnessContrastDialog extends javax.swing.JDialog {
AdjustThread adj;
/**
* Creates new form BrightnessContrastDialog
*/
public BrightnessContrastDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
adj = new AdjustThread(this.getParent(), "Brightness");
adj.start();
}
// Run everytime the JSlider moves
private void sldBrightnessStateChanged(javax.swing.event.ChangeEvent evt) {
float val = sldBrightness.getValue();
txtBrightness.setText("" + (int) val);
adj.setAmount(val);
}
}
Is this.amount declared as volatile?
I take it this field changes by virtue of assignment in another thread. If it's not declared as volatile, there's no reason to assume that the thread running the run() method above will ever observe a change to it. After the first time you assign this.amount to cAmount, they remain equal thereafter—from the point of view of this thread, anyway.
Once you clarify for us the declared qualifiers on this.amount and show the snippet of code where it's changed elsewhere, we can help specify the proper synchronization devices necessary to restore the behavior you desire.
As for why the call to PrintStream#println() seems to make a difference here, it's likely causing not only a delay but may also be hitting a happens-before memory visibility edge that's allowing the changes to this.amount to become visible to this thread. That's a lot of hand-waving, but I think that there are larger problems here to solve first before pegging the root cause for that particular side effect.
I have two classes class Game and class wampusGUI. In wampusGUI class I have one textarea named displayTextArea under the method textarea1().
I am trying to append result to textarea from Game class. but when I am trying to access from that class . the function running fine and also the result is coming in that class (I just tested by simply System.out.print() method), but it is not appending to textarea. Here is my code.
// Code of wampusGUI class
public class wampusGUI extends javax.swing.JFrame {
/**
* Creates new form wampusGUI
*/
public wampusGUI() {
initComponents();
}
public void textArea1(String text) {
System.out.print(text);
displayTextArea.append(text); // this is not appending to textarea.
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new wampusGUI().setVisible(true);
Game g = new Game();
g.testing();
}
});
}
//Here is the code of Game class
private wampusGUI gui;
public void testing () {
String welCome=welcome();
gui= new wampusGUI();
gui.textArea1(welCome);
}
Make this Changes in your code
In Your First Class wampusGUI
public class wampusGUI extends javax.swing.JFrame {
/**
* Creates new form wampusGUI
*/
public wampusGUI() {
initComponents();
}
public void textArea1(String text) {
System.out.print(text);
displayTextArea.append(text); // this is not appending to textarea.
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
wampusGUI w=new wampusGUI();
w.setVisible(true);
Game g = new Game(w);
g.testing();
}
});
}
And for Second class Game
private wampusGUI gui;
//Add Contructor with Parameter
public Game(wampusGUI w){
//put this line of code at the end
gui=w;
}
public void testing () {
String welCome=welcome();
gui.textArea1(welCome);
}
this will work...
To append the text in TextArea
String str = textarea.getText();
str+="appending text";
textarea.setText(str);
It may help you.
You are creating one instance of wampusGUI inside run() of invokeLater, and one instance of wampusGUI inside testing() method.
What you are actually doing is appending the text to an textarea you can't see (probably) because you have the other one instance of wampusGUI set visible.
I have created a textfield that takes all characters from the user.. but i want to disable the space so that user cant enter space ...help??
pin = new TextField("Pin#","",4,TextField.PASSWORD);
If it's a PIN number then maybe you should replace the constraints parameter with TextField.NUMERIC | TextField.PASSWORD.
Implement the ItemStateListener interface. Then call this.setItemStateListener(this) in the Form constructor.
Implement the itemStateChanged method so that if the Item is the one you are interested in then get its content and test it if it contains spaces.
In my case I create a MIDlet and a Form which contains a TextField. And it works. I do not know why did you say that the solution I gave you did not work to you ! Here is a very simple example I give ( I created it and tested it ! ) :
package hello;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloMIDlet extends MIDlet {
public Display display;
public HelloMIDlet() {
display = Display.getDisplay(this);
}
public void startApp() {
Form f = new F(display);
display.setCurrent(f);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
package hello;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.TextField;
public class F extends Form implements ItemStateListener {
private TextField pin = new TextField("PIN :","",4,TextField.PASSWORD);
private Alert alert;
private Display disp;
public F(Display d)
{
super("");
disp = d;
this.setItemStateListener(this);
this.append(pin);
}
public void itemStateChanged(Item item) {
if (item == pin)
{
for (int i=0; i<pin.getString().length(); i++)
{
if (String.valueOf(pin.getString().charAt(i)).equals(new String(" ")))
displayAlert();
}
}
}
private void displayAlert()
{
alert = new Alert("Info","No space please !",null, AlertType.ERROR);
disp.setCurrent(alert, this);
}
}
This is a HW problem. I keep getting the following error on screen related to my if(i==3) statement...
"Exception in thread "AWT-EventQueue-1" java.lang.NullPointerException
at ui.panels.ChoicePanel$1.itemStateChanged(ChoicePanel.java:31)"
...Can someone point me in the right direction? Here is my code. Thanks for your time.
package ui.panels;
import java.awt.Choice;
import java.awt.Panel;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import model.Model;
import interfaces.Resettable;
public class ChoicePanel extends Panel implements Resettable{
public int i = 0;
/**
*
*/
private static final long serialVersionUID = 1L;
Model model;
Choice selection;
public ChoicePanel(Model mdl) {
selection = new Choice();
for (String msg : Model.selections) {
selection.add(msg);
}
selection.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if(i==3) {//drop down clicked three times)
System.out.println("PING");
}else{
model.setMessage(selection.getSelectedItem());
//this line is what sends a value to shape that is drawn on screen
//NOT line 36 of GUIDemo.java
//
model.setCurrentShapeType(selection.getSelectedItem());
model.repaint();
++i;
}
}
});
this.add(selection);
}
public void resetComponents() {
//this resets the drop down list selection array to the first choice on the list
selection.select(0);
//this sets selected item in the selection array set in the above line
model.setMessage(selection.getSelectedItem());
//model.repaint();
}
}
I believe you are not initializing model, which would give a NullPointerException when it was first dereferenced.
You did not initialize model. If i is not 3 the else-block will get executed, which contains model.setMessage(...) - but model does not yet "exist".