简体   繁体   中英

Blocking main-thread after gui-event

I've been making a program that reads from a file, identifies common "posts" in the file, and makes a summary of these. My problem is that the GUI-event that allows the user to specify the name and search-term of the post, does not interrupt the running of the program, like I want it to.

I can make it stop, but then the GUI will not be correctly displayed. I have tried some solutions, which will be specified at the bottom of the post.

EDIT: removed codedump and added something resembeling an SSCCE:

class SSCCE{
public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable(){
        @Override
        public void run(){
            new Gui();
        }
    });
}
}

class Gui implements ActionListener{

boolean runn=true;
JFrame wind2;
JTextField nameF, searchtermF;
JButton done;

Gui(){
    runEx();
}

public void runEx(){

    int i =0;
    while(runn){
        if(i==10)   break;
        System.out.println("Open window and record information given! One at the time!!!");
        System.out.println(" ");
        giveName("test");

        i++;
    }
}

public void giveName(String s){


    JLabel nameL = new JLabel("Give this post a name:");
    JLabel searchL = new JLabel("What do you want the searchterm to be?");

    wind2 = new JFrame("EazyMoney");
    wind2.setLayout(new BorderLayout());

    JPanel all = new JPanel();
    all.setLayout(new GridLayout(2,2));


    searchtermF = new JTextField(30);
    nameF=new JTextField(30);

    all.add(nameL);
    all.add(nameF);
    all.add(searchL);
    all.add(searchtermF);

    done = new JButton("Press when you have filled in the information!");
    done.addActionListener(this);

    String prn = "The post in question: " + s;
    JLabel header = new JLabel(prn);

    wind2.add(header, BorderLayout.NORTH);
    all.setVisible(true);
    wind2.add(all, BorderLayout.CENTER);
    wind2.add(done, BorderLayout.SOUTH);

    wind2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    wind2.pack();
    wind2.setLocationRelativeTo(null);
    wind2.validate();
    wind2.setVisible(true);
}

public void actionPerformed(ActionEvent e){
    System.out.println("Action recorded, new window can now be shown. All information stored.");
    System.out.println(" ");
}
}

The solutions I have tried is:

  • A simple block, that does a while(true){} and sets the variable to true after the first instance of g.giveName() have been called. I used the ActionListener to call a method that then changed the variable to false again, when the necessary input was given. This resulted in a gray box, with nothing in it.
  • Making a cyclic barrier that did the same as the block above. Used a separate thread to call g.giveName() and then call the await() from the action listener. Same result as above.
  • Making readFile be run by a separate thread and call invokeAndWait() on the g.giveName() function. Gave cannot call invokeAndWait() from the EDT-thread , even though it was run from a new thread.

I can not give examples of the code used in instances above, as I have tried a lot of different solutions and do not have it any more. Please take into account that it might have been implemented wrong, and thus might be a valid answer to my question, even though I could not seem to get it to work!

Final note: all work can be found here, if you wish to test the code: https://github.com/Robiq/EazyMoneyWork

The way to avoid blocking the EDT if you need to execute something else on the same thread it is to temporarily create a new event queue. Here is some example code. In this case it blocks the current thread waiting for some other event to be signalled but you could replace this with whichever long running process is required.

First check if you are running on the EDT: SwingUtilities.isEventDispatchThread . Then if you are:

EventQueue tempEventQueue = new EventQueue();
Toolkit.getDefaultToolkit().getSystemEventQueue().push(tempEventQueue);
try {
    wait();
} catch (InterruptedException ex) {
    // stop waiting on interrupt
} finally {
    tempEventQueue.pop();
}

Something similar to this is how modal dialogs work in Swing. However in general it's not good practice. Much better is to understand which events to listen for to perform specific actions. In your case the user event should not 'stop' your program - it should disable inappropriate components until the user has responded and then re-enable them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM