I have looked over this code and i don't know what is wrong. I keep getting incorrect outputs when i enter a command (any input). Please look at the bottom part of my code.
public class gui {
private final static javax.swing.JFrame frame = new javax.swing.JFrame();
private final static javax.swing.JPanel panel = new javax.swing.JPanel();
public final static javax.swing.JTextArea outtextArea = new javax.swing.JTextArea("");
public final static javax.swing.JTextField intextArea = new javax.swing.JTextField();
public static void main(String[] args) {
java.awt.Font font = new java.awt.Font(java.awt.Font.SANS_SERIF, java.awt.Font.PLAIN, 15);
String command;
/* Optional */
frame.setTitle("Console");
frame.setUndecorated(true);
frame.getRootPane().setWindowDecorationStyle(javax.swing.JRootPane.FRAME); // COMMENT THIS OUT WHEN COMPLETE
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); //if exit command, dispose() first
frame.setBackground(java.awt.Color.BLACK);
/* size */
frame.setMinimumSize(new java.awt.Dimension(0b001011010100,0b000110000100));
frame.setLocation(0,0);
frame.setExtendedState(javax.swing.JFrame.MAXIMIZED_BOTH);
/* Sets panel */
panel.setBackground(java.awt.Color.PINK); // if sees pink, has error
panel.setLayout(new java.awt.BorderLayout());
panel.setSize(frame.getWidth(),frame.getHeight());
/* Sets text area */
//javax.swing.JScrollPane inscrollPane = new javax.swing.JScrollPane(intextArea);
intextArea.setHorizontalAlignment(javax.swing.JTextField.LEFT);
intextArea.setFont(font);
intextArea.setBackground(java.awt.Color.BLACK);
intextArea.setForeground(java.awt.Color.GREEN);
intextArea.setFocusable(true);
javax.swing.JScrollPane outscrollPane = new javax.swing.JScrollPane(outtextArea);
outtextArea.setRows(10);
outtextArea.setLineWrap(true);
outtextArea.setFont(font);
outtextArea.setBackground(java.awt.Color.BLUE);
outtextArea.setForeground(java.awt.Color.GREEN);
outtextArea.setEditable(false);
/* Sets all necessary components */
frame.add(panel);
panel.add(outscrollPane,java.awt.BorderLayout.CENTER);
// panel.add(inscrollPane,java.awt.BorderLayout.SOUTH);
panel.add(intextArea,java.awt.BorderLayout.SOUTH);
/* Adjusts components */
frame.pack();
frame.setVisible(true);
//every time a command is entered, it is sent to handler and
//textbox should be cleared
// THIS BELOW IS WHERE THE PROBLEM LIES/////////////////////////////
boolean keepGoing=true;
while(keepGoing){
command = intextArea.getText();
String refactored;
if(entering_a_command(command) && !command.equals("exit")){
refactored=command.substring(0,command.length()-1);
outtextArea.append(refactored+"\n");
intextArea.setText("");
}
else if(!command.equals("exit")){//no need to read before submission
outtextArea.append("");
command=intextArea.getText();
}
else{
outtextArea.append("EXITING\n");
keepGoing=false;
}
}
}
/*
Method is strictly for entering user input at appropriate time
*/
private static boolean entering_a_command(String temp){
//handler.print(temp);
return temp.contains("="); //key to submit user input
}
}
My input:
12345=
123456=
This is hell=
This is hello=
My EXPECTED output:
12345
123456
This is hell
This is hello
My ACTUAL output:
12345
12345
This is hell
This is hell
My problem:
When i enter an input the first time, it all checks out. When i enter an input the second time, an input that has greater length than the first, it is automatically submitted just as if i had pressed the trigger key (=).
The input box is the black box in the bottom. To submit an input, press '='
The problem is that you're abusing the threading model. You shouldn't be accessing UI components in a thread other than the UI thread - and having a tight loop like this is pretty much always a bad idea. You should read about the Swing threading model. From that tutorial:
Swing event handling code runs on a special thread known as the event dispatch thread. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not "thread safe": invoking them from multiple threads risks thread interference or memory consistency errors.
Instead, you should add an event listener to your text area. There are loads of options here, none of which is obviously ideal, unfortunately. Adding a key listener and handling keyTyped sounds good - but you get the event before the key ends up in the text area, which isn't ideal. Adding a document listener is a nice abstraction in that then it doesn't matter how the text is changed (e.g. programmatically) - but you can't mutate the document within a listener, so you can't clear it.
As a starting point, adding a key listener and handling keyReleased works well at least for the simple case. Get rid of your current loop (and the unconventionally named entering_a_command method) and replace them with:
intextArea.addKeyListener(new java.awt.event.KeyAdapter() {
#Override public void keyReleased(java.awt.event.KeyEvent e) {
String command = intextArea.getText();
if (!command.contains("=")) {
return;
}
command = command.substring(0, command.length() - 1);
if (command.equals("exit")) {
frame.setVisible(false);
frame.dispose();
return;
}
outtextArea.append(command + "\n");
intextArea.setText("");
}
});
Related
Here is my code:
while(monster.curHp > 0)
{
System.out.println("");
if(battle.pressedButton)
{
text = Player.name + ": " + Player.curHitPoints + " " + monster.name + ": " + monster.curHp;
battle = new GUIForBattle(text,Player,monster);
}
}
The weird thing is that if I have that println line in the while loop the code will work normally and when the button is pressed we will update text to have the current status and we will redraw the GUI using the GUIForBattle class, however if I don't have that println it wont redraw. Any advice? Thank you!
Here is the GUIForBattle for more context
public class GUIForBattle extends JFrame {
boolean pressedButton = false;
public GUIForBattle(String words, player PlayerOne, Monster monster)
{
JFrame frame = new JFrame(); //frame that holds everything
JPanel Panel = new JPanel(new GridLayout(5,5)); //panel where things get added
JLabel text = new JLabel(words); // text label
JButton attack = new JButton("Attack"); //makes a button used to attack
//adding what pressing the attack button would do
attack.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
int attackAmount = PlayerOne.weaponEquipped.att;
monster.curHp = monster.curHp - attackAmount;
pressedButton = true;
}
}
);
JButton Item = new JButton("Item"); // makes a button used to use items
Item.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//we need to make a item interface
}
});
Panel.add(text); //adds the text to the panel
Panel.add(attack);
Panel.add(Item);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 800); //setting size of frame
frame.add(Panel); //adding the panel to frame
frame.setVisible(true); //making the frame visible
}
}
Your code is inherently multi-threaded; one thread is running through that little while loop; the other is the swing application thread that will be handling your swing event handlers.
If you use shared variables like this (both threads access pressedButton) you need to make sure that variable is synchronized between threads. There are several ways of handling this, but an easy way for this particular problem would be to make the variable volatile.
If the variable is not synchronized in any way, there is no guarantee by the JVM as to when one thread will 'see' the changes made to it by the other. And typically, if you keep one thread occupied like you're doing here (this while loop is called a busy wait) it will never take the time to synchronize, and you'll never see the updates.
The println is an IO operation, meaning at some point your thread will be waiting for IO to complete. Most likely this causes the JVM to synchronize the variables, which is why you notice this difference.
In any case, relying on this without thinking about synchronization can be considered a bug.
Java threads and memory handling are a complex subject, and not something I would advise for beginners to jump in to; it could be overwhelming. Just try to avoid sharing memory between threads for now. For the moment, just run your logic in your swing application code (it's not ideal, but for some beginner code it's probably a good starting point).
When you feel ready for it, read up on the memory model and what it implies for multi-threading.
I got a mouse click event that call and display a new JFrame form when click. But when I click, the form show up with no element inside it. There are 2 events of that type in my project and I handle them both with the same mechanism. The first one works perfectly, but the second one got the problem. I also use pack() but the problem is still there. Could any one show me how to work this out? Thanks a lot! My project is in Vietnamese, so if any one wants to mention any element in the code or the UI, just writing it with no sign is good enough!
Here are the event handlers:
//The first event
private void tblClientResultMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
DefaultTableModel dm = (DefaultTableModel) tblClientResult.getModel();
int row = tblClientResult.getSelectedRow();
int col = tblClientResult.getSelectedColumn();
if (col == 7) {
SearchTruyenFrm searchTruyenFrm = new SearchTruyenFrm(listKH.get(row));
searchTruyenFrm.setVisible(true);
}
}
//The second one
private void tblTruyenResultMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
DefaultTableModel dm = (DefaultTableModel) tblTruyenResult.getModel();
int row = tblTruyenResult.getSelectedRow();
int col = tblTruyenResult.getSelectedColumn();
if (col == 6) {
MuonTruyen muonTruyen = new MuonTruyen();
muonTruyen.setTruyen(listTruyen.get(row));
muonTruyen.setPhieuMuon(phieuMuon);
//Trouble here (?)
ThueTruyenInfoFrm infoFrm = new ThueTruyenInfoFrm(listTruyen.get(row));
infoFrm.setVisible(true);
while (infoFrm.isVisible()) {
}
muonTruyen.setDieuKien(infoFrm.getTxtDieuKien().getText());
muonTruyen.setGiaMuon(Float.parseFloat(infoFrm.getTxtGiaThue().getText()));
muonTruyen.setTienPhat(0);
muonTruyen.setPaid(false);
}
}
Inside the constructor:
public ThueTruyenInfoFrm(Truyen selected) {
initComponents();
txtTenTr.setText(selected.getTen());
txtTacGia.setText(selected.getTacGia());
pack();
}
How it happens:
Desired outcome:
Welcome to the wonderful world of "Honey, I've blocked the Event Dispatching Thread (and now nothing works)"
Mouse events (like all GUI based events) are delivered within the context of the EDT, so doing something like...
private void tblTruyenResultMouseClicked(java.awt.event.MouseEvent evt) {
//....
while (infoFrm.isVisible()) {
}
}
will block the EDT and prevent any further processing of events, including paint events, basically hanging your program.
I suggest you start by having a read of The Event Dispatch Thread to get a nutter understand of the overall issue.
To solve your problem, you will want to make use of a modal dialog, which will wait at the point the dialog is made visible and continue executing after it's closed.
Have a look at How to make dialogs.
This is an important lesson, as you should never start with a top level container (like JFrame), but instead, base all you GUIs on something like a JPanel instead, this gives you greater freedom in deciding on when and how those components are displayed.
Form editors won't teach you techniques which produce re-usable or self contained code and I would highly recommend that you consider spending sometime coding them by hand.
Glad to be on this very helpful website. I have a problem with my Java program that will probably either be an easy fix, or impossible to fix.
You know how when you run a program that's open in NetBeans, it shows the output within the NetBeans application? I am trying to create a program that allows anybody who puts it on their computer to execute it, even if they have not installed an IDE like NetBeans or Eclipse. And when somebody executes my program, I want it to show the same thing as when I run it in NetBeans, with the same output and everything. The program doesn't use a GUI or anything like that. I managed to create an executable .jar file with the "Clean and build project" option, and I made a .bat file that successfully executes the program. This should achieve my goal of allowing anyone to run it. When I start up the .bat file, it works, and shows a white-text-black-background screen that runs the program exactly as it ran while in NetBeans.
The problem is that when I run the program (with the .bat file), the text is too small... I've tried looking everywhere for a solution to this, but I could only find discussion about how to make things work with GUIs, or other more complicated things than what my program needs. I am willing to work with GUI stuff if it is necessary, but I don't think it will help, due to what a GUI is. From my understanding, a GUI is not one big thing, but is a user interface composed of smaller parts (such as pop-up input prompts and scroll bars) that are each made by the programmer. I don't need any fancy scroll bars etc., I just need my program to execute like it does when ran in NetBeans (pretty sure this is called the console), and I need to change the text size of the program text when it executes.
I greatly appreciate any help, even if you aren't sure if it will work or not. If the answer requires a lengthy explanation and you don't feel like explaining, that's okay; just tell me what I'd have to learn to figure this out and I can research it if necessary.
I just created one. Try using this one and tell us if it helped or not.
EDIT Added a JTextField to read data. It is more advanced code than the previous one, since it uses concurrency. I tried to make it simple, these are the functions you can use:
MyConsole (): Constructor. Create and show the console
print (String s): Print the s String
println (String s) Print the s String and add a new line
read (): Makes you wait untill the user types and presses Enter
closeConsole (): Closes the console
Here is the code:
public class MyConsole implements ActionListener {
private JFrame frame;
private JTextArea myText;
private JTextField userText;
private String readText;
private Object sync;
/*
* Main and only constructor
*/
public MyConsole() {
// Synchronization object
sync = new Object();
// Create a window to display the console
frame = new JFrame("My Console");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setContentPane(createUI());
frame.setVisible(true);
}
/*
* Creates user interface
*/
private Container createUI() {
// Create a Panel to add all objects
JPanel panel = new JPanel (new BorderLayout());
// Create and set the console
myText = new JTextArea();
myText.setEditable(false);
myText.setAutoscrolls(true);
myText.setBackground(Color.LIGHT_GRAY);
// This will auto scroll the right bar when text is added
DefaultCaret caret = (DefaultCaret) myText.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
// Create the input for the user
userText = new JTextField();
userText.addActionListener(this);
panel.add(new JScrollPane(myText), BorderLayout.CENTER);
panel.add(userText, BorderLayout.SOUTH);
return panel;
}
/*
* Waits until a value is typed in the console and returns it
*/
public String read(){
print("==>");
synchronized (sync) {
try {
sync.wait();
} catch (InterruptedException e) {
return readText = "";
}
}
return readText;
}
/*
* Prints s
*/
public synchronized void print(String s){
// Add the "s" string to the console and
myText.append(s);
}
/*
* Prints s and a new line
*/
public synchronized void println(String s){
this.print(s + "\r\n");
}
/*
* Close the console
*/
public void closeConsole(){
frame.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
// Check if the input is empty
if ( !userText.getText().equals("") ){
readText = userText.getText();
println(" " + readText);
userText.setText("");
synchronized (sync) {
sync.notify();
}
}
}
}
Here is how to use it (an example). It just asks your age and writes something depending on your input:
public static void main(String[] args) {
MyConsole console = new MyConsole();
console.println("Hello! (Type \"0\" to exit)");
int age = 1;
do{
console.println("How old are you ?");
String read = console.read();
try {
age = Integer.valueOf(read);
if ( age >= 18){
console.println("Wow! " + age + " ? You are an adult already!");
}else if ( age > 0 ){
console.println("Oh! " + age + " ? You are such a young boy!");
}else if (age == 0){
console.println("Bye bye!");
}else{
console.println("You can't be " + age + " years old!");
}
}catch (Exception e) {
console.println("Did you write any number there ?");
}
} while ( age != 0 );
console.closeConsole();
}
And here is a image:
I am trying to create a while loop with this condition. (a > 1) So basically. every time a is set to greater than 1, it will close the JFrame I created and then start the program over. My problem is that, when I try edit the integer "a" from within an action listener, it doesn't recognize that it has already been declared. This is somewhat difficult to actually describe, so here is my code.
public class TestBox {
public static void main(String[] args) {
int a = 2;
while(a > 1){
a = 0;
JFrame frame = new JFrame("Test Box");
frame.setSize(1200, 800);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setLayout(new GridLayout(6, 6, 1, 1));
JPanel panelAOne = new JPanel();
JPanel panelATwo = new JPanel();
JPanel emptySpace = new JPanel();
JLabel labelAOne = new JLabel();
labelAOne.setFont(new Font("Aerial", Font.ITALIC, 21));
labelAOne.setText("Welcome to the Test Box!");
JLabel labelATwo = new JLabel();
labelATwo.setFont(new Font("Aerial", Font.ITALIC, 21));
labelATwo.setText("Where would you like to go?");
JLabel emptyLabel = new JLabel("stuff goes here");
JButton buttonAOne = new JButton("Colors");
panelAOne.add(labelAOne);
panelAOne.add(labelATwo);
panelATwo.add(buttonAOne);
emptySpace.add(emptyLabel);
frame.add(panelAOne);
frame.add(buttonAOne);
frame.add(emptySpace);
frame.setVisible(true);
buttonAOne.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
a = 2;
//If this code is left as is, a GUI will open endlessly until it crashes the computer
}
}
});
}
}
You look to be trying to shoe-horn a linear console program into a Swing event-driven GUI program or visa versa, and you really don't want to do that, and I would recommend that you re-structure your program. Instead, show your GUI, get the input, and re-request the input in the GUI if it's wrong. Don't use a console-type program while loop for this.
So, for instance if the ActionListener finds that the input is not valid, clear the text in the JTextField by calling setText("") on the JTextField, show the user a JOptionPane informing them of the error in input and await another press of the button. But leave the JFrame displayed.
Edit: I don't even see a JTextField in your code, so I'm not sure where the user is supposed to enter input.
Your scheme cannot work, at least not reliably. At the end of the first iteration of your loop, local variable a still has the value set at the top of the loop (0), so the loop exits and the application's main thread dies. The GUI will continue to run, as it does so in a separate thread (the AWT's event-dispatch thread (EDT)), but even if you re-wrote your code so that an analog of variable a could be modified by your ActionListener, nobody who cares would still be paying attention by that point. (Probably. You have multiple threads sharing data without any synchronization, so really the behavior of your program is not well defined.)
GUI programming is fundamentally different from console programming, as Hovercraft Full Of Eels pointed out. It requires a significant mental adjustment to move from one to the other, but the basic paradigm of GUI programming is that everything your program does is a response to an event. Thus, if you want some sort of re-spawning behavior then you should obtain it by registering a listener for the appropriate event, and having it perform the work you want.
I call a class that creates a jframe and waits from user to input some values.
The problem that I experience is that I need to wait these values before to continue.
So the code is something simple like this
Jframe frame= new jframe(); //here I want the program to show the frame and then wait till it will be disposed
// I want a pause here
System.out.println(frame.getvalue);
Till now the only I could do is to froze the frame before can even appear totally.
Any help?
Please keep it simple since I am new to Java.
THANK YOU!
I think you should use JDialog instead of JFrame. Please follow this example
What you're probably looking for is JOptionPane. This is a blocking routine that returns only after the user has entered some value, like so:
public class test
{
public static void main ( String args[] )
{
String input = JOptionPane.showInputDialog(null, "Thing: ",
"Enter Stuff", JOptionPane.OK_CANCEL_OPTION);
System.out.println ( "won't reach until got input");
System.out.println ( "My value: " + input );
}
}
The great thing about it is you can add Components to it, so you aren't limited to a single input field, but it is still blocking. The following would add two JTextField's to the frame:
public class test
{
public static void main ( String args[] )
{
JTextField input_box = new JTextField(7);
JTextField input_box2 = new JTextField(7);
JComponent[] inputs = new JComponent[] {
new JLabel("Thing 1:"),
input_box,
new JLabel("Thing 2:"),
input_box2 };
int rval = JOptionPane.showConfirmDialog(null, inputs,
"Enter Stuff", JOptionPane.OK_CANCEL_OPTION);
if ( rval == 0)
{
System.out.printf ("%s and %s!", input_box.getText(),
input_box2.getText());
}
}
}
Instead of using a JFrame, consider using a JDialog with modality set to true.
When it comes time to add an 'OK' button or something like that, check out JRootPane.setDefaultButton()
well as you know swing components are not thread safe though you can use SwingWorker to make the waiting in background,
It uses the thread way but it creates a new thread for the waiting ,long term operations in general,
instead of pausing the event dispatch thread so the user can interact with the rest of the application or the rest of the application can continue to work while the waiting goes on.
ofcourse you have to define a way for it to stop the waiting.
check out its documentation here http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
This will cause the current thread to wait 5 seconds:
try {
Thread.currentThread().wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}