Almost done...one problem with an error JPaneOption box - java

I've almost got my asignment done. Yayy! But.... I have two problems in my handler. For one, I have a public void itemStateChanged(ItemEvent e) method that is supposed to print a registrants name to a text field, plus the type of registration he is (student, business, complimentary). I have this working, only it prints twice to the text area. I don't get that. Also, there is a 'calculate charges' button which is used to...well, calculate the charges. When the button is clicked, the action event is supposed to check to make sure that a combo box (in a class called regPanel) does not have "Please select a registration type" which is element 0 in an object array. The way I have it now, if I don't pick something from the combobox (leaving it on element 0), I get the error message, but then the program prints to the textfield anyways. It is not supposed to. It is only supposed to print the error box, then allow the user to make the proper selections. Any advice would be appreciated. Here is the class:
public class ConferenceHandler implements ActionListener, FocusListener, ItemListener
{
protected final static String ERROR_TEXT = "Please enter a name";
protected ConferenceGUI gui; //reference the ConferenceGUI panel
/**Constructor*/
public ConferenceHandler(ConferenceGUI gui) {this.gui = gui;}
if (gui.regPanel.getRegType() == "Please select a type")
JOptionPane.showMessageDialog(null, "Please select a registration type",
"Type Error",JOptionPane.ERROR_MESSAGE);
//prints to textarea if registrant will be attending keynote or not
else if (gui.regPanel.regCheckBox.isSelected())
gui.textArea.append("\nKeynote address will be attended");
else
Did a little more googling, and figured out the problem with the double firing of the itemStateChanged affair. Trimmed all of the extra code out, because I'm pretty sure that all I need is a loop of some sort around here. When I put a while or do-while loop, all that happens is the JOptionPane comes up and won't go away. I need to validate that the user has entered an appropriate checkbox selection, though.

I have this working, only it prints twice to the text area.
You still haven't posted a SSCCE that demonstrates the problem as you where asked in a previoius question.
Copying and pasting a few lines of code from your real problem does not help you isolate the problem.
As a beginner, you need to learn how to simplify problems. Once you simplify the problem it is easier to find and solve the problem.
In this case a working SSCCE will be about 20 lines of code. A couple lines to create the GUI, a few more to add the compnonents and a few more to create the ItemListener.
Post your SSCCE and I'll post the answer to your question. This is a common mistake when working with an ItemListener. I could probably give you the answer without seeing your SSCCE, but you need to learn how to create a SSCCE for when you encounter more complex problems. So this question is a good place to start.
Maybe looking at the section from the Swing tutorial on How to Write an Item Listenerwill help you understand what is happening.

Related

ActionListener and dynamic(?) GUI

I've read through a dozen or so actionlistener/loop related questions here, but I'm not sure I've found my answer. I started on my first large Java project, a text RPG that's spiraled into around 5K lines of logic and game features which was functioning as intended using just the console - when I decided I'd try to build a Java swing GUI for it instead. Here's my problem:
I use a Room object which handles the description of where the player is at and also has an array of options for the player to choose next which it creates dynamically based on what cell the room's id is in on a csv file and what is beside it. I stopped outputting this to the console and instead started creating JButtons based on the options array like so:
public void showNarrate(){
add(dd,gridConstraints);
optionCopy.clear();
int i = 0;
for(JButton j : optionButtons){
//adding and formatting buttons to gridBagConstraint I also set actionCommand for each button to the triggerValue (ID of the next room which the button should take the player to)
}
//I tried using a copy of my JButton array here so I could have something to iterate over in actionListener after clearing out the original
//(Since it needs to be cleared so the next Room's buttons can be built after the player chooses an option)
for(JButton j : optionButtons){
optionCopy.add(j);
}
optionButtons.clear();
//dd is a seperate drawingComponent I used for outputting room descriptions which may be totally unnecessary at this point :/
dd.repaint();
setVisible(true);
}
Over in actionlistener (Same class) this is how I tried to swing it:
for(JButton j : optionCopy){
if(e.getActionCommand().equals(j.getActionCommand())){
Main.saveRoom = Main.currentRoom;
Main.currentRoom = j.getActionCommand();
System.out.println(Main.currentRoom);
}
}}
Then in my main class I call:
narrator.narrate(currentRoom, saveRoom); which takes care of some other logic concerning locked doors, encounters, etc.
Also in Main loop are some other methods related to autosave and tracking which rooms the player has visited. I know from other q/a i'v read on here that this is all pretty bad design, and I'm sttarting to understand that now, but my issue is this:
The first room of the game loads up fine, when I click a button it outputs to console(Just for testing) the correct trigger value of the room the button should be calling, so I'm getting that far, but how can I call the same method over again now?
-If I call narrate from actionListener it will wind up calling itself again and complain about ConcurrentModification.
-If I try to keep a loop going in my Main class it will keep looping and won't allow for the player to actually choose a button.
I've never used threads before, which I wonder might be the answer,and the closest thing to a related answer I've found is this:
Java: Method wait for ActionListener in another class
but I don't think moving actionListener to Main class would resolve my problem which is actionListener winding up calling itself recursively. And as for the observer-observable pattern... I just can't understand it :(
I appreciate any and all help, I've learned a LOT trying to make this thing work without seeking help as much as possible but this has stumped me.
Your loop in actionPerformed only checks whether a JButton exists in your optionList with the given actionCommand. However this can be done before actually doing something:
boolean contained = false;
for (JButton j : optionButtons)
if (j.getActionCommand().equals(e.getActionCommand()))
contained = true;
if (contained) {
// change room
}
now you can call narrate because you have finished iterating over the collection beforehand and will not get a ConcurrentModificationException

Java in NetBeans - Adding actionEvents with custom parameters

I'm working on something in NetBeans, and I want to create an actionListener in a jTextPane for when the user presses Enter. However, I also need to input a String array (from a different subroutine within the source code) into the listener. But in NetBeans, events are generated automatically and I'm not allowed to edit this apparently extremely sensitive code. So, then, I tried typing up my own event thing (sorry about my terminology; I'm very new to GUI programming):
private void jTextPaneEnterPressed(KeyEvent evt, String[] stringArray)
{
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER)
{
// do something when the user presses enter that involves the program knowing what stringArray is
}
}
But when I run the program, pressing Enter in the text pane does nothing. I understand that this is because there is no actionListener associated with jTextPaneEnterPressed, but NetBeans gives no option for such customized code.
So what I want to know is either how I can pass in my own parameters when NetBeans creates an event handler, or how I can write my own actionListener alongside this actionPerformed block.
(And for the record, this is not an import problem)
I have tried looking this up, but have found nothing specific, as all other similar issues are not relevant to NB. Any help would be greatly appreciated.
*EDIT: This may seem like a trivial problem to most, but I'm open to any actual answers that tell me how to get done what I am trying to do, though I would prefer to stick with NetBeans. All I need is for the action listener to know that this string array exists, because the program needs to deal with that array when the user presses Enter. I'm sorry I can't give any specific context, but it's too much to get into.

Any way to delay PaintComponent?

I've read through lots of the threads on paintComponent here, most of which making the point that it either is never or almost never necessary (or possible) to choose when paintComponent is called.
In my program, however, sometimes (only sometimes) paintComponent gets called before some of the objects it needs to paint have finished initializing or even sometimes before they've been created, triggering warnings- JOptionPane pop-ups, which surprisingly do not show any of the text they were hard-coded to display in their "message" area. I've read in other places that it's something to do with the EDT, and I've looked into some parts of that but I'm just getting confused. If the main purpose of the EDT is to update the gui, and by default pretty much everything will run in the EDT, then could I tell the program to run all the initialization and update functions in a different thread(s), which I somehow forcibly make run before the EDT runs?
What I'd ideally like to have happen is for paintComponent to wait until a certain point in my code to be run (after a bunch of update functions, regardless of what happens to the screen. After it does get called, it is followed by a pause in which relatively little is going on ( I had been using Thread.sleep() inside a while loop ) and which lasts until the user clicks something - at which point all the necessary functions are run again, followed by paintComponent afterwards, then the sleep() while loop, etc.
From what I understand, I think what I want isn't really possible, so my question is: Do you guys have any ideas of how to get around this?
EDIT:
So essentially the program is a college course planner, intended to make it easier for someone to plan out by semester all the courses they have to take before graduation, move those courses around (if possible), and see how all the courses are connected (prerequisites and such). When the program starts, it loads the list of necessary courses from a text file, then loads info about each course from a bunch of individual text files, and arranges them according to their prerequisites. Courses with no prerequisites go in the first semester, courses whose prerequisites have all been added to the first semester get added to the second, and so on until all the courses have been added. When paintComponent runs, it calls a function that assume all of each course's prerequisites exist on the schedule, and if it finds otherwise, it throws an error and displays a JOptionPane message box. When this happens during a normal run of the program (like if I manually add a course before adding its prerequisites), that all works and displays correctly. But sometimes that message box pops up when only some of the courses have been loaded (meaning control is still in the main constructor) and when it does so, the actual string message doesn't show up - only the actual pane, title and ok button do. Heres the line where I display the error box, so you can know that I'm not trying to display a string variable which has the potential of being empty.
JOptionPane.showMessageDialog(this,
"Course couldn't be loaded, partially >loaded\ncourses have been removed.",
"Error",
JOptionPane.OK_OPTION);
It is the "Course couldn't...been removed." part that doesn't get displayed. This is the only JOptionPane I display with the title "Error".
This post mentioned what sounds like the same thing happening, except I'm not using any of the things that poster had to fix. So possibly it's irrelevant but I'll add it just in case. JOptionPane.showMessageDialog() shows but without any message?
But to step back a bit, because that box popped up before all the courses had been added, it means that paintComponent was somehow called in the middle of the relevant JPanel's constructor, before a bunch of things had been initialized. I added a bunch of println() statements to make sure that that is true. Is it normal for that to happen, and if so, is there a way to fix it without simply using Andrew Thompson's advice?
After thinking though it a bit, I think that because the project is 3200 lines long and relies to a huge extent on text files, I'm really not sure how to ( or if I can) make a SSCCE for it..
If any specific pieces would be helpful I'll gladly add those but if this problem isn't clearly some standard issue I'm getting wrong, then I'll just add that flag and keep looking for bugs.
Thanks for your help
Declare a flag as a class attribute. Check it in the paint method. Change it at the end of the initialization.
class XandYandZ extends JComponent {
boolean initializationFinished = false;
public XandYandZ() {
// long initialisation..
initializationFinished = true;
}
public void paintComponent(Graphics g) {
if (!initializationFinished) return;
// .. paint ..

variable when called in the same scope produces multiple values java

In a Java Swing desktop app. I have a number of smaller classes, all of which are made use of in an overarching App Class. One of such smaller classes is a JPanel that represents my login page. I've added a mouselistener to the login button on this page, that goes thus:
Public class loginPage extends JPanel{
String username;
boolean capturedName=false;
JTextField nameField;
...
loginButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
username = nameField.getText();
capturedName=true; //for redundant checking of mouse click event
System.out.println(username); //error checking
System.out.println(capturedName); //error checking
}
});
}
In a separate display class that represents my JFrame, I make the login page an attribute of said class and I instantiate this display class in my app class, after adding the login page to it. I am trying to capture the login page username attr in the App class and pass it to other methods. But when I run the code, and click on the login button, the value in the textbox isn't captured.
To error check, I tried the ff:
//Set login page GUI up
while(display.loginPage.username==null){ //this is initially true
if (display.loginPage.capturedName){ //boolean to check if button has been clicked
display.loginPage.username=display.loginPage.nameField.getText(); //intentional redundancy
String username=display.loginPage.username;
System.out.print(username);
//pass username to other methods
}
}
When I run the code, enter a name on the username textfield, and click login, the typed name and a true value for the capturedName boolean are both printed, but the
if (display.loginPage.capturedName)
condition is never fulfilled. Also when I add in print display.loginPage.username, I get a null value . What could be the reason for this discrepancy between the same values?
What could be the reason for this discrepancy between the same values?
You could have two objects of the same type, one displayed, whose state is being changed, and one not displayed that you're checking in the if block.
But again, for better help, consider creating and posting a Minimal, Complete, and Verifiable Example Program. We don't want to see your whole program, but rather you should condense your code into the smallest bit that still compiles, has no extra code that's not relevant to your problem, but still demonstrates your problem. As an aside, you will never want to use a MouseListener with a JButton as you're doing. Instead use an ActionListener as that is what it was built for.
"I've added a mouselistener to the login button" - Not a good idea, buttons should use ActionListener, see How to Write an Action Listeners and How to Use Buttons, Check Boxes, and Radio Buttons;
while(display.loginPage.username==null){ is a REALLY, REALLY bad idea which could lock up your UI and suggests that you violating the single thread rules of Swing. See Concurrency in Swing for more details.
What it sounds like you need is a modal dialog, which can block the execution of the code at the point the dialog is made visible...
See How to Make Dialogs for more details
Take a look at Java and GUI - Where do ActionListeners belong according to MVC pattern? for an example of a Login dialog/form using the MVC paridigm (Model-View-Controller)
Turns out as #MadProgrammer suggested, that I was creating two different loginPage objects in my display class. It's curious, however, that the mouselistener on the login page GUI that was visible actually listened for, and returned expected results of the better defined login page object (which was invisible).

Adding a cancel button to my JOptionPane

My question is the inverse of this one: Is there a way to only have the OK button in a JOptionPane showInputDialog (and no CANCEL button)?
One solution to that was (if I read correctly) to add an arbitrary JPanel, in that instance a label. My problem is that I need a JComboBox object in the message window, and (in the same way that solved Coffee_Table's problem) having the JComboBox seemingly removes the cancel button. It doesn't matter if I replace YES_NO_CANCEL_OPTION with OK_CANCEL_OPTION or QUESTION_MESSAGE.
I'm still at the mindless-copying stage of learning about the JOptionPane family, so I presume the solution is obvious and I just don't know it because I haven't seen any specific examples to mindlessly copy. (Which also means that once I learn how to add a cancel button, I'll need to work on how to access whether the user hit it. EDIT: And I'm half-sure how I'd do it, so you don't need to answer it if you don't want to.)
public static void main(String[] args) {
int numCh1 = 1;
String[] moves = {"rock","paper","scissors"};
JComboBox<?> optionList = new JComboBox<Object>(moves);
JOptionPane.showMessageDialog(
null,
optionList,
"Player One: Choose a Move",
JOptionPane.YES_NO_CANCEL_OPTION
);
numCh1 = optionList.getSelectedIndex();
System.out.println(moves[numCh1]);
}
Note: The combo box is non-negotiable (as opposed to, say, three buttons) because my actual project is to simulate rps101; I just figured you didn't need to see all 100 moves (or anything else irrelevant to this question).
You're using the showMessageDialog() method, which shows just that: a message. It doesn't have a cancel option. For that, use one of the other methods.
In fact, that last parameter isn't even valid. It's not looking for an option type like you provided, it's looking for a message type (ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE, or PLAIN_MESSAGE).
As always, the API is your best friend: http://docs.oracle.com/javase/7/docs/api/javax/swing/JOptionPane.html

Categories