I have a button with action listener. When action is performed I call a method to show a label with my message using:

Actionperformed(){
    ShowMessage();
    PerformAction();
}

NOTE: This code is just an example.

The problem is the message never shows even though the action is performed.

Any help will be appreciated. Thanks in advance

Recommended Answers

All 24 Replies

Hi!

Can post your exact code to know more..,

how are you showing a message? in a command prompt? then maybe it is shown, but overwritten by later information. you give way too little information for us to base ourselves on.
you're also being pretty vague in what exactly you are trying to achieve, so you may want to elaborate on that a bit.

Are you trying to do this?

actionPerformed ...
   show "busy" message
   do some stuff
   remove "busy" message

if so...

Everything to do with Swing (eg painting the screen, running actionPerformed methods) happens on a single thread - the "Event Dispatch Thread", or "EDT", or "Swing thread".
That means that once your actionPerformed method starts NOTHING else will happen in Swing, including no screen updates, until your method finishes. You can update stuff and loop and sleep as much as you like, but none of that will affect what's on the screen until your method has terminated.

The one interesting exception is if you use a JOptionPane for the busy message...

Having said all that, if the "stuff" takes long enough to notice, then it should not be on the swing thread anyway. SwingWorker is a good option.

You need to use SwingWorker. He is used for progres bars i think you can redesign it, so you can show message you want in seperate thread so your method will run free.

I used that to download picture from internet and in progres bar I will show how much proces is done. So your method will download everything you need and other will show message.

I am attempting to show a message using a JLabel that displays "SHUFFLING CARDS" while the deck is being shuffled. At the end of the shuffle method I set visible to false for said label. The show label method is working as it should, if I comment out the visible(false) statement it shows after the suffle has completed. I will research the swingworker option but any help is appreciated.

OK, that's exactly the scenario I guessed in my first post. You cannot do it like that becuase of the way the EDT works.
SwingWorker is definitely what you should look at. The API doc starts with a couple of examples - the first one should give you what you need. In your actionPerformed set the message and call execute() for your SwingWorker. In the SwingWorker's done() method just turn the message off again.

Shouldn't the shuffle method take only a few miliseconds to run, if that? Swingworker is for tasks that take so long to execute that they will make the UI unresponsive. So if your shuffle method takes a second or two to run then it should definetly be on another thread. But unless your shuffle method is actually displaying an animation of the cards gettings shuffled or you have some unusual game that is played with a deck of 25,000 cards, I don't see why a shuffle would take so long.

That's a very good point. A standard Fisher-Yates / Knuth Shuffle on a 52 element array runs in microseconds.

I plan to make this a multi-player game over a LAN. Everyone needs to play from the same deck or decks of cards(Single Deck, Double Deck or Six decks). I'm writing the card index and value of the card to a database. All cards are dealt from this database. It does take a while(5 - 7 seconds for double deck) but it is effective.
By the way thanks for the help with displaying my label. I used the suggestion from James:

OK, that's exactly the scenario I guessed in my first post. You cannot do it like that becuase of the way the EDT works.
SwingWorker is definitely what you should look at. The API doc starts with a couple of examples - the first one should give you what you need. In your actionPerformed set the message and call execute() for your SwingWorker. In the SwingWorker's done() method just turn the message off again.

Database processing over a network connection is exactly the kind of thing SwingWorker is good for, so that's OK.
But 7 seconds for 104 tiny records? That sounds crazy! If you want to post the relevant code I'm sure we can get that way way faster.

I believe the reason it takes so long is that I'm adding random generated cards to the database instead of selecting a random card from the database.

