Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Moving all my buttons to a frame?

Moving all my buttons to a frame?

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 5.1k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    anil_arise
    wrote on last edited by
    #3

    @anarelle said in Moving all my buttons to a frame?:

    layout->addWidget(btn01);

    syntax error..

    use of gridlayout: SYNTAX
    layout->addWidget(btn01,0,0);
    layout->addWidget(btn02,0,1);

    1 Reply Last reply
    0
    • Maaz MominM Offline
      Maaz MominM Offline
      Maaz Momin
      wrote on last edited by
      #4

      @anarelle can you paste your ui_MainWindow.h code?

      1 Reply Last reply
      1
      • A Offline
        A Offline
        anarelle
        wrote on last edited by anarelle
        #5

        Thanks for your answers :)
        I have my game almost ready, so I'll post the relevant parts of the code.

        It's memory game where 12 tiles display on screen, then you click on two and try to match the images they show. My tiles are implemented as QPushButtons. Each one is clicked, an image is displayed (by calling a showImage() method that changes the button background). When a second tile is clicked, if there is a match the two buttons are disabled so user can't click on them again (and score increases). If there was no match, the two tiles go back to their initial state (no background) after 1 second.

        Also, when the first "tile" (button) is clicked I set enabled to false until a second button is clicked. If there is no match, then both buttons get their blank background again and they are setEnabled(true). I'm using a single shot QTimer to reset both tiles after a no-match.

        There is also a countdown for 1 minute, implemented as another QTimer. If the countdown reaches 0, then a message is displayed saying game is over. If after matching 2 tiles the match count is 6 (as there are 12 tiles), then a message shows saying the total score reached.

        This is what I have on mainwindow.h:

        namespace Ui {
            class MainWindow;
        }
        
        class MainWindow : public QMainWindow{
            Q_OBJECT
        
        
        public:
            explicit MainWindow(QWidget *parent = nullptr);
            ~MainWindow();
            QTimer *timer=new QTimer();
            QTime time{0,1,0};
            QVector<QString> tiles{"btn01", "btn02", "btn03", "btn04",
                                      "btn05", "btn06", "btn07", "btn08",
                                      "btn09", "btn10", "btn11", "btn12"};
            QHash<QString, QString> hash;
            int score=0;
            bool turnStarted=false;
            QPushButton* previousTile;
            QPushButton* currentTile;
            int pairsLeft=6;
            QMessageBox msgBox;
         
        
        private slots:
            void updateCountDown();
            void tileClicked();
            void randomize(QVector<QString> &tiles);
            void bind(QVector<QString> &tiles, QHash<QString, QString> &hash);
            void checkPartialResult();
            void turnTilesBack();
            void showBackground();
            void checkFinalResult();
            void updateCountDown();
        
        private:
            Ui::MainWindow *ui;
        };
        

        And this is part of mainwindow.cpp:

        MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){
            ui->setupUi(this);
        
            //Set up countdown
            connect(timer, SIGNAL(timeout()), this, SLOT(updateCountDown()));
            timer->start(1000);
            ui->countdown->setText(time.toString("m:ss"));
        
            //Button names are stored in a QVector, so they need to be sort randomly. After that, grab pairs of tiles and bind the name of an image file to each pair. Store this in a QHash where each key is a button name and its value is the image it should show when that button is clicked.
            randomize(tiles);
            bind(tiles, hash);
        
            //Connect each button to the same slot, which will figure out which button was pressed and show its associated image file accordingly
            connect(ui->btn01, SIGNAL(clicked()), this, SLOT(tileClicked()));
            connect(ui->btn02, SIGNAL(clicked()), this, SLOT(tileClicked()));
            //etc (all 12 tiles are set the same way)
        

        I won't post all my methods as it would be too long, but this is where I'm trying to make changes: this is the method called every time a second tile is clicked, to find out if there was a match:

        void MainWindow::definirResultadoParcial(){
            //check if there is a match (the current tile matches the previous tile in the turn)
            if (hash[currentTile->objectName()]==hash[previousTile->objectName()]){
                score+=15;
                pairsLeft--;
        
                //if there is a match, find out if all 12 tiles have been matched.
                checkFinalResult();
            }
            else{
                score-=5;
        
                //if there is no match, after 1 second turn back both tiles from current turn so they can be used in future turns
                QTimer::singleShot(1000, this, SLOT(turnTilesBack()));
            }
        }
        

        When there is no match, I need the mis-matched tiles to remain on screen for 1 second and then turn them back (remove their backgrounds). However, as the QTimer seems to be running on a different thread, this makes it possible for the user to continue clicking on tiles, before the singleShot timer has timed out.

        So, when a second button is clicked and there is no match, I need to disable all my buttons for 1 second and then re-enable only the ones that hadn't been matched yet. That's why I'm trying to set up my buttons inside some sort of container that I can disable and re-enable without losing my buttons state.

        However, I didn't use any layouts or anything. I only dragged & dropped buttons on my form. So I don't have any layouts. Are they absolutely necessary? I'd actually like to avoid messing with my buttons if possible. What's the simplest way to achieve what I'm trying to do?

        Thanks again :)

        1 Reply Last reply
        0
        • mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by mrjj
          #6

          Hi
          Fist of all, layouts are only needed if you wish/need your tile area to be able to follow size of the Mainwindow so
          if user resize it, it can use more or less space. If a fixed size is ok, you dont need layout as such.
          However, its very common to do as screen can have many different resolutions. Especially laptops.

          Regarding, preventing clicking while 1 sec "timeout". The QTimer do not block the GUI tread and hence
          user can still click stuff.

          But you dont really need container to disable them.
          Just add a QList<QPushButtons *> buttonsList; to mainwindow.h
          then when you connect them, also append to this list.
          buttonsList.append(ui->btn01) etc.

          Then before
          QTimer::singleShot(1000, this, SLOT(turnTilesBack()));
          you simply loop over the buttonsList and disable each of them.
          Using a function like
          setEnableForAll(bool state)
          that loops the list, allows you to easy call with true or false to enable or disable on when needed.

          A 1 Reply Last reply
          1
          • mrjjM mrjj

            Hi
            Fist of all, layouts are only needed if you wish/need your tile area to be able to follow size of the Mainwindow so
            if user resize it, it can use more or less space. If a fixed size is ok, you dont need layout as such.
            However, its very common to do as screen can have many different resolutions. Especially laptops.

            Regarding, preventing clicking while 1 sec "timeout". The QTimer do not block the GUI tread and hence
            user can still click stuff.

            But you dont really need container to disable them.
            Just add a QList<QPushButtons *> buttonsList; to mainwindow.h
            then when you connect them, also append to this list.
            buttonsList.append(ui->btn01) etc.

            Then before
            QTimer::singleShot(1000, this, SLOT(turnTilesBack()));
            you simply loop over the buttonsList and disable each of them.
            Using a function like
            setEnableForAll(bool state)
            that loops the list, allows you to easy call with true or false to enable or disable on when needed.

            A Offline
            A Offline
            anarelle
            wrote on last edited by
            #7

            @mrjj Thanks :) maybe that's the best way to go, as I don't need to support different resolutions. I thought adding widgets to a container and then enabling/disabling the container would be easier, but it would actually require too many changes.

            mrjjM 1 Reply Last reply
            0
            • A anarelle

              @mrjj Thanks :) maybe that's the best way to go, as I don't need to support different resolutions. I thought adding widgets to a container and then enabling/disabling the container would be easier, but it would actually require too many changes.

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by
              #8

              @anarelle
              well it should not BE super complicated to place QFrame on the form
              and select all buttons and drag to the QFrame. and then let it handle enable/disable
              for its children.
              However, i do wonder how you reset the images on the buttons.
              Dont you loop the buttons somehow there too ?

              A 1 Reply Last reply
              1
              • mrjjM mrjj

                @anarelle
                well it should not BE super complicated to place QFrame on the form
                and select all buttons and drag to the QFrame. and then let it handle enable/disable
                for its children.
                However, i do wonder how you reset the images on the buttons.
                Dont you loop the buttons somehow there too ?

                A Offline
                A Offline
                anarelle
                wrote on last edited by
                #9

                @mrjj As for your question, I only have to reset 2 images on each turn (when the user unveils the second image, if it doesn't match with the first image then I remove the background on both):

                void MainWindow::turnTilesBack(){
                    //return tiles from current turn to the default state (remove backgrounds)
                    previousTile->setStyleSheet("#" + previousTile->objectName() + "{ }");
                    currentTile->setStyleSheet("#" + currentTile->objectName() + "{ }");
                
                    //re-enable both tiles so they can be used on another turn
                    currentTile->setEnabled(true);
                    previousTile->setEnabled(true);
                }
                

                This only happens when there's no match. If there's a match then I only disable the buttons but the backgrounds are not changed, so the user can clearly see which tiles are left. So I don't have to keep the state of each button. I manage it on each turn. I was trying to avoid having to keep the state of the buttons (although I could do that by just adding the disabled ones to a vector), that's why I was trying to add the QFrame.

                So in order to add a QFrame and add the buttons to it I shouldn't need a layout at all? That's where I was getting confused. I'll try adding the buttons to the QFrame directly and let you know how it turns out :)

                mrjjM 1 Reply Last reply
                0
                • A anarelle

                  @mrjj As for your question, I only have to reset 2 images on each turn (when the user unveils the second image, if it doesn't match with the first image then I remove the background on both):

                  void MainWindow::turnTilesBack(){
                      //return tiles from current turn to the default state (remove backgrounds)
                      previousTile->setStyleSheet("#" + previousTile->objectName() + "{ }");
                      currentTile->setStyleSheet("#" + currentTile->objectName() + "{ }");
                  
                      //re-enable both tiles so they can be used on another turn
                      currentTile->setEnabled(true);
                      previousTile->setEnabled(true);
                  }
                  

                  This only happens when there's no match. If there's a match then I only disable the buttons but the backgrounds are not changed, so the user can clearly see which tiles are left. So I don't have to keep the state of each button. I manage it on each turn. I was trying to avoid having to keep the state of the buttons (although I could do that by just adding the disabled ones to a vector), that's why I was trying to add the QFrame.

                  So in order to add a QFrame and add the buttons to it I shouldn't need a layout at all? That's where I was getting confused. I'll try adding the buttons to the QFrame directly and let you know how it turns out :)

                  mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by
                  #10

                  @anarelle
                  Hi
                  Ah, so its only currentTile, previousTile you change image on so no loop.
                  Yes, you can also add buttons to a QFrame without a layout.
                  Its only required to use a layout if size of container changes and you wants its sub widgets to adjust to new size.
                  For your use case (disable all with parent/container) a layout is not needed.

                  A 1 Reply Last reply
                  0
                  • mrjjM mrjj

                    @anarelle
                    Hi
                    Ah, so its only currentTile, previousTile you change image on so no loop.
                    Yes, you can also add buttons to a QFrame without a layout.
                    Its only required to use a layout if size of container changes and you wants its sub widgets to adjust to new size.
                    For your use case (disable all with parent/container) a layout is not needed.

                    A Offline
                    A Offline
                    anarelle
                    wrote on last edited by
                    #11

                    @mrjj Yup, it was definitely easier without a layout. I just added a QFrame using the designer, selected all my buttons and dragged them onto the QFrame, then called frame->setEnabled(false) and frame->setEnabled(true) when needed and that was it. My individual buttons state isn't affected every time the frame state changes.

                    Thanks so much for everyone's help!

                    mrjjM 1 Reply Last reply
                    1
                    • A anarelle

                      @mrjj Yup, it was definitely easier without a layout. I just added a QFrame using the designer, selected all my buttons and dragged them onto the QFrame, then called frame->setEnabled(false) and frame->setEnabled(true) when needed and that was it. My individual buttons state isn't affected every time the frame state changes.

                      Thanks so much for everyone's help!

                      mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by
                      #12

                      @anarelle
                      Hi if issue is resolved, please mark the post Solved.

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved