问题
I have developed a piece of software that creates an Ontology using neo4j. Once the ontology is built, I start mapping the dataset of 2 million rows to it, which takes more or less 20 minutes to be completed. As a result, I wished to add a JFrame that shows the process execution. The code below creates at the beginning the JFrame and then it starts mapping the dataset. However, I can see during the execution the JFrame, but its components appears inside the JFrame after the mapping finishes. I have read that the problem might be due to the lack of a thread that surrounds the code. Can anyone help me in solving this matter??
void createGraphDataset(String [][] choices , final ArrayList<String[]> DatabaseFile, GraphDatabaseService BORO_DB){
JFrame converterFrame = new JFrame();
converterFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
converterFrame.setBounds(100, 100, 650, 288);
JPanel contentPane = new JPanel();
contentPane.setLayout(null);
contentPane.setVisible(true);
converterFrame.getContentPane().add(contentPane);
JPanel panelNeo1 = new JPanel();
panelNeo1.setBounds(6, 6, 638, 254);
panelNeo1.setVisible(true);
contentPane.add(panelNeo1);
panelNeo1.setLayout(null);
JLabel labelNeo1 = new JLabel("CSV BORO Converter");
labelNeo1.setBounds(16, 19, 260, 37);
panelNeo1.add(labelNeo1);
labelNeo1.setVisible(true);
JPanel panelNeo2 = new JPanel();
panelNeo2.setBounds(16, 60, 605, 167);
panelNeo1.add(panelNeo2);
panelNeo2.setLayout(null);
panelNeo2.setVisible(true);
/*
JProgressBar progressBar = new JProgressBar();
progressBar.setBounds(27, 89, 547, 20);
panelNeo2.add(progressBar);
panelNeo2.setVisible(true);
*/
JLabel labelNeo2 = new JLabel(" Processing: Number of row");
labelNeo2.setOpaque(true);
labelNeo2.setBounds(28, 36, 184, 20);
panelNeo2.add(labelNeo2);
labelNeo2.setVisible(true);
JLabel labelNeo3 = new JLabel("");
labelNeo3.setBounds(212, 36, 76, 20);
panelNeo2.add(labelNeo3);
labelNeo3.setVisible(true);
JLabel labelNeo4 = new JLabel();
labelNeo4.setText(String.valueOf(DatabaseFile.size()));
labelNeo4.setBounds(311, 36, 70, 20);
panelNeo2.add(labelNeo4);
labelNeo4.setVisible(true);
JLabel labelNeo6 = new JLabel("of");
labelNeo6.setBounds(288, 36, 23, 20);
panelNeo2.add(labelNeo6);
labelNeo6.setVisible(true);
converterFrame.setVisible(true);
TopNode= new Node [DatabaseFile.get(0).length];
//Create TopNodes
Transaction tx0 = BORO_DB.beginTx();
try{
for(int u =0; u<DatabaseFile.get(0).length;u++){
TopNode[u]=BORO_DB.createNode();
TopNode[u].setProperty("name", choices[u][0]);
}
tx0.success();
}
finally{
tx0.finish();
}
//Create the database
for(int i =0; i<DatabaseFile.size();i++){
Transaction tx2 = BORO_DB.beginTx();
try
{
// Nodes for each row
Node []graphNode= new Node [DatabaseFile.get(i).length];
// Relationships for each row ingoing
Relationship [] graphRelOn = new Relationship [DatabaseFile.get(i).length-1];
// Relationships for each row outgoing
Relationship [] graphRelOut = new Relationship [DatabaseFile.get(i).length-1];
//Relationship to TopNode ingoing
Relationship TopNodeRelIn[]=new Relationship [DatabaseFile.get(i).length];
//Creates Nodes for row and relationship to TopNode
for(int j=0; j<DatabaseFile.get(i).length;j++){
//Stores Database values
String []ValuesRow =DatabaseFile.get(i);
//Creates nodes for 1 row
graphNode[j] = BORO_DB.createNode();
graphNode[j].setProperty("name", ValuesRow[j]);
//From row to TopNode Relationship (enter)
TopNodeRelIn[j]=graphNode[j].createRelationshipTo(TopNode[j], RelTypes.typeInstances);
TopNodeRelIn[j].setProperty("relationship-type", "typeInstances");
}
//Creates Relationships
for(int k=0; k<(DatabaseFile.get(i).length)-1;k++){
//Between same elements of the same row (left to right)
graphRelOn[k]=graphNode[k].createRelationshipTo(graphNode[k+1], RelTypes.relatesTo);
graphRelOn[k].setProperty("relationship-type", "relatesTo");
//Between same elements of the same row (right to left)
graphRelOut[k]=graphNode[(DatabaseFile.get(i).length)-1].createRelationshipTo(graphNode[(DatabaseFile.get(i).length)-(2+k)], RelTypes.relatesTo);
graphRelOut[k].setProperty("relationship-type", "relatesTo");
}
tx2.success();
}
finally
{
tx2.finish();
}
}
}
回答1:
Your are right, your problem has to do with the problem that the Thread responsible for painting the components is blocked by your operation. However, explaining all aspects of multi-threaded programming is beyond the scope of a single answer.
As a workaround you can just delay the computation.
// setup the GUI
frame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
public void run()
{
doYourHavyComputation();
}
});
This way your computation still runs within the same thread and blocks the UI but at a later time when the initial frame contents has been painted.
If you wanna do real background computation you have to study one or more tutorials about multi-threading to understand all the complications then try it and come back if you have more specific questions.
回答2:
I have read that the problem might be due to the lack of a thread that surrounds the code
Would be a suitable assumption. Swing is a single threaded environment, which means, all interactions and updates to the UI are required to be made within the context of the Event Dispatching Thread. Equally in action or operation which blocks this thread will prevent the EDT from processing (amongst other things) paint requests.
While there are a number of possible solutions, the best suited to your needs is probably the SwingWorker
.
This allows you to run lengthy operations in a background thread, but has a number of methods by which you can re-sync the out comes of these operations back to the EDT.
Check out Concurrency in Swing for more details.
How you use it will depend on your needs...
For example, you could simply "publish" the current row your are processing...
public class Generator<Node , Integer> {
protected void process(List<Integer> rows) {
// Back in the EDT
int lastRow = rows.get(rows.size() - 1); // Only interested in the last one...
// Update the UI...
}
protected Node doInBackground() throws Exception {
Node topNode = new Node [DatabaseFile.get(0).length];
/*...*/
publish(rowNumber);
/*...*/
return topNode;
}
public void done() {
// Back in the EDT
try {
Node topNode = get(); // Get the result of the calculation...
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
Or you could take advantage of the SwingWorker
's property change support and use it's in built setProgress
method.
See...
- JProgressBar isn't progressing
- How to use the Swing Timer to delay the loading of a progress bar
For some examples.
These will ensure that whole you a processing your calculations, the UI remains responsive to your changes
来源:https://stackoverflow.com/questions/18508085/i-cant-see-the-jframe-components-until-the-end-of-dataset-mapping-why