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() {...});
Related
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().
I'm trying to create a simple UI for a program that can read a file, write to a file and search for text within a file. I have most of my Components created, the problem is that they're all being "drawn" in the same (center) cell. I've tried applying weights, widths, etc. all to no avail.
Here's my base code for the UI:
public void GUI(){
//Create main window for Program
JFrame mainWindow = new JFrame("Simple Data Base"); //Init frame
mainWindow.setSize(500, 400); //Set frame size
mainWindow.setVisible(true); //Make frame visible
//Create panel for the main window of the GUI
JPanel simpleGUI = new JPanel( new GridBagLayout());
GridBagConstraints gbCons = new GridBagConstraints();
simpleGUI.setBackground(Color.cyan);
//Create button linking to read function
JButton readButton = new JButton("Read"); //Init button, and give text
gbCons.fill = GridBagConstraints.BOTH;
gbCons.gridx = 0;
gbCons.gridy = 1;
//Create button linking to the search function
JButton searchButton = new JButton("Search");
gbCons.fill = GridBagConstraints.BOTH;
gbCons.gridx = 1;
gbCons.gridy = 1;
//Create label prompting user to specify desired function
JLabel promptText = new JLabel("Click 'Read' to read a file, 'Search' to search within a file, 'Write' to write to a file:");
gbCons.fill = GridBagConstraints.BOTH;
gbCons.gridx = 0;
gbCons.gridy = 0;
//Add components to Main window
mainWindow.getContentPane().add(simpleGUI);
simpleGUI.add(promptText, gbCons);
simpleGUI.add(readButton, gbCons);
simpleGUI.add(searchButton, gbCons);
}
the problem is that they're all being "drawn" in the same (center) cell.
simpleGUI.add(promptText, gbCons);
simpleGUI.add(readButton, gbCons);
simpleGUI.add(searchButton, gbCons);
You are using the same GridBagConstraints for each component so the contraints are identical for each component.
You neeed to:
set the constraints
add the component to the panel using the constraints
repeat steps 1 and 2.
For example:
JButton readButton = new JButton("Read");
gbCons.fill = GridBagConstraints.BOTH;
gbCons.gridx = 0;
gbCons.gridy = 1;
simpleGUI.add(readButton, gbCons);
JButton searchButton = new JButton("Search");
gbCons.fill = GridBagConstraints.BOTH;
gbCons.gridx = 1;
gbCons.gridy = 1;
simpleGUI.add(searchButton, gbCons);
I suggest you read the section from the Swing tutorial on How to Use GridBagLayout for more information and examples.
Download the demo code and use that example as your starting code. The demo code will show you how to better structure your class by:
NOT extending JFrame
Creating the GUI on the Event Dispatch Thread
Use the pack() method, NOT the setSize(...) method
Make the frame visible AFTER all components have been added to the frame
I'm trying to build simple calculator gui with display and 9 buttons
public void init()
{
setSize(60,80);
inf = new InfoButton(this);
zero = new CalcButton(this,"0");
one = new CalcButton(this,"1");
add = new CalcButton(this,"+");
sub = new CalcButton(this,"-");
div = new CalcButton(this,"/");
mlt = new CalcButton(this,"*");
modu = new CalcButton(this,"%");
blank = new JButton("");
wys = new Wyswietlacz(); // its JTextPane
wys.setSize(60,20);
przyciski = new JPanel();
przyciski.setSize(60,60);
przyciski.setLayout(new GridLayout(3,3));
przyciski.add(zero);
przyciski.add(one);
przyciski.add(add);
przyciski.add(sub);
przyciski.add(mlt);
przyciski.add(div);
przyciski.add(modu);
przyciski.add(inf);
przyciski.add(blank);
calosc = new JPanel();
calosc.setLayout(new BoxLayout(calosc,BoxLayout.Y_AXIS));
calosc.add(wys);
calosc.add(przyciski);
calosc.setSize(60,80);
add(calosc);
}
and in main i make frame with size (60,80) but when i make it visible all i can see is display and one row of buttons. What am i doing wrong?
Call setPreferredSize(..) instead of setSize() on wys and przyciski. Then use JFrame's pack() instead of specifying a size for it.
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.
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).