public static void ShuffleDeck() {

        SwingWorker<Void, Void> Worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() {

                int[] Deck = new int[Table.CreateTable.NumCards];

                for (int a = 1; a < Deck.length; a++) {
                    Deck[a] = a;
                }

                try {
                    con = DriverManager.getConnection(host, uName, uPass);
                    Clean = con.createStatement();
                    Clean.executeUpdate("DELETE FROM cards WHERE ID > 0");//("TRUNCATE cards");
                    Clean.executeUpdate("ALTER TABLE cards AUTO_INCREMENT = 1");

                    Clean.close();

                } catch (SQLException err) {
                    System.out.println(err.getMessage());
                }

                // Shuffle the cards - Add index of cards to a HashSet
                Set<Integer> generated = new LinkedHashSet<Integer>();
                while (generated.size() < Deck.length) {
                    Integer index = rand.nextInt(Deck.length) + 1;
                    // As we're adding to a set, this will automatically do a containment check
                    generated.add(index);
                }

                //Write card index to database
                Iterator itr = generated.iterator();

                try {
                    con = DriverManager.getConnection(host, uName, uPass);
                    stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
                    String SQL = "SELECT * FROM cards";

                    while (itr.hasNext()) {
                        int thisCard = ((int) itr.next() - 1) % 52;//Makes sure card is a value between 1 and 52
                        int thisVal = (thisCard) % 13;//Writes a value of 1 to 13 in the datbase associated with thisCard
                        rs = stmt.executeQuery(SQL);
                        rs.moveToInsertRow();
                        rs.updateInt("CardIndex", thisCard + 1);//(int) itr.next());
                        rs.updateInt("CardValue", thisVal + 1);
                        rs.insertRow();
                    }

                    stmt.close();
                    rs.close();

                } catch (SQLException err) {
                    System.out.println(err.getMessage());
                }
                generated.clear();
                Table.CreateLayout.gameInfo.setVisible(false);

                return null;
            }

            @Override
            protected void done() {

                Table.CreateLayout.gameInfo.setVisible(false);
                Players.Player1Actions.PlayerCard1();

            }
        };
        Worker.execute();
    }
}

First mistake is creating a new connection for each statement. Opening a connection is expensive. Just open a connection when starting the program and re-use that throughout.
Secondly: I wasn't able to understand why you have all that code and complexity just to create a shuffled deck of cards. Can you explain what else you are trying to achieve? What is the format and content of the table you are trying to create?

Should we put this in another discussion?

I'm not clear on why a database is being used at all. Is there no server component, just different clients for the various players all syncing with the same database?
I would have the clients all communicate with a server (either with TCP if this is running on a LAN or http REST calls or web sockets). The state of the deck could just be kept in RAM by the server and all the latency problems go away.

Actually I haven't gotten to the point were I'm ready to add additional players yet. The previous post were inquiring about the amount of time it takes to shuffle the cards. The database is a preference of mine because I like to see what is going on and to insure all players from a table are playing from the same deck. Keep in mind the cards are not shuffled at the begining of each round, just when a shuffle is required (As in after a set number of cards have been dealt and the round is over). I do plan to have players connect to my computer which I will use as a server initally. Thanks for your input on the matter.

If you keep a master table with the right number of complete decks, you can simply get a shuffled deck by selecting all the records in the master in random order. eg for JavaDB (Derby) you can just use
SELECT * FROM ONEDECKMASTER ORDER BY RANDOM()

OK, let's back up to creating the connection part. Create one connection that stays open thought the program. I have yet to figure out how this works. Could you explain that and maybe an example. I'm using MySQL, the table has 3 columns in it(ID as primary, CardIndex and CardValue). It is a innoDB database. I have already created a class called Connection1() in a folder named Connections. Here is the code from that Class:

package Connections;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 *
 * @author Henry S.
 */
public class Connection1 {

    static String host = "jdbc:mysql://localhost:3306/henderson_games";
    static String uName = "root";
    static String uPass = "nbuser";
    static Connection con; //Creates connection
    static Statement stmt; //Creates object to hold our statement
    static Statement Clean;
    static ResultSet rs; //Creates object to hold the results of our statement

    public static void Connection1() {

        try {
            host = "jdbc:mysql://localhost:3306/henderson_games";
            uName = "root";
            uPass = "nbuser";
            con = DriverManager.getConnection(host, uName, uPass);
            stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
            String SQL = "SELECT * FROM cards";
            rs = stmt.executeQuery(SQL);
        } catch (SQLException err) {
            System.out.println(err.getMessage());

        }

    }
}

I have need to have 3 connections that do different things. I think that would be a matter of changing the SQL string, not sure.

I need to know how to access the connection from different classes.

You can use one connection with multiple SQL commands and strings. Just connect once and use multiple createStatements.
Access the connection just like any other Java variable - pass it to the classes that need it, or provide a getter method that returns it, etc. Which you chose depends on how the application is structured.

I think I have it. I have commented out all the code that calls for a new connection. I left it there because I'm not sure this is the correct way to do this. I made con a public static variable and the imported into the classes where it is needed. Here is the updated DECK code:

package DeckActions;

