Optimizing JTextArea Text Drawing - java

So, I'm trying to make a little program to display chat logs from a certain app in a custom way. I alredy built my GUI, and I can read the messages from the .txt file. My problem is, when I print them on the console, the program takes about 1.5 seconds to process the 17k line file. But, when I try to show the text on the GUI, it takes around a minute and a half, and I have no idea why.
To read the text from the file, I'm using a BufferedReader. And to show the text on a JTextArea, and all I'm doing is the following:
JTextArea.append(myString+"\n");
My test file is around 1,000,000 characters long, if that's any help. I'd really like to know what's happening, and maybe some advice on how to fix it. Thanks in advance.

Use a StringBuilder to build the String and then just call setText() once one the TextArea so you don't force a repaint of the area for each line.
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(() -> {
JFrame frame =new JFrame();
JTextArea area = new JTextArea();
JScrollPane pane = new JScrollPane(area);
frame.add(pane);
frame.setPreferredSize(new Dimension(400,400));
frame.pack();
frame.setVisible(true);
long t1 = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
area.append(i+"\n");
}
long t2 = System.currentTimeMillis();
System.out.println("(t2-t1) = " + (t2-t1));
StringBuilder sb = new StringBuilder();
long t3 = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
sb.append(i+"\n");
}
long t4 = System.currentTimeMillis();
area.setText(sb.toString());
System.out.println("(t4-t3) = " + (t4-t3));
});
}
prints:
(t2-t1) = 2871
(t4-t3) = 26
The first time difference was measured with JTextArea.append() the second with StringBuilder.append() followed by JTextArea.setText().

Related

RCaller, thread handling, and a Java GUI

