I'm working on a program that serves as a hypothetical email system in which users can be created and can send messages to other users that have been created.
The message will be stored in a "Message" class, and the text is typed in a JTextArea in a GUI. What I want to know is how I would go about storing the text typed into the JTextArea, in the exact same layout (indentations and all), within the Message class. I thought about text files but then there would have to be one for each message, potentially creating an infinite number of them, and I don't like the concept of having to make a system for coming up with unique names for each text file.
Can you please give me some advice?
Simply implement the DocumentListener interface, then do the following:
JTextArea someMessage = new JTextArea();
someMessage.getDocument().addDocumentListener(new MyDocumentListener());
someMessage.getDocument().putProperty("name", "Text Area");
Here, we assume the name of the listener you implement is called MyDocumentListener, and the implementation could be as simple as:
class MyDocumentListener implements DocumentListener {
String newline = "\n";
#Override
public void insertUpdate(DocumentEvent e) {
updateLog(e, "inserted into");
}
#Override
public void removeUpdate(DocumentEvent e) {
updateLog(e, "removed from");
}
#Override
public void changedUpdate(DocumentEvent e) {
//Plain text components do not fire these events
}
public void updateLog(DocumentEvent e, String action) {
Document doc = (Document)e.getDocument();
int changeLength = e.getLength();
displayArea.append(
changeLength + " character" +
((changeLength == 1) ? " " : "s ") +
action + doc.getProperty("name") + "." + newline +
" Text length = " + doc.getLength() + newline);
}
}
Examples taken from Oracle website. I recommend reading the rest of that article as it goes into much depth of how to effectively listen for updates to the internal document model.
How to get text that was inserted
insertUpdate is what notifies you when new text has been typed into the textarea. You can get the freshly inserted text by calling off to the DocumentEvent#getOffset and DocumentEvent#getLength. Using both methods, you can get the offset (index) within document where the insertion happened, as well as the length of the change.
Then to get the actual text that was inserted, you call DocumentEvent#getDocument#getText and supplying the offset and length you got from the event.
How to get all the text in the textarea
You can use this similar method to get the entire text in the document by making use of Document#getStartPosition and Document#getEndPosition, then calling Document#getText.
Or even easier, JTextArea#getText
Related
I have written a code to connect to this webpage: compilerjava.net
1) I found the text-area field within that page which accepts the code to compile.
2) I have found the button that compiles the code.
3) I have found the text-area which returns the result of the code.
The issue is, when I call textarea.setText( "something"), it (I think) doesn't actually change the code in the webpage. So when I click on the compile button, it compiles the default code within that page and returns the output of that default code.
I have tried to set focus to textarea, you can see all of those down below.
I called;
1) textArea.focus();
2) textArea.click();
3) I tried using textArea.setAttribute( "name", "code");
I have searched the internet and found various stackoverflow questions close to this problem, neither of them solved my issue and it just seems to work for everyone when they say textArea.setText().
Another interesting fact I should share with you is,
If I call textArea.setText( "...") and then I say;
HtmlTextArea textArea1 = form.getTextAreaByName( "code");
If I call textArea1.getText(), the value of this text will be "...". This should imply that I have actually managed to change the value of the text-area, but when I compile, it compiles the default text in the text-area and not the text that I have set it to.
Any help with this?
P.S: The reason why I put the result of the compilation on a while loop is related to network connection issues. If you try to run this code it might not work on your first try. Also note that the run-time is around 15 seconds, because it gives thousands of warnings which I blocked to print to console.
P.S2: I also looked at this page and none of these worked;
http://www.programcreek.com/java-api-examples/index.php?api=com.gargoylesoftware.htmlunit.html.HtmlTextArea
public class Test {
public static void main(String[] args) {
try {
// Prevents the program to print thousands of warning codes.
java.util.logging.Logger.getLogger("com.gargoylesoftware").setLevel(java.util.logging.Level.OFF);
java.util.logging.Logger.getLogger("org.apache.http").setLevel(java.util.logging.Level.OFF);
// Initializes the web client and yet again stops some warning codes.
WebClient webClient = new WebClient( BrowserVersion.CHROME);
webClient.getOptions().setThrowExceptionOnFailingStatusCode( false);
webClient.getOptions().setThrowExceptionOnScriptError( false);
webClient.getOptions().setJavaScriptEnabled( true);
webClient.getOptions().setCssEnabled( true);
// Gets the html page, which is the online compiler I'm using.
HtmlPage page = webClient.getPage("https://www.compilejava.net/");
// Succesfully finds the form which has the required buttons etc.
List<HtmlForm> forms = page.getForms();
HtmlForm form = forms.get( 0);
// Finds the textarea which will hold the code.
HtmlTextArea textArea = form.getTextAreaByName( "code");
// Finds the textarea which will hold the result of the compilation.
HtmlTextArea resultArea = page.getHtmlElementById( "execsout");
// Finds the compile button.
HtmlButtonInput button = form.getInputByName( "compile");
textArea.click();
textArea.focus();
// Simple code to run.
textArea.setDefaultValue( "public class HelloWorld\n" +
"{\n" +
" // arguments are passed using the text field below this editor\n" +
" public static void main(String[] args)\n" +
" {\n" +
" System.out.print( \"Hello\");\n" +
" }\n" +
"}");
System.out.println( textArea.getText());
// Compiles.
button.click();
// Result of the compilation.
String str = resultArea.getText();
while ( resultArea.getText() == null || resultArea.getText().substring(0, 3).equals( "exe")) {
System.out.print( resultArea.getText());
}
System.out.println();
System.out.println( resultArea.getText());
} catch ( Exception e) {
e.printStackTrace();
}
}
}
a little patience helps here
// Result of the compilation.
while (resultArea.getText() == null || resultArea.getText().startsWith("exe")) {
System.out.println(resultArea.getText());
Thread.sleep(500);
}
System.out.println();
System.out.println(resultArea.getText());
I posted this code yesterday for another issue but now I once again must call on you all for help.. I appreciate all the assistance so far I have had without this community I wouldn't have made it so far.
Now, my problem is quite simple. I have a GUI with an input box for the user and three buttons. The buttons are not JButtons, they are the standard JOptionsPane yes, no, and cancel buttons. I did change the text to "next entry", "next batch", and "finished".
Before I made changes to my GUI I had standard buttons. The button that will most often be used is the "yes" button (now "next entry").. This button will be clicked a LOT in my program. Before the default button setting worked.. A user could simply type a number and press enter quickly. Now the enter key will not activate the default button instead the user must physically click on it.. This is what I want to change.
Is there any way I can set the below code so when the user clicks enter, regardless of what text they have typed, the "yes" (now "next batch" is clicked on default)? For what it's worth I did do research on this but could not find a solution that suited my specific circumstances.
package nacha;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Testing4
{
public static void main(String args[]){
String css = "<span style='font-size:10; color: white; background-color:black'>";
String batchCss = "<span style='font-size: 20'>";
String endSpanCss = "</span>";
String table = "<table border=4>";
String endTable = "</table>";
String mainCss = "<span style='font-size:12; color: red'>";
String header1Css = "<span style = 'font-size:15; font-weight:bold;text-decoration:underline;border:1px dotted red'>";
String text1Css = "<span style = 'font-size:12; font-style:italic'>";
String text = "<html>" +
css + batchCss + "1 of 2"+endSpanCss+endSpanCss+ endSpanCss +
"<br><br><br>"+header1Css+"Entry Detail:"+endSpanCss +
"<br>"+mainCss+"111111111111111111111"+endSpanCss+
"<br><br><br>"+text1Css+"Please type 1-21 to apply a reason code and addenda record to the entry detail." +
"<br>Please type 'h' and press the next entry button to open the help screen."+endSpanCss +
"<br><br><br>"+header1Css+"Reason Codes"+ endSpanCss +
"<br>"+table+"R01 - Insufficient Funds" +
"<br>R02 - Account Closed" +
"<br>R03 - No Account" +
"<br>R04 - Invalid Account Number" +
"<br>R05 - Unauthorized Debit to Consumer Account" +
"<br>R06 - Returned per ODFI Request" +
"<br>R07 - Auth Revoked by Customer" +
"<br>R08 - Payment Stopped" +
"<br>R09 - Uncollected Funds" +
"<br>R10 - Customer Advises Not Authorized" +
"<br>R11 - Check Truncation Entry Return" +
"<br>R12 - Branch Sold to Another DFI" +
"<br>R13 - Invalid ACH Routing Number" +
"<br>R14 - Represenative Payee Deceased or Unable to Continue" +
"<br>R15 - Beneficiary or Account Holder Deceased" +
"<br>R16 - Account Frozen" +
"<br>R17 - File Record Edit Criteria" +
"<br>R18 - Improper Effective Entry Date" +
"<br>R19 - Account Field Error" +
"<br>R20 - Non-Transaction Amount" +
"<br>R21 - Invalid Company Information" +
"<br>R22 - Invalid Individual ID Number"+endTable;
//Below code creates the GUI for the return builder portion of the program.
Object[] options1 = {"Next Entry","Next Batch","Finished"};//Changes the default buttons.
BorderLayout border = new BorderLayout();
JPanel panel = new JPanel();
panel.setLayout(border);
panel.add(new JLabel(text),BorderLayout.NORTH);//Adds the label to the top of the panel.
JTextField textField = new JTextField(10);
panel.add(textField,BorderLayout.SOUTH);//Adds a user-input text area to the bottom of the panel.
int result = JOptionPane.showOptionDialog(null, panel, "Return Builder", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options1, JOptionPane.YES_OPTION);
}
}
You need to pass the default option as the final argument to JOptionPane.showOptionDialog:
int result = JOptionPane.showOptionDialog(null, panel, "Return Builder",
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null,
options1, options1[0]);
This will have the side effect of making that button have the initial keyboard focus whenever the dialog is displayed. If you don't want that, you can force the JTextField to receive the focus whenever it is displayed in a window:
textField.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
final Component c = e.getComponent();
long flags = e.getChangeFlags();
if ((flags & HierarchyEvent.SHOWING_CHANGED) != 0 &&
c.isShowing()) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
c.requestFocusInWindow();
}
});
}
}
});
A side note: For asking the user to select from a list of known options, a JComboBox is a better choice than a JTextField. Your Help option can simply be a different JButton, present in the message body of the JOptionPane.
I'm trying to call a method from a class called Circle in my project which displays some basic information about the object in a JLabel. For some reason the text won't go to a new line even when I use HTML to try and format it:
#Override
public String toString(){
return "<html>Type: " + this.getClass().getSimpleName() + "<br>Radius: " + getRadius() + "<br>Area: " + df.format(getArea()) + "<br>Perimeter: </html>" + df.format(getPerimeter());
}
I'm trying to display the info with this code:
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource()==btnCalc && x==1){
//create object
double R = Double.parseDouble(Txt1.getText());
Circle circ = new Circle(R);
lblResult.setText(circ.toString());
}
When I run the program it just returns this:<html>Type: Circle<br>Radius: 4.0<br>Area: 50.27<br>Perimeter:</html> 25.13
edit: I tried just setting the text as an exception message instead of calling the method and it didn't work this way either
edit: Now this happens when I try to run the cylinder-sphere classes, but it doesn't do that when I don't have any html in the toString() method.
Turns out I was using a DecimalFormat in the last four classes which was what was giving me the exception. Once I got rid of that, the strings formatted nicely using a JTextPane instead of a JtextField.
From the image you pasted, it looks like it is a text INPUT control (under Show Info button), like JTextField and not a JLabel.
You can use HTML content with JLabel constructor as well as with its setText method too. It works fine.
JLabel lbl = new JLabel("<html>Type: Circle<br>Some info<br>More info</html>")
JLabel lbl2 = new JLabel();
lbl2.setText("<html>Type: Circle<br>Some info<br>More info</html>")
But if you want to have an INPUT control (as in your image), you can not use HTML with JTextField. You have to use JTextPane for this.
JTextPane txt = new JTextPane();
txt.setContentType("text/html");
txt.setText("<html>Type: Circle<br>Some info<br>More info</html>");
I am having some trouble with a couple of methods in my program: I have a method that is called when the user clicks a start button on the GUI. This method will receive all of the network traffic currently being sent/ received over the network, and display information about it to the user. The user can stop this method being called by clicking the stop button.
This method currently looks like this:
public static void retrieveFilteredPdu(){
/*Try/Catch block copied from 'receivePdu()' method in EspduReceiver.java on 07/05/2014
* Now edit it so that it will receive all PDUs, but only display the ones matching the filter values in the top JTextArea */
try{
/*Specify the socket to receive the data */
EspduReceiver.socket = new MulticastSocket(EspduSender.PORT);
EspduReceiver.address = InetAddress.getByName(EspduSender.DEFAULT_MULTICAST_GROUP);
EspduReceiver.socket.joinGroup(EspduReceiver.address);
//stopCapture = false;
/*Loop infinitely, receiving datagrams */
while(true){
/*First, set the value of the 'stopCapture' boolean to 'false', in case it has previously been set to true during the life of
* the program */
/*stopCapture = false; /*For some reason, if I do this here, clicking the 'Get site' button causes the program to start receiving
PDUs again, and you are not able to stop it without manually shutting down the program. Possibly because I am infinitely
setting the value of 'stopCapture' to false?*/
byte buffer[] = new byte[EspduReceiver.MAX_PDU_SIZE];
EspduReceiver.packet = new DatagramPacket(buffer, buffer.length);
EspduReceiver.socket.receive(EspduReceiver.packet);
Pdu pdu = EspduReceiver.pduFactory.createPdu(EspduReceiver.packet.getData()); /*Moved this line to the top of the class to declare as global variable (29/04/2014) */
if(pdu != null){
System.out.print("Got PDU of type: " + pdu.getClass().getName());
if(pdu instanceof EntityStatePdu){
EntityID eid = ((EntityStatePdu)pdu).getEntityID();
Vector3Double position = ((EntityStatePdu)pdu).getEntityLocation();
System.out.println(" EID:[" + eid.getSite() + ", " + eid.getApplication() + ", " + eid.getEntity() + "] ");
System.out.println("Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "] ");
/*Add PDU to ArrayList of PDUs */
EspduReceiver.espdu.add(pdu);
/* System.out.println(" PDU added to arrayList. ");
System.out.println(espdu); /*This is printing out the actual DIS messages (i.e. edu.nps.moves.dis.EntityState...),
maybe try adding the 'eid.getSite()', etc to an ArrayList instead. Use Associative arrays/ map/ hashmap */
EspduReceiver.entitySite.add(eid.getSite());
System.out.println("Entity Site added to ArrayList from Filter.retrieveFilteredPdu() ");
EspduReceiver.entityApplication.add(eid.getApplication());
System.out.println("Entity Application added to ArrayLIst. ");
EspduReceiver.entity.add(eid.getEntity());
System.out.println("Entity ID added to ArrayList");
/*Check that everything is actually in the ArrayLists
for(int i : entity){ /*Substituted 'entity' with 'entitySite' and 'entityApplication'- values are all printed correctly.
System.out.println(i);
} */
/*07/05/2014
* Write a method that will only append the PDUs that match the filter values to the text area,
* call that method here. */
/*Now append each PDU to the text area */
Gui.displayFilteredOutput.append("\n");
Gui.displayFilteredOutput.append("EID: [" + eid.getSite() + ", " + eid.getApplication() + ", " + eid.getEntity() + "]. ");
Gui.displayFilteredOutput.append("Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "] ");
/*Append every PDU that matches the filter criteria to the displayFilteredOutput JTextArea
Gui.displayFilteredOutput.append("\n");
Gui.displayFilteredOutput.append("EID: [" + eid.getSite() + ", " + eid.getApplication() + ", " + eid.getEntity() + "]. ");
Gui.displayFilteredOutput.append("Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "] "); */
} else if(!(pdu instanceof EntityStatePdu)){
System.out.println("There are no PDUs currently being received.");
}
System.out.println();
}
Thread.sleep(1000);
/*Try adding a boolean to allow me to stop the capture by clicking 'stop' button- Look on stackoverflow */
boolean queryStopCapture = EspduReceiver.stopCapture;
if(queryStopCapture == true){
System.out.println("Break clause in 'queryStopCapture' if statement in EspduReceiver.java has been called. ");
break; /*Use a call to receivePdu() to populate the second JTextArea, but don't let it call a 'break' clause at all.
* Find some other way of adding a 'break' to the output displayed in the first JTextArea (01/05/2014)
* Maybe add this code to receivePdu() call in ActionListener instead of here.
*/
}
} /*end while */
} /*end try */
catch(Exception e){
System.out.println(e);
e.printStackTrace();
System.out.println("Error in retrieveFilteredPdu() method. ");
/*09/04/2014 # 17:100
* If this exception gets called, presumably it either means that pdu is not an instance of EntityStatePdu, or
* that pdu does not actually hold a packet. */
}
}
I have another method, which, in theory, should display information about only the network traffic which has attributes matching some values set by the user. This method is called when the user clicks the 'Filter' button on the GUI. The method currently looks like this:
public static void filterPDUs(){
// if(EspduReceiver.startCapture == true){
/*If EspduReceiver.startCapture is true, then the program is already receiving PDUs, so now I need to set it to only display the ones that
* match the filter criteria. Do this by checking the PDU attributes against the filter values before printing- if they match, then print,
* if not, don't. */
if((EspduReceiver.startCapture == true) && (EspduReceiver.stopCapture == false)){
/*Get the size of the sitesToBeFiltered ArrayList, and store in a variable. Will need to update the variable with every iteration
* of the loop, because the ArrayList will keep growing as long as the capture is running. */
int sitesToBeFilteredSize = sitesToBeFiltered.size();
int matchingSitesIterator = 0;
/*First, check if site filter value matches the PDU's site, if it does, then check Application, if it matches again, then check ID.
* If at any point it doesn't match, exit the while loop. */
while(matchingSitesIterator < sitesToBeFilteredSize){
System.out.println("SitesToBeFiltered.size() = " + sitesToBeFilteredSize);
if(sitesToBeFiltered.get(matchingSitesIterator) == Filter.filter1Value){
if(applicationsToBeFiltered.get(matchingSitesIterator) == Filter.filter2Value){
if(IDsToBeFiltered.get(matchingSitesIterator) == Filter.filter3Value){
Gui.displayFilteredOutput.append("Matching PDU found: [" + sitesToBeFiltered.get(matchingSitesIterator) + ", " + applicationsToBeFiltered.get(matchingSitesIterator) + ", " + IDsToBeFiltered.get(matchingSitesIterator) + "] ");
} else {Gui.displayFilteredOutput.append("Sorry, there were no PDUs found with the specified ID value.");}
Gui.displayFilteredOutput.append("Need to display every PDU that had a matching Site & Application here. ");
}else {Gui.displayFilteredOutput.append("Sorry, there were no PDUs found with the specified Application value.");}
Gui.displayFilteredOutput.append("need to display every PDU that had a matching Site here. ");
}else {Gui.displayOutput.append("Sorry, there were no PDUs found with the specified Site value.");}
}
} else {
Gui.displayFilteredOutput.append("Do something if EspduReceiver.startCapture is not true, and EspduReceiver.stopCapture is not false");
}
// }else if(EspduReceiver.startCapture == false){
/*If EspduReceiver.startCapture is false, then the program is not receiving PDUs, so I now need to call the method that will receive PDUs,
* and display only the ones that match the filter criteria. */
// }
}
The problem I'm having is that for some reason, if the user clicks the 'Filter' button to display only the PDUs with matching filter criteria, after clicking 'Start' (to call the first method), then the program crashes completely... (i.e. it appears to stop performing the function that it was carrying out, and will not respond to clicks on any buttons or even the 'Close window' button)
If they click 'Filter' after having clicked 'Start' & 'Stop' (i.e. when the first method is not running, then the second method performs its tasks as expected.
It seems that for some reason, calling the second method while the first method is still running causes the program to crash- and I can't work out why this is... can anyone point out what's going wrong here?
Edit
I have the following code in my main method:
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
Gui gui = new Gui();
gui.setVisible(true);
}
});
}
You need to show more of the code, as others have said, but if you're using Swingworkers or other threads to run these methods, then either the methods have to be thread-safe or they need to be synchronized to prevent their execution from being interleaved. If you're directly accessing Swing components outside the event-dispatching thread, then Swing will make demons come out of your nose, so don't do that (there are some special exceptions for some text components, but generally it's prohibited). If you're not sure, stick assert java.awt.EventQueue.isDispatchThread() before every statement that constructs or uses a Swing object, and enable assertions in the runtime system.
I assume Gui is built on Swing. Read the Swing tutorial, and pay attention to the Event Dispatch Thread. I can't see how the Swing portion of you code works, but I'm guessing you are locking up the EDT somehow. A long-running process needs to run in its own thread and use SwingUtilities.invokeLater() to update Swing components, like your text area.
I have a form for the user to fill out in a JFrame which then writes the collected data to a JTable in a different class.
I'm trying to configure it that when the user selects "Submit" that the JFrame will close, but not close down the program. What would be the command I need to achieve this?
The code for the submit button is as follows is as follows:
JButton bMark = new JButton("Submit");
bMark.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String start = tbStart.getText();
String end = tbEnd.getText();
String[] marking = {start, end, active, body, dysk, trem, brady};
//This is just for me to ensure the collected data is correct
System.out.println(marking[0] + " " +marking[1] + " " +marking[2] + " " +
marking[3] + " " + marking[4] + " " + marking[5] + " " + marking[6]);
//This is is the class the form data is being sent to
markTable.main(marking);
//This is where I would like the close the current window
}
});
bMark.setBounds(308, 191, 86, 23);
The class name is createMark and the method is public createMark
Thanks to anyone who replies,
Jared.
//This is where I would like the close the current window
there are these ways
JFrame#setVisible(false), but not terminating current JVM, this session exist until PC restarted,
JFrame#dispose() terminating current JVM,
System#exit(int); terminating current JVM,
better would be to JFrame#setDefaultCloseOperation
don't suplly JOptionPane, maybe will be better use that directly
You need to set the default close operation on the JFrame as such:
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
This will take care of the case where the user closes the window using the title bar or hits something like Alt+F4.
Next, simply call setVisible(false) when the submit button is pressed.