import static Connections.Connection1.con;
import static Table.CreateLayout.gameInfo;
import static Table.CreateTable.NumCards;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
import javax.swing.SwingWorker;

/**
 *
 * @author Henry S.
 */
public class CreateDeck {

    static Random rand = new Random();

    //Creates connection
//    static String host = "jdbc:mysql://localhost:3306/henderson_games";
//    static String uName = "root";
//    static String uPass = "nbuser";
//    static Connection con; //Creates connection
    static Statement stmt; //Creates object to hold our statement
    static Statement Clean;
    static ResultSet rs; //Creates object to hold the results of our statement

    public static void ShuffleDeck() {

        SwingWorker<Void, Void> Worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() {

                int[] Deck = new int[NumCards];

                for (int a = 1; a < Deck.length; a++) {
                    Deck[a] = a;
                }

                try {
//                    con = DriverManager.getConnection(host, uName, uPass);
                    Clean = con.createStatement();
                    Clean.executeUpdate("DELETE FROM cards WHERE ID > 0");//("TRUNCATE cards");
                    Clean.executeUpdate("ALTER TABLE cards AUTO_INCREMENT = 1");

                    Clean.close();

                } catch (SQLException err) {
                    System.out.println(err.getMessage());
                }

                // Shuffle the cards - Add index of cards to a HashSet
                Set<Integer> generated = new LinkedHashSet<Integer>();
                while (generated.size() < Deck.length) {
                    Integer index = rand.nextInt(Deck.length) + 1;
                    // As we're adding to a set, this will automatically do a containment check
                    generated.add(index);
                }

                //Write card index to database
                Iterator itr = generated.iterator();

                try {
//                    con = DriverManager.getConnection(host, uName, uPass);
                    stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
                    String SQL = "SELECT * FROM cards";

                    while (itr.hasNext()) {
                        int thisCard = ((int) itr.next() - 1) % 52;//Makes sure card is a value between 1 and 52
                        int thisVal = (thisCard) % 13;//Writes a value of 1 to 13 in the datbase associated with thisCard
                        rs = stmt.executeQuery(SQL);
                        rs.moveToInsertRow();
                        rs.updateInt("CardIndex", thisCard + 1);//(int) itr.next());
                        rs.updateInt("CardValue", thisVal + 1);
                        rs.insertRow();
                    }

                    stmt.close();
                    rs.close();

                } catch (SQLException err) {
                    System.out.println(err.getMessage());
                }
                generated.clear();
                gameInfo.setVisible(false);

                return null;
            }

            @Override
            protected void done() {

                gameInfo.setVisible(false);
                Players.Player1Actions.PlayerCard1();

            }
        };
        Worker.execute();
    }
}

The section that uses the "clean" statement is used to clear the database and reset the auto increment to 1.

The other section writes the info to the database.

Any way to make it faster?

The static "global" variable is a perfectly valid solution... maybe not the best O.O practice, but OK in this context. It's certainly the easiest to code!

As for other speedups, keep "master" tables for a complete deck or decks, and copy then to a new table in random order (see my previous post about shuffling a deck).

Sounds great, let me go research Mysql a learn that now.

About "Public Static Variables" what are the issues involved with using them. I THINK I may have a few of those about my program.

About "Public Static Variables" what are the issues involved with using them.

Here's a pretty decent discussion of this topic.

Thanks for the link.

Finally got around to trying to speed up my shuffle. Here is the code I'm using:

public class CreateDeck2 {

    static Statement stmt; //Creates object to hold our statement

    public static void ShuffleDeck() {

        SwingWorker<Void, Void> Worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() {

                try{

                stmt = con.createStatement();
                stmt.execute("DROP TABLE cards");
                stmt.execute("CREATE TABLE IF NOT EXISTS cards LIKE 2deck");
                stmt.execute("INSERT INTO cards SELECT *  FROM 2deck");
                stmt.execute("SELECT * FROM cards ORDER BY RAND()");
                } catch (SQLException err) {
                    System.out.println(err.getMessage());
                }
                return null;
            }

    @Override
            protected void done() {
                gameInfo.setVisible(false);
                Players.Player1Actions.PlayerCard1();
            }
        };
        Worker.execute();
    }

This cuts the time of shuffle in half. Now I have a problem with the rand(), it randomizes the orignal table but always with the same output. I need to fix this random staement and a little quicker shuffle would be nice. It sounds like your suggesting that I randomize as I copy the data over. If that's the case the more research is needed.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.