I am making a Java GUI to go with my colleague's custom made R package, IntramiRExploreR, which includes a function made to create an interactive graphic via igraph and IntramiRExploreR's Visualisation function, using the following parameters:
Visualisation(miR,mRNA_type=c('GeneSymbol'),method,thresh,platform=Platform,visualisation = 'igraph',layout = 'interactive')
where miR is a vector made via selected JCheckboxes, and method, thresh, and platform are populated from JRadioButtons. I've no doubt the function itself and how the variables are filled in is correct, as I have run the function in R and run the function using a text output format and both run correctly.
The code first fills out a JTable correctly with the results from
Visualisation(miR,mRNA_type=c('GeneSymbol'),method,thresh,platform=Platform)
which outputs text accessible using
caller.getParser().getAsStringArray(//one of seven parameters)
then provides a JButton to use the same parameters and objects to call the aforementioned igraph function in R. However, when the JButton is clicked, the igraph is created but then its frame is disposed as soon as the graphic is fully made. The second time the button is clicked, calling the function again, the provided error is:
Exception in thread "AWT-EventQueue-0" com.github.rcaller.exception.ExecutionException: Can not run C:\Program Files\R\R-3.3.0\bin\x64\Rscript.exe. Reason: java.lang.IllegalThreadStateException
Should I create new thread to handle the igraph visualisation, or is there some method in RCaller I am missing that can handle this? Is Java emptying its memory of my objects after I call a second RCaller and RCode block?
Here's what of my code I can show without violating my agreement to confidentiality:
public void actionPerformed(ActionEvent e){//if goButton is clicked
if(e.getSource() == goButton){
JFrame resultFrame = new JFrame("Results: For full readout, use export button below.");//creates entire resultFrame
resultFrame.setLayout(new BorderLayout());
resultFrame.setSize(new Dimension(950,750));
JPanel resultBack = new JPanel();
resultBack.setLayout(new BorderLayout());//creates the resultBack to be placed into JScrollPane
//RESULTS (from user query; calls R commands to fill out JTable)
//create int checkCnt to keep track of how much info is needed
int checkCnt = 0;
for(int t = 0;t<155;t++){
if(selected[0][t]==true){//if targets for one miR with index t is queried
checkCnt++;
}}
//create JTable
//create column names
String[] colNames = {"miRNA", "tar_GS", "tar_FB", "tar_CG", "Score", "Function", "Experiment", "Method"};
//determine threshold
int threshold=0;
if(checkCnt==1){threshold=100;}
if(checkCnt==2){threshold=50;}
if(checkCnt==3){threshold=33;}
if(checkCnt==4){threshold=25;}
if(checkCnt>=5){threshold=20;}
/*create RCaller and wire query to buttons;
code handles table filling,
///code1 handles graphic display*/
RCaller caller = RCaller.create();
RCaller caller1 = RCaller.create();
RCode code = RCode.create();
RCode code1 = RCode.create();
code.R_require("IntramiRExploreR");
code.R_require("futile.logger");
code.R_require("devtools");
code.R_require("Runiversal");
code1.R_require("IntramiRExploreR");
code1.R_require("futile.logger");
code1.R_require("devtools");
//create array of selected miRs to input to R code
String[] chosen = new String[checkCnt];
for(int kk=0;kk<checkCnt;kk++){
chosen[kk] = litmiR(selected)[kk];
}
code.addStringArray("miR", chosen);
code.addInt("thresh", threshold);
code1.addStringArray("miR", chosen);
code1.addInt("thresh", threshold);
String method =new String();
if(Pears.isSelected()){
method="Pearson";
code.addString("method", method);
code1.addString("method", method);
}
else if(Dist.isSelected()){
method="Distance";
code.addString("method", method);
code1.addString("method", method);
}
else{
method="Both";
code.addString("method", method);
code1.addString("method", method);
}
if(Affy1.isSelected()){
String Platform="Affy1";
code.addString("Platform", Platform);
code1.addString("Platform", Platform);
}
else{
String Platform="Affy2";
code.addString("Platform", Platform);
code1.addString("Platform", Platform);
}
code.addRCode("yy <-Visualisation(miR,mRNA_type=c('GeneSymbol'),method,thresh,platform=Platform)");
String [] aa= caller.getParser().getAsStringArray("miRNA");
String [] aa1= caller.getParser().getAsStringArray("Target_GeneSymbol");
String [] aa2= caller.getParser().getAsStringArray("Targets_FBID");
String [] aa3= caller.getParser().getAsStringArray("Targets_CGID");
double [] aa4= caller.getParser().getAsDoubleArray("Score");
//convert double array to string array
String [] sa4= new String[aa4.length];
for(int ss=0;ss<aa4.length;ss++){
sa4[ss]= Double.toString(aa4[ss]);
}
String [] aa5 = caller.getParser().getAsStringArray("GeneFunction");
String [] aa6 = caller.getParser().getAsStringArray("Experiments");
//create JTable objects
String[][] results = new String[checkCnt*threshold][8];
int w = 0;
int x = 0;
for(int n=0;n<checkCnt;n++){
for(int jj=0;jj<threshold;jj++){//first miR
results[jj+w][0]=aa[jj+x*threshold];//the first miR, then the next one after n loops once
results[jj+w][1]=aa1[jj+x*threshold];//tar_GS
results[jj+w][2]=aa2[jj+x*threshold];//tar_FB
results[jj+w][3]=aa3[jj+x*threshold];//tar_CG
results[jj+w][4]= sa4[jj+x*threshold];//Score
results[jj+w][5]=aa5[jj+x*threshold];//Function
results[jj+w][6]=aa6[jj+x*threshold];//Experiment
}
w=w+threshold;
x++;
}
System.out.println(checkCnt);
//make JTable
JTable resultTable = new JTable(results, colNames);
//create scroll pane to embed results JTable in; allow for vertical scrolling
JScrollPane scrollTable = new JScrollPane(resultTable);
resultTable.setFillsViewportHeight(true);
scrollTable.setPreferredSize(new Dimension(resultBack.getWidth(),(resultFrame.getHeight()-150)));
scrollTable.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollTable.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollTable.getVerticalScrollBar().setUnitIncrement(12);
//create bottom buttonPanel to allow for visualization, exportation, and ontological research
JPanel buttonPanel = new JPanel();
buttonPanel.setPreferredSize(new Dimension(200, 150));
buttonPanel.setBackground(Color.LIGHT_GRAY);
buttonPanel.setLayout(null);
//create buttons
JButton gOnt = new JButton("Gene Ontology");
gOnt.setFont(new Font("Arial", Font.PLAIN, 18));
gOnt.setBorder(BorderFactory.createLineBorder(Color.BLACK));
gOnt.setBounds(50,50,250,100);
buttonPanel.add(gOnt);
JButton vis = new JButton("Visualization");
vis.setFont(new Font("Arial", Font.PLAIN, 18));
vis.setBorder(BorderFactory.createLineBorder(Color.BLACK));
vis.setBounds(650,50,250,100);
buttonPanel.add(vis);
vis.addActionListener(new ActionListener(){
**public void actionPerformed(ActionEvent v){
if(v.getSource() == vis){
code1.addRCode("yy1<-Visualisation(miR,mRNA_type=c('GeneSymbol'),method,thresh,platform=Platform,visualisation = 'igraph',layout = 'interactive')");
caller1.setRCode(code1);
caller1.runAndReturnResult("yy1");
}
}
});**
JButton exp = new JButton("Export as .txt file");
exp.setFont(new Font("Arial", Font.PLAIN, 18));
exp.setBorder(BorderFactory.createLineBorder(Color.BLACK));
exp.setBounds(350, 50, 250, 100);
buttonPanel.add(exp);
resultFrame.setLocation(470,150);//add in the panels and display the resultFrame
resultFrame.add(buttonPanel, BorderLayout.PAGE_END);
resultFrame.add(scrollTable, BorderLayout.PAGE_START);
resultFrame.setVisible(true);
}}});
The area of concern is the ActionListener for my JButton vis. I am absolutely certain that all else is well, but the igraph is unresponsive at first after populating and then a second call provides the IllegalThreadException error.
This is what I would check first:
The GUI can NOT be modified from a NON gui thread.
Make sure you have a background thread that passes the info to the GUI. Otherwise the GUI will become unresponsive until it finishes the processing (this is in the scenario of no background thread)
You can always put a gui runnable around the actionPerformed code.
In your case
SwingUtilities.invokeLater(new Runnable() {...});

