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?
Forum Updated to NodeBB v4.3 + New Features

Moving all my buttons to a frame?

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 5.0k 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.
  • mrjjM Offline
    mrjjM Offline
    mrjj
    Lifetime Qt Champion
    wrote on last edited by
    #2

    Hi
    You say you added
    QGridLayout* layout();
    to the .h file but that would be a function returning a QGridLayout pointer.
    did you mean
    QGridLayout* layout;
    with
    layout = new QGridLayout()
    ?

    Anyway,
    no need to add layout from code.
    On the ui->frame, in Designer, place one button on the frame. Right click outside
    button and select a layout. Then delete button. Frame will keep its layout.
    However, the one should think that ui->frame->layout() would
    be the way to address the layout but Creator do add
    a direct variable. so its ui->verticalLayout or similar.
    alt text

    So now from code simply add to this layout.

    Im not sure with the errors as you are not showing the full source.
    "'btn01' was not declared in this scope" means it dont know the button.
    maybe its ui->btn01 but its hard to guess at.

    1 Reply Last reply
    5
    • 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