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. Selecting QTreeView Switches Focus on Default QButton
Forum Updated to NodeBB v4.3 + New Features

Selecting QTreeView Switches Focus on Default QButton

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 3 Posters 1.0k Views 1 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.
  • Axel SpoerlA Offline
    Axel SpoerlA Offline
    Axel Spoerl
    Moderators
    wrote on last edited by
    #2

    Which Qt Version are you running, and which OS is the one that works without switching the default button?

    Software Engineer
    The Qt Company, Oslo

    G 1 Reply Last reply
    0
    • Axel SpoerlA Axel Spoerl

      Which Qt Version are you running, and which OS is the one that works without switching the default button?

      G Offline
      G Offline
      gsephelec
      wrote on last edited by
      #3

      @Axel-Spoerl

      Qt 6.6.0 (Clang 13.0 (Apple), arm64)

      I can't verify at this time, but I don't think the same thing happens when I run the same code but on Windows.

      I tried adding the following code:

      assetSelectTree->setFocusPolicy(Qt::NoFocus);
      

      and this seems to resolve what I'm seeing, but I'm not sure if it's the correct way to do it?

      Axel SpoerlA 1 Reply Last reply
      0
      • G gsephelec

        @Axel-Spoerl

        Qt 6.6.0 (Clang 13.0 (Apple), arm64)

        I can't verify at this time, but I don't think the same thing happens when I run the same code but on Windows.

        I tried adding the following code:

        assetSelectTree->setFocusPolicy(Qt::NoFocus);
        

        and this seems to resolve what I'm seeing, but I'm not sure if it's the correct way to do it?

        Axel SpoerlA Offline
        Axel SpoerlA Offline
        Axel Spoerl
        Moderators
        wrote on last edited by Axel Spoerl
        #4

        @gsephelec
        Qt::NoFocuscertainly helps, unless you need the tree to acquire focus at some point.
        MacOS treats buttons differently from other OSes at times, e.g. in a QDialogButtonBox. But bouncing from OK to Cancel sounds wrong to me. Unless related to application code, it could be a bug in Qt. However, I can't reproduce it on the spot.
        A recent focus chain fix related to macOS has landed in 6.6, so you can't be affected from the bug anymore.
        Can you isolate the issue in a minimal, compilable reproducer?

        Software Engineer
        The Qt Company, Oslo

        G 2 Replies Last reply
        0
        • Axel SpoerlA Axel Spoerl

          @gsephelec
          Qt::NoFocuscertainly helps, unless you need the tree to acquire focus at some point.
          MacOS treats buttons differently from other OSes at times, e.g. in a QDialogButtonBox. But bouncing from OK to Cancel sounds wrong to me. Unless related to application code, it could be a bug in Qt. However, I can't reproduce it on the spot.
          A recent focus chain fix related to macOS has landed in 6.6, so you can't be affected from the bug anymore.
          Can you isolate the issue in a minimal, compilable reproducer?

          G Offline
          G Offline
          gsephelec
          wrote on last edited by
          #5

          @Axel-Spoerl

          Sure thing, I've uploaded a completely minimal project that recreates the issue here:

          https://github.com/george-sephton/QTreeView_Test

          1 Reply Last reply
          0
          • Axel SpoerlA Axel Spoerl

            @gsephelec
            Qt::NoFocuscertainly helps, unless you need the tree to acquire focus at some point.
            MacOS treats buttons differently from other OSes at times, e.g. in a QDialogButtonBox. But bouncing from OK to Cancel sounds wrong to me. Unless related to application code, it could be a bug in Qt. However, I can't reproduce it on the spot.
            A recent focus chain fix related to macOS has landed in 6.6, so you can't be affected from the bug anymore.
            Can you isolate the issue in a minimal, compilable reproducer?

            G Offline
            G Offline
            gsephelec
            wrote on last edited by
            #6

            @Axel-Spoerl

            I noticed other implementions of QDialog have similar functionality, eg, if a textbox is selected, the default button swicthes from Ok to Cancel, despite Ok being the default button.

            Could you reproduce the issue with the code I posted?

            Thanks

            JonBJ Axel SpoerlA 2 Replies Last reply
            0
            • G gsephelec

              @Axel-Spoerl

              I noticed other implementions of QDialog have similar functionality, eg, if a textbox is selected, the default button swicthes from Ok to Cancel, despite Ok being the default button.

              Could you reproduce the issue with the code I posted?

              Thanks

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #7

              @gsephelec
              I'm throwing this thought in. No testing, and I don't have Mac anyway.

              I note that the the cancelButton is the first button you add to the QDialogButtonBox. I don't know why or whether this is desired/intended, but my suspicion is that it resets/selects the first button? Try swapping the order of your cancelButton/okButton, does it now select the okButton?

              G 1 Reply Last reply
              0
              • JonBJ JonB

                @gsephelec
                I'm throwing this thought in. No testing, and I don't have Mac anyway.

                I note that the the cancelButton is the first button you add to the QDialogButtonBox. I don't know why or whether this is desired/intended, but my suspicion is that it resets/selects the first button? Try swapping the order of your cancelButton/okButton, does it now select the okButton?

                G Offline
                G Offline
                gsephelec
                wrote on last edited by
                #8

                @JonB

                It seems to make no difference regardless of the order the buttons are added to the QDialogButtonBox unfortunately.

                1 Reply Last reply
                0
                • G gsephelec

                  @Axel-Spoerl

                  I noticed other implementions of QDialog have similar functionality, eg, if a textbox is selected, the default button swicthes from Ok to Cancel, despite Ok being the default button.

                  Could you reproduce the issue with the code I posted?

                  Thanks

                  Axel SpoerlA Offline
                  Axel SpoerlA Offline
                  Axel Spoerl
                  Moderators
                  wrote on last edited by
                  #9

                  @gsephelec
                  I don't download reproducer code from external sources.
                  If you want me to reproduce, the code has to be so minimal that you can post it here.

                  Software Engineer
                  The Qt Company, Oslo

                  G 1 Reply Last reply
                  0
                  • Axel SpoerlA Axel Spoerl

                    @gsephelec
                    I don't download reproducer code from external sources.
                    If you want me to reproduce, the code has to be so minimal that you can post it here.

                    G Offline
                    G Offline
                    gsephelec
                    wrote on last edited by
                    #10

                    @Axel-Spoerl

                    See code here:

                    main.cpp

                    #include "mainwindow.h"
                    #include <QApplication>
                    
                    int main(int argc, char *argv[])
                    {
                        QApplication a(argc, argv);
                        MainWindow w;
                        w.show();
                        return a.exec();
                    }
                    

                    mainwindow.cpp

                    #include "mainwindow.h"
                    #include "assetDialog.h"
                    
                    MainWindow::MainWindow(QWidget *parent)
                        : QMainWindow(parent)
                    {
                        assetAssetSelector dialog(this);
                        dialog.exec();
                    }
                    
                    MainWindow::~MainWindow()
                    {
                    }
                    

                    mainwindow.h

                    #ifndef MAINWINDOW_H
                    #define MAINWINDOW_H
                    
                    #include <QMainWindow>
                    
                    #include <QtWidgets>
                    #include <QTreeView>
                    
                    
                    QT_BEGIN_NAMESPACE
                    namespace Ui {
                    class MainWindow;
                    }
                    QT_END_NAMESPACE
                    
                    class MainWindow : public QMainWindow
                    {
                        Q_OBJECT
                    
                    public:
                        MainWindow(QWidget *parent = nullptr);
                        ~MainWindow();
                    
                    private:
                        Ui::MainWindow *ui;
                    
                        QLabel *assetSelectLabel;
                        QTreeView *assetSelectTree;
                        QDialogButtonBox *buttonBox;
                        QPushButton *okButton;
                        QPushButton *cancelButton;
                    
                        QStandardItemModel *assetSelectItemModel;
                    };
                    #endif // MAINWINDOW_H
                    

                    assetDialog.cpp

                    #include "assetDialog.h"
                    
                    assetAssetSelector::assetAssetSelector(QWidget *parent)
                        : QDialog(parent)
                    {
                        assetSelectLabel = new QLabel("Test");
                    
                        assetSelectTree = new QTreeView();
                        assetSelectTree->setFixedSize(260, 360);
                        assetSelectTree->setHeaderHidden(true);
                        assetSelectTree->setDragEnabled(false);
                        assetSelectTree->setEditTriggers(QAbstractItemView::NoEditTriggers);
                    
                        assetSelectItemModel = new QStandardItemModel(this);
                    
                        // Data would usually be added here
                    
                        assetSelectTree->setModel(assetSelectItemModel);
                        assetSelectTree->setCurrentIndex(assetSelectItemModel->invisibleRootItem()->index());
                        assetSelectTree->expandAll();
                    
                        okButton = new QPushButton(QString("&OK"));
                        okButton->setDefault(true);
                    
                        cancelButton = new QPushButton(QString("&Cancel"));
                    
                        buttonBox = new QDialogButtonBox(Qt::Horizontal);
                        buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole);
                        buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole);
                    
                        QVBoxLayout *assetSelectLayout = new QVBoxLayout;
                        assetSelectLayout->addWidget(assetSelectLabel);
                        assetSelectLayout->addWidget(assetSelectTree);
                    
                        QGridLayout *mainLayout = new QGridLayout;
                        mainLayout->setSizeConstraint(QLayout::SetFixedSize);
                        mainLayout->addLayout(assetSelectLayout, 0, 0);
                        mainLayout->addWidget(buttonBox, 1, 0);
                    
                        setLayout(mainLayout);
                    
                        connect(buttonBox, &QDialogButtonBox::accepted, this, &assetAssetSelector::slotAccept);
                        connect(buttonBox, &QDialogButtonBox::rejected, this, &assetAssetSelector::slotReject);
                    }
                    
                    void assetAssetSelector::slotAccept()
                    {
                        /* Accept the dialog */
                        accept();
                    }
                    
                    void assetAssetSelector::slotReject()
                    {
                        /* Reject the dialog */
                        reject();
                    }
                    

                    assetDialog.h

                    #ifndef ASSETDIALOG_H
                    #define ASSETDIALOG_H
                    #pragma once
                    
                    #include "mainWindow.h"
                    
                    #include <QDialog>
                    #include <QtWidgets>
                    #include <QTreeView>
                    
                    #include <string>
                    
                    QT_BEGIN_NAMESPACE
                    class QLabel;
                    class QLineEdit;
                    class QComboBox;
                    //class QCheckBox;
                    
                    class QDialogButtonBox;
                    class QPushButton;
                    QT_END_NAMESPACE
                    
                    class assetAssetSelector : public QDialog
                    {
                        Q_OBJECT
                    
                    public:
                        assetAssetSelector(QWidget *parent = nullptr);
                    
                    protected slots:
                        void slotAccept();
                        void slotReject();
                    
                    private:
                        QLabel *assetSelectLabel;
                        QTreeView *assetSelectTree;
                        QDialogButtonBox *buttonBox;
                        QPushButton *okButton;
                        QPushButton *cancelButton;
                    
                        QStandardItemModel *assetSelectItemModel;
                    };
                    
                    #endif // ASSETDIALOG_H
                    

                    This repoduces the error on Macbook Pro Nov 2023 M3 Pro, Qt 6.6.0 (Clang 13.0 (Apple), arm64).

                    Thanks

                    Axel SpoerlA 1 Reply Last reply
                    0
                    • G gsephelec

                      @Axel-Spoerl

                      See code here:

                      main.cpp

                      #include "mainwindow.h"
                      #include <QApplication>
                      
                      int main(int argc, char *argv[])
                      {
                          QApplication a(argc, argv);
                          MainWindow w;
                          w.show();
                          return a.exec();
                      }
                      

                      mainwindow.cpp

                      #include "mainwindow.h"
                      #include "assetDialog.h"
                      
                      MainWindow::MainWindow(QWidget *parent)
                          : QMainWindow(parent)
                      {
                          assetAssetSelector dialog(this);
                          dialog.exec();
                      }
                      
                      MainWindow::~MainWindow()
                      {
                      }
                      

                      mainwindow.h

                      #ifndef MAINWINDOW_H
                      #define MAINWINDOW_H
                      
                      #include <QMainWindow>
                      
                      #include <QtWidgets>
                      #include <QTreeView>
                      
                      
                      QT_BEGIN_NAMESPACE
                      namespace Ui {
                      class MainWindow;
                      }
                      QT_END_NAMESPACE
                      
                      class MainWindow : public QMainWindow
                      {
                          Q_OBJECT
                      
                      public:
                          MainWindow(QWidget *parent = nullptr);
                          ~MainWindow();
                      
                      private:
                          Ui::MainWindow *ui;
                      
                          QLabel *assetSelectLabel;
                          QTreeView *assetSelectTree;
                          QDialogButtonBox *buttonBox;
                          QPushButton *okButton;
                          QPushButton *cancelButton;
                      
                          QStandardItemModel *assetSelectItemModel;
                      };
                      #endif // MAINWINDOW_H
                      

                      assetDialog.cpp

                      #include "assetDialog.h"
                      
                      assetAssetSelector::assetAssetSelector(QWidget *parent)
                          : QDialog(parent)
                      {
                          assetSelectLabel = new QLabel("Test");
                      
                          assetSelectTree = new QTreeView();
                          assetSelectTree->setFixedSize(260, 360);
                          assetSelectTree->setHeaderHidden(true);
                          assetSelectTree->setDragEnabled(false);
                          assetSelectTree->setEditTriggers(QAbstractItemView::NoEditTriggers);
                      
                          assetSelectItemModel = new QStandardItemModel(this);
                      
                          // Data would usually be added here
                      
                          assetSelectTree->setModel(assetSelectItemModel);
                          assetSelectTree->setCurrentIndex(assetSelectItemModel->invisibleRootItem()->index());
                          assetSelectTree->expandAll();
                      
                          okButton = new QPushButton(QString("&OK"));
                          okButton->setDefault(true);
                      
                          cancelButton = new QPushButton(QString("&Cancel"));
                      
                          buttonBox = new QDialogButtonBox(Qt::Horizontal);
                          buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole);
                          buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole);
                      
                          QVBoxLayout *assetSelectLayout = new QVBoxLayout;
                          assetSelectLayout->addWidget(assetSelectLabel);
                          assetSelectLayout->addWidget(assetSelectTree);
                      
                          QGridLayout *mainLayout = new QGridLayout;
                          mainLayout->setSizeConstraint(QLayout::SetFixedSize);
                          mainLayout->addLayout(assetSelectLayout, 0, 0);
                          mainLayout->addWidget(buttonBox, 1, 0);
                      
                          setLayout(mainLayout);
                      
                          connect(buttonBox, &QDialogButtonBox::accepted, this, &assetAssetSelector::slotAccept);
                          connect(buttonBox, &QDialogButtonBox::rejected, this, &assetAssetSelector::slotReject);
                      }
                      
                      void assetAssetSelector::slotAccept()
                      {
                          /* Accept the dialog */
                          accept();
                      }
                      
                      void assetAssetSelector::slotReject()
                      {
                          /* Reject the dialog */
                          reject();
                      }
                      

                      assetDialog.h

                      #ifndef ASSETDIALOG_H
                      #define ASSETDIALOG_H
                      #pragma once
                      
                      #include "mainWindow.h"
                      
                      #include <QDialog>
                      #include <QtWidgets>
                      #include <QTreeView>
                      
                      #include <string>
                      
                      QT_BEGIN_NAMESPACE
                      class QLabel;
                      class QLineEdit;
                      class QComboBox;
                      //class QCheckBox;
                      
                      class QDialogButtonBox;
                      class QPushButton;
                      QT_END_NAMESPACE
                      
                      class assetAssetSelector : public QDialog
                      {
                          Q_OBJECT
                      
                      public:
                          assetAssetSelector(QWidget *parent = nullptr);
                      
                      protected slots:
                          void slotAccept();
                          void slotReject();
                      
                      private:
                          QLabel *assetSelectLabel;
                          QTreeView *assetSelectTree;
                          QDialogButtonBox *buttonBox;
                          QPushButton *okButton;
                          QPushButton *cancelButton;
                      
                          QStandardItemModel *assetSelectItemModel;
                      };
                      
                      #endif // ASSETDIALOG_H
                      

                      This repoduces the error on Macbook Pro Nov 2023 M3 Pro, Qt 6.6.0 (Clang 13.0 (Apple), arm64).

                      Thanks

                      Axel SpoerlA Offline
                      Axel SpoerlA Offline
                      Axel Spoerl
                      Moderators
                      wrote on last edited by
                      #11

                      @gsephelec
                      Sorry for taking so long.

                      The setVisible()override of QDialogchecks, if there is a QPushButtonat the next position in the focus chain. If it finds one, it sets it as a default button. That matches almost all use cases. But it can get in the way of a QDialogButtonBoxinside a QDialog. In your case, the cancel button is next in the focus chain. Therefore it wins the prize and becomes default.

                      There is a simple workaround:
                      Define void setVisible(bool visible) override;in the (new) protectedsection of assetDialog.hand implement it as follows:

                      void assetAssetSelector::setVisible(bool visible)
                      {
                          QDialog::setVisible(visible);
                          okButton->setDefault(true);
                      }
                      

                      It's a bit hacky, but it does the job.

                      You can file a bugreport if you want - you have a perfect reproducer.
                      I can't promise if we will actually fix it. I somehow feel, that a fix in Qt would break a lot of other stuff.

                      Software Engineer
                      The Qt Company, Oslo

                      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