How to make Java GUI settext recognize new lines for a 2 dimensional array input

I have a char[xSize][ySize] being sent to my GUI. The GUI prints the long string as one long line without recognizing the new lines in it. What method or code could I use?
The code I currently use is:
JFrame frame1 = new JFrame("Start Screen");
JLabel label = new JLabel();
frame1.setVisible(true);
frame1.setSize(500, 500);
frame1.setLayout(new BorderLayout());
frame1.add(label, BorderLayout.NORTH);
//Code to recieve from other program:
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
String Sentence = new String(receivePacket.getData());
//Print received text to GUI:
label.setText(Sentence);
Thanks in advance
For something JLabel, you would need to first replace the new lines (\n) with <br> and wrap the text in <html>...</html>
String Sentence = new String(receivePacket.getData());
//Print received text to GUI:
label.setText("<html>" + Sentence.replaceAll("\n", "<br>") + "</html>");
Or you might be able to use a non-editable JTextArea instead...

Text area doesn't seem to be working

I am try to create a text area that will display a list of scores. For some reason though, the text area only expands when someone types in it, and the user should not even be allowed to type in it. I thought i wrote in the code for it properly but for some reason it doesn't seem to work. The "hello" phrase I appended isn't even displaying in the text area. Can anyone provide some advice:
public HighScores() throws FileNotFoundException, IOException{
frame.setVisible(true);
frame.setSize(400,200);
frame.add(main);
GridBagConstraints g = new GridBagConstraints();
g.insets = new Insets(10,10,10,10);
g.gridx = 0;
g.gridy = 0;
main.add(highscorespanel, g);
highscorespanel.add(highscores);
g.gridx = 0;
g.gridy = 1;
main.add(textareapanel, g);
Color c = textareapanel.getBackground();
textareapanel.setBackground(c);
textareapanel.add(ta);
ta = new JTextArea ();
ta.setVisible(true);
ta.setEnabled(true);
ta.setEditable(false);
ta.append("hello");
JScrollPane sp = new JScrollPane(ta);
BufferedReader br = new BufferedReader(new FileReader("src/BattleShip/scores.txt"));
String namescore = br.readLine();
while(namescore!=null){
ta.append("\t"+namescore);
}
Im almost sure you don't need the answer anymore but you need to move your line "textareapanel.add(ta);" to some point after you initialize ta.
ta = new JTextArea();
textareapanel.add(ta);
ta.setVisible(true);
ta.setEnabled(true);
ta.setEditable(false);
EDIT:
At a second look you want a JScrollPane for your JTextArea so you code should be like this:
JTextArea ta = new JTextArea();
ta.setVisible(true);
ta.setEnabled(true);
ta.setEditable(false);
JScrollPane sp = new JScrollPane(ta);
textareapanel.add(sp);

Java JTable data loading

so i have a large cardlayout with one panel as a JTable:
tbm = new DefaultTableModel();
tbm.addColumn("Account Number");
tbm.addColumn("PIN");
tbm.addColumn("Access Level");
tbm.addColumn("Balance");
table = new JTable(tbm);
JScrollPane scrollPane = new JScrollPane(table);
under actionPerformed, I am trying to load some data into the table as follows:
else if(event.getSource() == listallButton) {
String query = "SELECT * FROM ATM";
String delimiter = ",";
String input = "go";
int count=0;
al = new ArrayList<String>();
try {
communicationObject = new DataObject();
communicationObject.setMessage(query);
Socket socketToServer = new Socket("sunlab32.njit.edu",31414);
ObjectOutputStream myOutputStream = new ObjectOutputStream(socketToServer.getOutputStream());
ObjectInputStream myInputStream = new ObjectInputStream(socketToServer.getInputStream());
myOutputStream.writeObject(communicationObject);
communicationObject = (DataObject)myInputStream.readObject();
input = communicationObject.getMessage();
if (input != "stop") {
al.add(input);
data[count] = input;
count++; }
for (int i=0;i<data.length;i++) {
row = data[i];
temp = row.split(delimiter);
tbm.addRow(new String[] {temp[0],temp[1],temp[2],temp[3]}); }
tbm.fireTableDataChanged();
table.repaint();
now my problem is that the table does not get repainted after all the rows are loaded...any suggestions?
tbm.addModel should be firing table changed event, so tbm.fireTableDataChanged is not necessary.
You can try doing this though to force it to paint itself after you have added all the rows.
table.setModel(tbm);
Off topic:
Swing is a single threaded event model, which means the task that you are carrying out will block UI update.
I would suggest you move your data loading to SwingWorker and once you are done with your changes push the data on the UI. Take a look at this tutorial
There is no need to call tbm.fireTableDataChanged();. The model itself will notify the table in response to addRow(). And if the table and model are connected correctly the table will refresh itself.
You may find this example helpful, it demos use of DefaultTableModel.
As this code is not visible, make sure the table and scroll pane are setup correctly. Also, make sure your query actually returns data.

How to capture image from webcam WHILST already streaming from webcam too with Java Gstreamer?

I am using the gstreamer library for a Java project that needs to be able to capture an image from a webcam.
I already have the code that displays the webcam stream, I just can't figure out how to capture an image at the press of a button next to it.
I have searched the internet, but could only find pieces of code that show either the stream, or capture the image, but none illustrated both... I've tried to merge those pieces of code, but that didn't work for me either.
What do I have to do to get this to work?
public class WebcamPanel extends JPanel {
private static Pipeline pipe;
public WebcamPanel(){
String[] args = {};
args = Gst.init("Webcam", args);
pipe = new Pipeline("pipeline");
final Element videosrc = ElementFactory.make("dshowvideosrc", "source");
final Element videofilter = ElementFactory.make("capsfilter", "flt");
videofilter.setCaps(Caps.fromString("video/x-raw-yuv, width=320, height=240"));
setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
JButton takePic = new JButton();
takePic.setPreferredSize(new Dimension(50,50));
c.gridx = 0;
c.insets = new Insets(0,10,0,0);
add(takePic,c);
c.gridx = 2;
c.gridwidth = GridBagConstraints.REMAINDER;
c.insets = new Insets(0,40,0,0);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
VideoComponent videoComponent = new VideoComponent();
Element videosink = videoComponent.getElement();
// This gives 2nd window with stream from webcam
// Element videosink = ElementFactory.make("xvimagesink", "sink");
pipe.addMany(videosrc, videofilter, videosink);
Element.linkMany(videosrc, videofilter, videosink);
videoComponent.setPreferredSize(new Dimension(320, 240));
add(videoComponent,c);
videoComponent.setVisible(true);
// Start the pipeline processing
pipe.setState(State.PLAYING);
}
});
}
}
Have you take a look at camerabin2? This will implement the whole camera workflow for you (viewfinder, image capture, video captue, effects, ...).
The basic approach is to either tee off a 2nd stream and capture selected images from it (e.g. use a valve ! jpegenc ! multifilesink and open the valve for selected images) or to use a output-selector to the image-saving pipe or to use a buffer-probe (hacky).

Categories

Resources