Help With Qt Programming; Approaching a Program



  • Hello QtForum,

    My name is Angel and I'm looking for some help in approaching a GUI development project for school. I need to develop/design a GUI interface, in this case a GUI that allows a user to play Baccarat, a casino game between a dealer and player.

    Anyways, I have wrote all of the code in straight C++ and have got the game running smoothly in command prompt, but now my problem comes into translating that into a GUI interface. The main question I have how would you more experienced programmers go about tackling this? I know that when a user presses the "Bet" button, I want the program to basically run the game. Would I need to make ONE function that will run the game and connect that to the button slot? Also, I want to display the cards in the window; would I need to make two "child" widgets inside of the main window and use them as containers to display the cards? And finally, what would you guys recommend I use to display the cards; I've looked up examples both online and in the Qt Book and most of the examples used to display images are QLabel and QPixmap; which would you guys recommend?

    Apologies if I placed this in the wrong forum or if this is asking too much, I just need a guide in the right direction. Thank you for your help.

    Also, I wanted to post my code including the classes so you guys can get a good idea of what I am working with but I'm not sure if there are limits to how long a post can be. Thanks for your time.



  • Yes, I think you can simply create a Slot function and connect it to the QPushButton's clicked() Signal. Then, in the the Slot function, you can call your existing code. Also using QLabel's with setPixmap() to show images, like the cards, is a reasonable approach. You could update the cards as soon as your existing function returns.

    A more sophisticated design would be wrapping your Game logic into a "model" class. The game model class would then provide Slots to activate player actions and Signals to emit updates to the game status. For example, the game model class could provide a bet() Slot, which you could connect directly to the clicked() Signal of the Bet button of your GUI dialog class. In turn, the game model class could provide a cardsChanged() Signal, which it does emit whenever the cards change. The GUI dialog could connect to that Signal and update the cards being displayed on every change. Now all the game logic is handled "inside" the model class and you can connect as many views to the model as you like. You could have a GUI view and a Console view at the same time.

    Sketch:
    @//---------------
    //game_model.h
    //---------------

    class MyGameModel : public QObject
    {
    Q_OBJECT

    public slots:
    void bet();

    signals:
    void cardsChanged();

    /* ... */
    

    }

    //---------------
    //game_model.cpp
    //---------------

    /Your existing code goes here, implementing the game model/
    /Don't forget to "emit cardsChanged()" as soon as something changed!/
    /You will need some more "getter" functions here, I guess.../

    //---------------
    //gui_view.cpp
    //---------------

    /constructor/
    MyGuiDialog::MyGuiDialog(QWidget *parent, MyGameModel *model)
    :
    QDialog(parent)
    {
    m_model = model;
    connect(m_model, SIGNAL(cardsChanged()), this, SLOT(handleUpdates()));
    connect(ui->myBetButton, SIGNAL(clicked(bool)), m_model, SLOT(bet()));
    }

    /update handler/
    void MyGuiDialog::handleUpdates(void)
    {
    /update the GUI as needed, after model has changed/
    }

    //---------------
    //main.cpp
    //---------------

    main(/.../)
    {
    QApplication app;
    MyGameModel *model = new GameModel();
    MyGuiDialog *dialog = new MyGuiDialog(NULL, model);
    /could create something like a "ConsoleView" here too!/
    dialog->show();
    app.exec();
    }@

    Finally, you may think about running the game logic in a separate "background" thread, so the GUI doesn't "lock up" while the game logic is running calculations. Have a look at QThread for this purpose...



  • IMHO, another approach would be to separate your GUI from your app, as in using Qt as a "frontend" for your command line application. This approach uses QProcess (or QtDBus). This way your game logic will not be modified.

    QLabel is, I think, the easiest way to show images in a GUI but you may try the QWidget+QPainter way. From experience, it is more responsive and faster than QLabel.



  • [quote author="MuldeR" date="1353885716"]
    @/constructor/
    MyGuiDialog::MyGuiDialog(QWidget *parent, MyGameModel *model)
    :
    QDialog(parent)
    {
    m_model = model;
    connect(m_model, SIGNAL(cardsChanged()), this, SLOT(handleUpdates()));
    connect(ui->myBetButton, SIGNAL(clicked(bool)), m_model, SLOT(bet()));
    }

    /update handler/
    void MyGuiDialog::handleUpdates(void)
    {
    /update the GUI as needed, after model has changed/
    }

    //---------------
    //main.cpp
    //---------------

    main(/.../)
    {
    QApplication app;
    MyGameModel *model = new GameModel();
    MyGuiDialog *dialog = new MyGuiDialog(NULL, model);
    /could create something like a "ConsoleView" here too!/
    dialog->show();
    app.exec();
    }@
    [/quote]

    Thank you for your response MuldeR,

    I had a question about your handleUpdates function. In this function are you implementing anything the changes in the GUI, such as showing the cards, a bet placed(like possibly showing some casino chips of some sort), or do I have the idea of this function wrong?

    Your approach to it definitely makes a lot more sense to me, thank you for your response.

    Also, I have a Player and a Dealer class which each store their own bets, hands, etc. How would I include that because it seems that the GameModel class only has 1 bet, when I really need 2(one for each). Below is the code for my Player class(the Dealer class is exactly the same, just substitute "Dealer" wherever your see "Player").

    @#ifndef Player_h
    #define Player_h

    #include <QMainWindow>
    #include <QObject>

    class Player : public QObject
    {
    Q_OBJECT

    public:
    Player();
    ~Player(){delete []playerHand;}
    int getBet();
    double getAdjustedBet();

    public slots:
    void setHand(int, int);
    void printCard(int);
    void printHand(int);
    void setBet(int);
    int returnScore(int);
    void setThirdCard(int);

    signals:
    void pushButton();

    private:
    int bet, rank, suit;
    int *playerHand;
    double adjustedBet;
    bool test;
    };

    #endif
    @

    @#include "Player.h"
    #include <iostream>
    using namespace std;
    #include <cstdlib>

    Player::Player()
    {
    playerHand=new int[3];
    bet = 0;
    }

    void Player::setBet(int s)
    {
    test = true;
    while(test)
    {
    if(s>=0)
    {
    bet = s;
    test = false;
    }
    else
    {
    cout << "Invalid bet placed. Try again." << endl;
    cin >> s;
    bet = s;
    }
    }
    }

    int Player::getBet()
    {
    return bet;
    }

    double Player::getAdjustedBet()
    {
    adjustedBet = bet + (bet * 0.9);
    return adjustedBet;
    }

    void Player::setHand(int card1, int card2)
    {

    playerHand[0] = card1;
    playerHand[1] = card2;
    playerHand[2] = 0;
    

    }

    void Player::setThirdCard(int card3)
    {
    playerHand[2] = card3;
    }

    void Player::printCard(int Card)
    {
    rank = ( Card % 13);
    if(rank==0)
    cout << 'A';
    else if(rank < 9)
    cout << (rank + 1);
    else if(rank == 9)
    cout << 'T';
    else if(rank == 10)
    cout << 'J';
    else if(rank == 11)
    cout << 'Q';
    else
    cout << 'K';

    suit = ( Card / 13 );
    if(suit==0)
        cout << 'D' << endl;
    else if(suit==1)
        cout << 'C' << endl;
    else if(suit==2)
        cout << 'S' << endl;
    else
        cout << 'H' << endl;
    

    }

    void Player::printHand(int playerCardCount)
    {
    for(int i=0;i<playerCardCount;i++){
    printCard(playerHand[i]);
    }
    }

    int Player::returnScore(int numCards)
    {
    int numAces = 0;
    int score = 0;
    int cardCount = numCards;

    for (int index=0; index<cardCount;index++)
    {
        int card = playerHand[index];
        int rank = (card % 13);
    
        if(rank==0)
        {
            numAces++;
            score++;
        }
        else if(rank < 9)
        {
            score = score + (rank + 1);
        }
        else
            score+=0;
    }
    
    if (score>9)
        score-=10;
    
    return score;
    

    }
    @



  • Well, I think you can do this how you like. There is no "right" or "wrong" design. You can give your GameModel a single somethingChanged() Signal that is used for all kinds of updates and the GUI will use a single handleUpdates() Slot to process all the updates. But you can as well define more fine-grained Signals in your GameModel class, like cardsChanged(), scoreChanged(), gameEnded() and so on. Then your GUI class can process them separately in separte Slots. Yet another option is to use a single Signal, but give it some parameters. Those parameters passed in the Signal can indicate what exactly has changed and/or what the new value is. Of course the latst two options (fine-grained Signals and parameters) can be combinded.

    About the Player and Dealer classes: You can make a single GameModel class that internally maintains an instance of Player and Dealer to do the actual work, so from the outside there is a single "game" interface. Alternatively the game model can be split into a DealerModel and PlayerModel class, so, instead of a single GameModel class, we have two cooperating classes that implement the game model. You decide what is more suitable...



  • Thank you so much for your help, I finally have a way of approaching this program. I don't have anymore questions for now, maybe I will once I start implementing the functions, classes, etc. later in the afternoon. Thank you for your help once again.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.