I'm currently coding a project Java in eclipse which has two classes. The first class (open) I use to send a specific string to my second class (viewer) and then run my second class. The second class (viewer) I have imported into my program in the form of a jar file. I have done it this way as class viewer is a pdf viewer that i created using apache PDFBox and class open sends the file to the viewer to use, but the file will be different depending on many conditions (that are not relevant) in class open. The point is that class open needs to be separate from class viewer and can not simply be two different methods in one class. I would like to know if there is a way for class open to know when class viewer has been closed, as currently I am using a while loop, which just eats up memory and is very inefficient. The code I have does currently work, but I feel there is a better way, perhaps using listeners. This is the code for closing class viewer:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//and import swing components ect
Public class viewer extends javax.swing.JFrame
implements KeyListener,
ActionListener{
private javax.swing.JButton zoomIn;
private javax.swing.JButton zoomOut;
//and a bunch more swing components
public static boolean closed = false;
public static String fileName = "";
public viewer()
{
}
private void initComponents() throws IOException
{
addWindowListener(new java.awt.event.WindowAdapter()
{
#Override
public void windowClosing(java.awt.event.WindowEvent evt)
{
exitApplication();
}
});
}
private void exitMenuItemActionPerformed(ActionEvent evt)
{
if( document != null )
{
try
{
document.close();
}
catch( IOException e )
{
throw new RuntimeException(e);
}
}
closed = true;
System.exit(0);
}
public static void main(String filename) throws Exception
{
fileName = filename;
viewer mainViewer = new viewer();
String[] splittedStr = fileName.split("/");
BASETITLE = splittedStr[splittedStr.length - 1];
if (fileName != null)
{
mainViewer.openPDFFile(fileName);
}
mainViewer.setVisible(true);
}
This is my code from class open:
public static void main(String[] args) throws Exception {
String fileName = "C:/Files/Test.pdf";
viewer.main(fileName);
while(viewer.closed == false)
{
if(viewer.closed == true)
{
System.out.print("The Viewer Has Been Closed");
}
}
}
I want to know when it is closed so I can delete the file on the local drive. Thanks for your help!
Either you pass a callback (e.g. a Runnable) as argument to viewer.main, like viewer.main(fileName, () -> System.out.print("The Viewer Has Been Closed")) and make sure that it is called when the process is done, or you do as you've done except that you sleep your main thread a short time in the while loop, like Thread.sleep(100).
okay so I actually found an answer to my question and I'll just post it in case someone else had the same problem as me. I added a interface to the open class with the method close as shown:
import mainpackage.viewer;
public class Open implements closeInterface{
public Open() { }
public static String fileName;
public static void main(String[] args) throws Exception {
fileName = "C:/Files/Test.pdf";
run();
}
#Override
public void close() {
System.out.print("The Viewer Has Been Closed");
}
public static void run() throws Exception
{
viewer view = new viewer();
view.main(fileName);
view.addListener(new Open());
}
}
This was my code for my interface:
package mainpackage;
public interface closeInterface {
public void close();
}
And this was the snipit of code for my Viewer class
public class viewer extends javax.swing.JFrame {
private static closeInterface Closed;
private void initComponents() throws IOException
{
addWindowListener(new java.awt.event.WindowAdapter()
{
#Override
public void windowClosing(java.awt.event.WindowEvent evt)
{
exitApplication();
}
});
}
private void exitApplication()
{
try
{
if( document != null )
{
document.close();
}
}
catch( IOException io )
{
//do nothing because we are closing the application
}
Closed.close();
this.setVisible( false );
this.dispose();
}
public void addListener(closeInterface closed){
Closed = closed;
}
}
Thanks for everyone's help!
Related
I have a runnable class "TemperatureSensor" which is periodically adding a new randomized floating point value to an array list TemperatureList as an object Temperature. The last added object in the array (index 0) is then sent from RMI client to RMI server - this happens without problems.
However, when I click a button on GUI to display the size of this object array, I always get a 0. If I print out the size of the array from RMI client class, it shows a correct size.
My question is, how do I access the same array from multiple classes correctly?
Here is the UML:
TemperatureSensor:
import java.text.DecimalFormat;
import java.util.Random;
public class TemperatureSensor implements Runnable
{
private int waitingTime;
private Model model;
public TemperatureSensor(Model model, int waitingTime)
{
this.model = model;
this.waitingTime = waitingTime;
}
#Override
public void run()
{
float temperature = 25.0f;
while(true)
{
temperature = measureTemperature(temperature);
model.addTemperatureData(temperature);
System.out.println("Sending: " + temperature);
waiting();
}
}
private float measureTemperature(float temperature)
{
Random rand = new Random();
float minTempFloat = 0.1f;
float maxTempFloat = 0.2f;
int incrementSwitch = rand.nextInt(3-0) + 0;
if (incrementSwitch == 0)
{
temperature += minTempFloat + rand.nextFloat() * (maxTempFloat - minTempFloat);
}
else if(incrementSwitch == 1)
{
//Do nothing
}
else if (incrementSwitch == 2)
{
temperature -= minTempFloat + rand.nextFloat() * (maxTempFloat -
minTempFloat);
}
return temperature;
}
private void waiting()
{
try
{
Thread.sleep(waitingTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
Model:
public interface Model
{
public void addTemperatureData(float value);
public Temperature getLatestTemperatureData();
public int getTempListSize();
}
ModelManager:
public class ModelManager implements Model
{
private TemperatureList temperatureList;
public ModelManager()
{
temperatureList = new TemperatureList();
}
#Override
public void addTemperatureData(float value)
{
Temperature temperature = new Temperature(value);
//this.temperatureList.clearTemperatureDataList();
this.temperatureList.addTemperatureDataToList(temperature);
}
#Override
public Temperature getLatestTemperatureData()
{
return temperatureList.getLatestTemperatureDataFromList();
}
#Override
public int getTempListSize()
{
return temperatureList.size();
}
}
RMIsensorClient:
import java.rmi.Naming;
import java.rmi.RemoteException;
public class RMIsensorClient
{
private RMIserverInterface serverInterface;
private static Model model = new ModelManager();
public static void main(String[] args) throws RemoteException, InterruptedException
{
TemperatureSensor tempSensor = new TemperatureSensor(model, 5000);
Thread tempThread = new Thread(tempSensor, "TempSensor");
tempThread.start();
RMIsensorClient sensorClient = new RMIsensorClient();
}
public RMIsensorClient() throws RemoteException
{
super();
try
{
serverInterface = (RMIserverInterface) Naming.lookup("rmi://localhost:1099/rmiServer");
while(true)
{
serverInterface.getTemperature(model.getLatestTemperatureData());
System.out.println(model.getTempListSize());
Thread.sleep(5000);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Controler:
public class Controller
{
private static Model model;
public Controller ()
{
this.model = new ModelManager();
}
public int getNumberOfListElements()
{
return model.getTempListSize();
}
}
GUI:
public class GUItemperatureController implements Initializable
{
private Controller controller = new Controller();
#FXML
private Label tlTemperature;
#FXML
private Pane mainPane;
#FXML
private TextField tfTemperature;
#FXML
private Button btnUpdate;
#Override
public void initialize(URL arg0, ResourceBundle arg1)
{
tfTemperature.setEditable(false);
}
#FXML
void showArraySize(ActionEvent event)
{
tfTemperature.setText(Integer.toString(controller.getNumberOfListElements()));
}
}
TemperatureList:
import java.io.Serializable;
import java.util.ArrayList;
public class TemperatureList implements Serializable
{
private ArrayList<Temperature> temperatureList;
public TemperatureList()
{
this.temperatureList = new ArrayList<>();
}
public void addTemperatureDataToList(Temperature temperature)
{
temperatureList.add(0,temperature);
}
public Temperature getLatestTemperatureDataFromList()
{
return this.temperatureList.get(0);
}
public void clearTemperatureDataList()
{
temperatureList.clear();
}
public int size()
{
return temperatureList.size();
}
}
Here is where I launch the GUI:
import java.rmi.RemoteException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class userMain extends Application
{
public FXMLLoader loader;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXML/FXMLtemperature.fxml"));
loader.setController(new GUItemperatureController());
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setTitle("GEMS - Test");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Your problem is not about classes.
You run two separate applications. One runs your RMIsensorClient and one runs your GUI. They know nothing about each other, your RMIsensorClient and your Controller have their own separate instances of ModelManager and you have no code anywhere that would share any data between them.
You need to make the data you want to show in your GUI accessible somehow.
One solution could be to use a network interface for that. Create two different ModelManagers, one that opens and listens to a ServerSocket, and one that uses a Socket in getLatestTemperatureData() to connect to the other one.
Use the former in your RMIsensorClient and the latter in your GUI's Controller.
Research networking in Java.
This is a very crude solution, but there are plenty of great tutorials for networking and sharing data between multiple Java applications.
You haven't included your TemperatureList implementation, but if as you say it's an ArrayList it's likely you're not properly synchronizing access across threads. It's imperative that you properly synchronize cross-thread work otherwise you'll wind up with some sort of undefined behavior, such as changes not propagating or data structures winding up broken.
There are a number of thread-safe collections in java.util.collect.concurrent that you might consider, otherwise you'll need to ensure you use synchronized blocks or methods anywhere you're working with this list.
The most obvious problem that I found(and this might not be all) is that your array list is method specific. it is not static. Meaning that it can only be accessed by the method it originates in. the easiest fix for this is to add a static modifier to your array list when it is created and create it outside of the methods.
I have a class named Parser which gets some input and do some calculations and output the results. I also have a jFrame, which has some text fields. I am misunderstanding how to run the parser and use the inputs from the jFrame. I don't know if I should implement the action Listener in my Parser class? or should I import all my Parser class methods in the jFrame? should I have run method in my main of the Parser or should I use the void run in the jframe class??
Here is my class Parser:
public class Parser{
public static List getXKeywords(String Url, int X, String html) throws Exception {
//somemethod with someoutput
}
public static void main(String[] args) throws Exception {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
SpyBiteDemo Sp = new SpyBiteDemo();
Sp.setVisible(true);
int X=Sp.getKeywordcount();
//this top line is not correct because it can only be done when the jframe jButton1 was clicked
}
});
}
}
and here is the jFrame;
public class SpyBiteDemo extends javax.swing.JFrame {
/**
* Creates new form SpyBiteDemo
*/
public SpyBiteDemo() {
initComponents();
}
public String getKeywordcount()
{
return jTextField4.getText();
}
//some methods
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//get the input from the jframe
//feed it to the parser?? how???
String SeedUrl=jTextField1.getText();
Parser P=new Parser();
//I don't have access to methods
because they are static
}
}
here I am trying to get keywordcount variable from the jFrame which is the int X in the getXKeywords method.
I solved my problem with the help of this link
I created a constructor in my parser class and also included a jframe in the parser class as follow:
public class Parser {
SpyBiteDemo Sp=new SpyBiteDemo();
public Parser(SpyBiteDemo Sp)
{
this.Sp=Sp;
int X = Sp.getXKeywords();
//do whatever
}
and in the action performed of the jframe class I call my parser constructor class:
public class SpyBiteDemo extends javax.swing.JFrame {
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Parser P=new Parser(this);
}
}
I am trying to get the OnTurnBasedMatchUpdateReceivedListener to trigger but it doesn't seem to work. Below is my code example that I am using. I get a valid GoogleApiClient and am already signed in (I have other Listeners going in other parts of code).
The goal is to have a single class that can handle this event, by passing the GoogleApiClient through and have it callback here (I have no other way of getting code to trigger such as the BaseGameActivity because the code is within another LIB and I am writing additional code).
Any suggestions on how to debug this?
package com.google.example.games.pluginsupport;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.games.Games;
import com.google.android.gms.games.multiplayer.turnbased.OnTurnBasedMatchUpdateReceivedListener;
import com.google.android.gms.games.multiplayer.turnbased.TurnBasedMatch;
public class TurnBaseMatchHelper implements OnTurnBasedMatchUpdateReceivedListener {
public interface TurnBasedMatchListener {
void onTurnBasedMatchReceived(TurnBasedMatch match);
void onTurnBasedMatchRemoved(String matchId);
}
private static TurnBaseMatchHelper turnbaseInterface = null;
private TurnBasedMatchListener sTurnBasedMatchListener = null;
public static void registerTurnBasedCallbacks(GoogleApiClient _googleApiClient, TurnBasedMatchListener sListener) {
if (turnbaseInterface == null) {
turnbaseInterface = new TurnBaseMatchHelper();
}
turnbaseInterface.sTurnBasedMatchListener = sListener;
Log.d("Unity", "registerTurnBasedCallbacks");
Games.TurnBasedMultiplayer.registerMatchUpdateListener(_googleApiClient, turnbaseInterface);
}
#Override
public void onTurnBasedMatchReceived(TurnBasedMatch match) {
Log.d("Unity", "onTurnBasedMatchReceived");
if (turnbaseInterface.sTurnBasedMatchListener != null) {
sTurnBasedMatchListener.onTurnBasedMatchReceived(match);
}
}
#Override
public void onTurnBasedMatchRemoved(String matchId) {
Log.d("Unity", "onTurnBasedMatchRemoved");
if (turnbaseInterface.sTurnBasedMatchListener != null) {
sTurnBasedMatchListener.onTurnBasedMatchRemoved(matchId);
}
}
}
here is my similar problem answer.
From post:
Go to the Settings -> Account and sync-> turn on Auto-sync checkbox
Sorry, if this is a stupid question.
I would like to find out how to call the run method that is located in
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FereastraPrincipala().setVisible(true);
from the class AdaugaComanda.java.
The run method is declared in FereastraPrincipala.java and I want to call this from AdaugaComanda.java, so that changes can be seen to FereastraPrincipala after introducing values in the textfields from AdaugaChitanta.java. If I don't call a method, then I have to run FereastraPrincipala.java again, in order to see the new info in the JTabbedPane.
Here is the code for FereastraPrincipala.java
package sakila.ui;
import java.util.List;
import java.util.Vector;
import javax.swing.table.DefaultTableModel;
import org.hibernate.Session;
import sakila.entity.*;
import sakila.util.HibernateUtil;
public class FereastraPrincipala extends javax.swing.JFrame {
public FereastraPrincipala() {
initComponents();
}
private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {
AdaugaComanda ac = new AdaugaComanda();
ac.setVisible(true);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FereastraPrincipala().setVisible(true);
Session session = HibernateUtil.getSessionFactory().openSession();
try{
List<Comanda> comenzi = session.createQuery("from Comanda").list();
Vector<String> tableHeaders = new Vector<String>();
Vector tableData = new Vector();
tableHeaders.add("IdComanda");
tableHeaders.add("Depozit");
tableHeaders.add("Furnizor");
tableHeaders.add("Client");
tableHeaders.add("Produs");
tableHeaders.add("Cantitate");
tableHeaders.add("Unit de mas");
for (Comanda comanda : comenzi) {
Vector <Object> oneRow = new Vector <Object>();
oneRow.add(comanda.getIdcomanda());
oneRow.add(comanda.getDepozit() == null ? "" : comanda.getDepozit().toString());
oneRow.add(comanda.getFurnizor() == null ? "" : comanda.getFurnizor().toString());
oneRow.add(comanda.getClient() == null ? "" : comanda.getClient().toString());
oneRow.add(comanda.getProdus() == null ? "" : comanda.getProdus().toString());
oneRow.add(comanda.getCantitate());
oneRow.add(comanda.getUnitmas());
tableData.add(oneRow);
}
ComandaTable.setModel(new DefaultTableModel(tableData, tableHeaders));
}catch (Exception he){
he.printStackTrace();
}
}
});
}
}
Here is the code for AdaugaComanda.java
package sakila.ui;
import java.io.EOFException;
import java.util.List;
import sakila.entity.*;
import sakila.service.Functie;
import sakila.entity.Client;
public class AdaugaComanda extends javax.swing.JDialog {
public AdaugaComanda() {
initComponents();
initComboBoxes();
}
private void initComboBoxes() {
DepozitComboBox.removeAllItems();
FurnizorComboBox.removeAllItems();
ClientComboBox.removeAllItems();
ProdusComboBox.removeAllItems();
System.out.println("sterge itemurile");
List<Depozit> depozite = (List<Depozit>) sakila.client.Client.citeste(Functie.LISTEAZA_DEPOZITE);
for (Depozit depozit : depozite)
DepozitComboBox.addItem(depozit);
List<Furnizor> furnizori = (List<Furnizor>) sakila.client.Client.citeste(Functie.LISTEAZA_FURNIZORI);
for (Furnizor furnizor : furnizori)
FurnizorComboBox.addItem(furnizor);
List<Client> clienti = (List<Client>) sakila.client.Client.citeste(Functie.LISTEAZA_CLIENTI);
for (Client client : clienti)
ClientComboBox.addItem(client);
List<Produs> produse = (List<Produs>) sakila.client.Client.citeste(Functie.LISTEAZA_PRODUSE);
for (Produs produs : produse)
ProdusComboBox.addItem(produs);
System.out.println("adaugaitemuri");
}
private void ClientComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
private void InsereazaButtonActionPerformed(java.awt.event.ActionEvent evt) {
runQueryBasedOnInsert();
}
private void runQueryBasedOnInsert(){
Comanda comanda = new Comanda();
Depozit depozit = (Depozit)DepozitComboBox.getSelectedItem();
comanda.setDepozit(depozit);
Furnizor furnizor = ((Furnizor)FurnizorComboBox.getSelectedItem());
comanda.setFurnizor(furnizor);
sakila.entity.Client client = ((sakila.entity.Client)ClientComboBox.getSelectedItem());
comanda.setClient(client);
Produs produs = ((Produs)ProdusComboBox.getSelectedItem());
comanda.setProdus(produs);
comanda.setCantitate(Integer.parseInt(CantitateTextField.getText()));
comanda.setUnitmas(UnitMasTextField.getText());
sakila.client.Client.scrie(Functie.CREAZA_COMANDA, comanda);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new AdaugaComanda().setVisible(true);
}
});
}
Maybe someone could help me. Thank you a lot!
You could make FereastraPrincipala a member variable of AnduagaChitanta.
public class AnduagaChitanta
{
FereastraPrincipala fPrincipala = new FereastraPrincipala (); //Or inject it into the constructor
private void SomeMethod()
{
fPrincipala.run();
}
}
in the run method()
public void run()
{
setvisible(true);
}
If you are wondering how to inject it:
public class AnduagaChitanta
{
FereastraPrincipala fPrincipala
public AnduagaChitanta(FereastraPrincipala fPrinicipala)
{
this.fPrinicipala = fPrinicipala;
}
private void SomeMethod()
{
fPrincipala.run();
}
}
If you like you can make FereastraPrincipala implement an interface so the definition of the constructor can be:
public AnduagaChitanta(ISomethingPrinicipala fPrinicipala)
But now we are going into design patterns so I will leave it at that.
Update
After your update I would do something like this:
FereastraPrincipala extends JFrame implements Runnable
{
public void run()
{
setvisible(true) ;
}
}
I don't know where but maybe in your AnduagaChitanta class I would do this
public void SomeMethod()
{
java.awt.EventQueue.invokeLater(fPrinicpala)
}
I hope that makes sense
Never call run() method of thread. It executes in the current thread it self !! Always call start() method. Coming to your case, create a new class so that you could invoke start() on it from other places
my code, being practically identical to the code given in BlackBerry's tutorial, has a syntax error in Eclipse. i'm sure there is some small but i'm just not seeing, but my coworker could not find it as well. any ideas would be greatly appreciated. thanks!
Code:
pushScreen(new ABCScreen());
Error:
Cannot make a static reference to the
non-static method pushScreen(Screen)
from the type UiApplication
here is the complete source:
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
public class AwesomeBBCalculator extends UiApplication {
public AwesomeBBCalculator() {
AwesomeBBCalculator app = new AwesomeBBCalculator();
app.enterEventDispatcher();
}
public static void main(String[] args) {
pushScreen(new ABCScreen()); // ERROR LINE
}
}
final class ABCScreen extends MainScreen {
public ABCScreen() {
super();
// add title
LabelField title = new LabelField("Awesome BlackBerry Calculator",
LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);
setTitle(title);
}
public boolean onClose() {
Dialog.alert("Thanks for using the Awesome BlackBerry Calculator!\nGoodbye.");
System.exit(0);
return true;
}
}
The pushScreen method can only be called within an instance of UiApplication. You are trying to call it from a static main method. That does not work. Do this instead...
public void foo()
{
pushScreen(this);
}
public static void main(String[] args)
{
(new ABCScreen()).foo();
}
public void class1()
{
pushScreen(this);
}
public static void main(String[] args)
{
(new NewScreen()).class1();
}
try making an object for the ABCScreen class and then use it or u may try this also:
UiApplication.getUiApplication().pushScreen(new ABCScreen());