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. Using QFileDialog in Custom Delegate displayed on the wrong screen

Using QFileDialog in Custom Delegate displayed on the wrong screen

Scheduled Pinned Locked Moved Unsolved General and Desktop
9 Posts 2 Posters 835 Views
  • 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.
  • S Offline
    S Offline
    sandro4912
    wrote on last edited by aha_1980
    #1

    I have a app were i want to edit a displayed picture in a QTableView. To achieve the edit i used a custom delegate for that row. Here is the code:

    #include "picturedelegate.h"
    
    #include <QLabel>
    #include <QBuffer>
    #include <QFileDialog>
    #include <QStandardPaths>
    
    PictureDelegate::PictureDelegate(QObject *parent)
        :QStyledItemDelegate{ parent }
    {
    }
    
    QWidget *PictureDelegate::createEditor(
            QWidget *parent, const QStyleOptionViewItem &option,
            const QModelIndex &index) const
    {
        auto editor = new QFileDialog{ parent };
        editor->setNameFilter(tr("Images (*.png)"));
        auto startDir = QStandardPaths::standardLocations(
                    QStandardPaths::DesktopLocation);
        editor->setDirectory(startDir[0]);
        editor->setFileMode(QFileDialog::ExistingFile);
    
        return editor;
    }
    
    void PictureDelegate::setModelData(
            QWidget *editor, QAbstractItemModel *model,
            const QModelIndex &index) const
    {
        auto fileDialog = static_cast<QFileDialog *>(editor);
    
        QStringList fileNames;
        fileNames = fileDialog->selectedFiles();
    
        if(!fileNames.isEmpty()) {
            QPixmap pixmap;
            pixmap.load(fileNames[0]);
    
            QByteArray bArray;
            QBuffer buffer(&bArray);
            buffer.open(QIODevice::WriteOnly);
            pixmap.save(&buffer, "PNG");
    
            model->setData(index, bArray, Qt::EditRole);
        }
    }
    
    

    Everything seems to work i can update pictures into my model.

    The only issue if have is that if i click on the picture in the table the FileDialog does not spawn near my application.

    I have the appilcation on my primary screen and click in the table.
    The File Dialog shows up on the other screen far far away.

    What could be the cause. Ist it possible to spawn it over the selected element in the table?

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What version if Qt are you using ?
      What OS are you running ?
      If Linux, what desktop environment are you using ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      2
      • S Offline
        S Offline
        sandro4912
        wrote on last edited by
        #3

        QT 5.12.4
        KDE Neon
        KDE Plasma

        1 Reply Last reply
        0
        • S Offline
          S Offline
          sandro4912
          wrote on last edited by
          #4

          It indeed seems to be an OS Issue. I run the same application in an windows 10 environment and there it perfectly fine displays the dialog over the view i just clicked.

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            You are likely correct.

            What version of Neon/Plasma are you running ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            1
            • S Offline
              S Offline
              sandro4912
              wrote on last edited by
              #6

              KDE neon User Edition 5.16

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                Can you provide a minimal compilable example that triggers this ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                1
                • S Offline
                  S Offline
                  sandro4912
                  wrote on last edited by
                  #8

                  I tryed to strip down my program to the Issue. Here is the code:

                  main.h

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

                  mainwindow.h

                  #ifndef MAINWINDOW_H
                  #define MAINWINDOW_H
                  
                  #include <QMainWindow>
                  
                  class QuestionModel;
                  class QTableView;
                  class PictureDelegate;
                  
                  class MainWindow : public QMainWindow
                  {
                      Q_OBJECT
                  public:
                      MainWindow();
                  
                  private:
                      QuestionModel *mQuestionModel;
                      PictureDelegate *mPictureDelegate;
                      QTableView *mQuestionsView{};
                  };
                  
                  #endif // MAINWINDOW_H
                  

                  mainwindow.cpp

                  #include "mainwindow.h"
                  
                  #include "questionmodel.h"
                  #include "picturedelegate.h"
                  
                  #include <QTableView>
                  #include <QGuiApplication>
                  #include <QScreen>
                  #include <QHeaderView>
                  #include <QTimer>
                  
                  MainWindow::MainWindow()
                      :mQuestionModel{ new QuestionModel },
                      mPictureDelegate{ new PictureDelegate }
                  {   
                      Question q;
                      mQuestionModel->addQuestion(q);
                  
                      setFixedSize(QGuiApplication::primaryScreen()->availableGeometry().size()
                                  * 0.6);
                  
                      mQuestionsView = new QTableView;
                      mQuestionsView->setModel(mQuestionModel);
                      mQuestionsView->setItemDelegateForColumn(1, mPictureDelegate);
                      mQuestionsView->setSizePolicy(
                                  QSizePolicy::Expanding, QSizePolicy::Preferred);
                      mQuestionsView->setWordWrap(true);
                  
                      QTimer::singleShot(10, this, [this]() {
                          mQuestionsView->verticalHeader()->setSectionResizeMode(
                                      QHeaderView::ResizeToContents);
                      }  );
                  
                      mQuestionsView->verticalHeader()
                              ->setSectionResizeMode(QHeaderView::ResizeToContents);
                  
                  
                      mQuestionsView->setColumnHidden(0, true);
                  
                      mQuestionsView->horizontalHeader()
                              ->setSectionResizeMode( 1, QHeaderView::Stretch );
                  
                      setCentralWidget(mQuestionsView);
                  }
                  

                  question.h

                  #ifndef QUESTION_H
                  #define QUESTION_H
                  
                  #include <QString>
                  
                  class Question
                  {
                  public:
                      Question(int id, QByteArray picture = QByteArray{})
                          : mId{id},
                            mPicture{picture}
                      {
                      }
                  
                      Question(QByteArray picture = QByteArray{})
                          :Question{-1, picture}
                      {
                      }
                  
                      int getId() const { return mId; }
                      void setId(int id) { mId = id; }
                  
                      QByteArray getPicture() const { return mPicture; }
                      void setPicture(const QByteArray &picture) { mPicture = picture; }
                  
                  private:
                      int mId{ -1 };
                      QByteArray mPicture;
                  };
                  
                  #endif // QUESTION_H
                  

                  questiondao.h

                  #ifndef QUESTIONDAO_H
                  #define QUESTIONDAO_H
                  
                  #include <QVector>
                  
                  #include <vector>
                  #include <memory>
                  
                  class QSqlDatabase;
                  class Question;
                  
                  class QuestionDao
                  {
                  public:
                      explicit QuestionDao(QSqlDatabase &database);
                      void init() const;
                  
                      void addQuestion(Question &question) const;
                      void updateQuestion(Question &question) const;
                  
                      std::unique_ptr<std::vector<std::unique_ptr<Question>>>
                      getAllQuestions() const;
                  
                  private:
                      QSqlDatabase &mDatabase;
                  };
                  
                  #endif // QUESTIONDAO_H
                  

                  questiondao.cpp

                  #include "questiondao.h"
                  
                  #include "question.h"
                  #include "databasemanager.h"
                  
                  #include <QSqlDatabase>
                  #include <QSqlQuery>
                  #include <QStringList>
                  #include <QVariant>
                  
                  QuestionDao::QuestionDao(QSqlDatabase &database)
                      :mDatabase{ database }
                  {
                  }
                  
                  void QuestionDao::init() const
                  {
                      if(!mDatabase.tables().contains("questions")){
                          QSqlQuery query{ mDatabase };
                          query.exec(
                              "CREATE TABLE questions ("
                              "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                              "picture BLOB)");
                          DatabaseManager::debugQuery(query);
                      }
                  }
                  
                  void QuestionDao::addQuestion(Question &question) const
                  {
                      QSqlQuery query{ mDatabase };
                  
                      query.prepare("INSERT INTO questions (picture) VALUES (:picture)");
                      query.bindValue(":picture", question.getPicture());
                      query.exec();
                      DatabaseManager::debugQuery(query);
                      question.setId(query.lastInsertId().toInt());
                  }
                  
                  void QuestionDao::updateQuestion(Question &question) const
                  {
                      QSqlQuery query{ mDatabase };
                  
                      if(!question.getPicture().isEmpty()) {
                          query.prepare("UPDATE questions SET "
                              "picture=:picture WHERE id=:id");
                  
                          query.bindValue(":id", question.getId());
                          query.bindValue(":picture", question.getPicture());
                  
                          query.exec();
                          DatabaseManager::debugQuery(query);
                      }
                  }
                  
                  std::unique_ptr<std::vector<std::unique_ptr<Question>>>
                  QuestionDao::getAllQuestions() const
                  {
                      QSqlQuery query{ mDatabase };
                      query.prepare("SELECT * FROM questions");
                      query.exec();
                      DatabaseManager::debugQuery(query);
                      auto list = std::make_unique<std::vector<std::unique_ptr<Question>>>();
                      while(query.next()) {
                  
                          auto id = query.value(0).toInt();
                  
                          QByteArray picture;
                          if(!query.value(1).isNull()) {
                              picture = query.value(1).toByteArray();
                          }
                  
                          auto question = std::make_unique<Question>(id, picture);
                  
                          list->push_back(std::move(question));
                      }
                      return list;
                  }
                  
                  

                  databasemanager.h

                  #ifndef DATABASEMANAGER_H
                  #define DATABASEMANAGER_H
                  
                  #include "questiondao.h"
                  
                  #include <QSqlDatabase>
                  
                  class QSqlError;
                  
                  class DatabaseManager
                  {
                  public:
                      static void debugQuery(const QSqlQuery& query);
                  
                      static DatabaseManager &instance();
                      ~DatabaseManager();
                  
                      DatabaseManager (const DatabaseManager &) = delete;
                      DatabaseManager (DatabaseManager &&) = delete;
                      DatabaseManager& operator=(const DatabaseManager &) = delete;
                      DatabaseManager& operator=(DatabaseManager &&) = delete;
                  
                  protected:
                      DatabaseManager(const QString &database_filename = default_filename);
                  
                  private:
                      static constexpr auto default_filename = "quiz.db";
                  
                      QString createPath(const QString &database_filename);
                  
                      QSqlDatabase *mDatabase;
                  
                  public:
                      const QuestionDao questionDao;
                  };
                  
                  #endif // DATABASEMANAGER_H
                  
                  
                  #include "databasemanager.h"
                  
                  #include <QDir>
                  #include <QDebug>
                  #include <QFile>
                  #include <QSqlError>
                  #include <QSqlQuery>
                  #include <QStandardPaths>
                  
                  void DatabaseManager::debugQuery(const QSqlQuery &query)
                  {
                      if (query.lastError().type() == QSqlError::ErrorType::NoError) {
                          qDebug() << "Query OK:"  << query.lastQuery();
                          qDebug() << "------";
                      }
                      else {
                          qWarning() << "Query KO:" << query.lastError().text();
                          qWarning() << "Query text:" << query.lastQuery();
                          qWarning() << "------";
                      }
                  }
                  
                  DatabaseManager &DatabaseManager::instance()
                  {
                      static DatabaseManager singleton;
                      return singleton;
                  }
                  
                  DatabaseManager::~DatabaseManager()
                  {
                      mDatabase->close();
                      delete mDatabase;
                  }
                  
                  DatabaseManager::DatabaseManager(const QString &database_filename)
                      :mDatabase{ new QSqlDatabase{ QSqlDatabase::addDatabase("QSQLITE") } },
                        questionDao{ *mDatabase }
                  {
                      mDatabase->setDatabaseName(createPath(database_filename));
                      mDatabase->open();
                  
                      questionDao.init();
                  }
                  
                  QString DatabaseManager::createPath(const QString &database_filename)
                  {
                      QString path{ QStandardPaths::writableLocation(
                                       QStandardPaths::StandardLocation::DesktopLocation) };
                      qDebug() << path;
                      path.append(QDir::separator()).append(database_filename);
                      return QDir::toNativeSeparators(path);
                  }
                  
                  

                  questionmodel.h

                  #ifndef QUESTIONMODEL_H
                  #define QUESTIONMODEL_H
                  
                  #include "question.h"
                  
                  #include <QAbstractTableModel>
                  #include <QVector>
                  
                  #include <memory>
                  #include <vector>
                  
                  class DatabaseManager;
                  
                  class QuestionModel : public QAbstractTableModel
                  {
                      Q_OBJECT
                  public:
                      explicit QuestionModel(QObject *parent = nullptr);
                  
                      int rowCount(const QModelIndex &parent = QModelIndex()) const override;
                      int columnCount(const QModelIndex &parent) const override;
                      QVariant data(const QModelIndex &index, int role) const override;
                      bool setData(
                              const QModelIndex &index, const QVariant &value, int role) override;
                      QVariant headerData(
                              int section, Qt::Orientation orientation, int role) const override;
                      Qt::ItemFlags flags(const QModelIndex &index) const override;
                  
                  public slots:
                      void addQuestion(const Question &question);
                  
                  private:
                  
                      enum Column{
                          id,
                          picture
                      };
                  
                      bool isIndexValid(const QModelIndex& index) const;
                  
                      DatabaseManager &mDb;
                      std::unique_ptr<std::vector<std::unique_ptr<Question>>> mQuestions;
                  };
                  
                  #endif // QUESTIONMODEL_H
                  

                  questionmodel.cpp

                  #include "questionmodel.h"
                  
                  #include "databasemanager.h"
                  
                  #include <QModelIndex>
                  #include <QColor>
                  #include <QPixmap>
                  
                  #include <QFileDialog>
                  #include <QStandardPaths>
                  
                  QuestionModel::QuestionModel(QObject *parent)
                      :QAbstractTableModel{ parent },
                        mDb(DatabaseManager::instance()),
                        mQuestions(mDb.questionDao.getAllQuestions())
                  {
                  }
                  
                  int QuestionModel::rowCount(const QModelIndex & /*parent*/) const
                  {
                      return static_cast<int>(mQuestions->size());
                  }
                  
                  int QuestionModel::columnCount(const QModelIndex & /*parent*/) const
                  {
                      return 2;
                  }
                  
                  QVariant QuestionModel::data(const QModelIndex &index, int role) const
                  {
                      if (!isIndexValid(index)) {
                          return QVariant();
                      }
                  
                      const Question &question = *mQuestions->at(
                          static_cast<std::vector<std::unique_ptr<Question>>::size_type>(
                              index.row()));
                  
                      if (role == Qt::DisplayRole) {
                          if (index.column() == Column::id) {
                              return question.getId();
                          }
                      }
                  
                      if(index.column() == Column::picture) {
                  
                          QPixmap pixmap;
                          if(!question.getPicture().isNull()) {
                              pixmap.loadFromData(question.getPicture());
                              pixmap = pixmap.scaled(
                                  100, 100, Qt::IgnoreAspectRatio, Qt::FastTransformation);
                          }
                  
                          if (role == Qt::DecorationRole) {
                              return pixmap;
                          }
                          if (role == Qt::SizeHintRole) {
                              return pixmap.size();
                          }
                      }
                  
                      if (role == Qt::EditRole) {
                          if (index.column() == Column::picture) {
                              return question.getPicture();
                          }
                      }
                      return QVariant{};
                  }
                  
                  bool QuestionModel::setData(
                          const QModelIndex &index, const QVariant &value, int role)
                  {
                      if (value.toString().isNull()) {
                          return false;
                      }
                  
                      if (role == Qt::EditRole) {
                          auto column = index.column();
                  
                          Question &question = *mQuestions->at(
                              static_cast<std::vector<std::unique_ptr<Question>>::size_type>(
                                  index.row()));
                  
                          auto editAccepted{ false };
                          if (column == Column::picture) {
                              if(question.getPicture() != value.toByteArray()) {
                                  question.setPicture(value.toByteArray());
                                  editAccepted = true;
                              }
                          }
                  
                          if(editAccepted) {
                              mDb.questionDao.updateQuestion(question);
                              return true;
                          }
                      }
                      return false;
                  }
                  
                  QVariant QuestionModel::headerData(
                          int section, Qt::Orientation orientation, int role) const
                  {
                      if (role == Qt::DisplayRole) {
                          if( orientation == Qt::Horizontal) {
                              switch(section) {
                                  case Column::id:
                                      return tr("id");
                                  case Column::picture:
                                      return tr("Picture");
                              }
                          }
                      }
                      return QAbstractTableModel::headerData(section, orientation, role);
                  }
                  
                  Qt::ItemFlags QuestionModel::flags(const QModelIndex &index) const
                  {
                      auto column = index.column();
                  
                      if (column == Column::picture)
                      {
                          return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
                      }
                      return QAbstractTableModel::flags(index);
                  }
                  
                  void QuestionModel::addQuestion(const Question &question)
                  {
                      Question q = question;
                      mDb.questionDao.addQuestion(q);
                      mQuestions = mDb.questionDao.getAllQuestions();
                      emit layoutChanged();
                  }
                  
                  bool QuestionModel::isIndexValid(const QModelIndex &index) const
                  {
                      return index.row() >= 0 && index.row() <rowCount() && index.isValid();
                  }
                  
                  

                  picturedelegate.h

                  #ifndef PICTUREDELEGATE_H
                  #define PICTUREDELEGATE_H
                  
                  #include <QStyledItemDelegate>
                  
                  class PictureDelegate : public QStyledItemDelegate
                  {
                  public:
                      explicit PictureDelegate(QObject *parent = nullptr);
                  
                      QWidget *createEditor(
                              QWidget *parent, const QStyleOptionViewItem &option,
                              const QModelIndex &index) const override;
                  
                      void setModelData(
                              QWidget *editor, QAbstractItemModel *model,
                              const QModelIndex &index) const override;
                  };
                  
                  #endif // PICTUREDELEGATE_H
                  
                  

                  picturedelegate.cpp

                  #include "picturedelegate.h"
                  
                  #include <QLabel>
                  #include <QBuffer>
                  #include <QFileDialog>
                  #include <QStandardPaths>
                  
                  PictureDelegate::PictureDelegate(QObject *parent)
                      :QStyledItemDelegate{ parent }
                  {
                  }
                  
                  QWidget *PictureDelegate::createEditor(
                          QWidget *parent, const QStyleOptionViewItem & /*option*/,
                          const QModelIndex & /*index*/) const
                  {
                      auto editor = new QFileDialog{ parent };
                      editor->setNameFilter(tr("Images (*.png)"));
                      auto startDir = QStandardPaths::standardLocations(
                                  QStandardPaths::DesktopLocation);
                      editor->setDirectory(startDir[0]);
                      editor->setFileMode(QFileDialog::ExistingFile);
                  
                      return editor;
                  }
                  
                  void PictureDelegate::setModelData(
                          QWidget *editor, QAbstractItemModel *model,
                          const QModelIndex &index) const
                  {
                      auto fileDialog = qobject_cast<QFileDialog *>(editor);
                  
                      QStringList fileNames;
                      fileNames = fileDialog->selectedFiles();
                  
                      if(!fileNames.isEmpty()) {
                          QPixmap pixmap;
                          pixmap.load(fileNames[0]);
                  
                          QByteArray bArray;
                          QBuffer buffer(&bArray);
                          buffer.open(QIODevice::WriteOnly);
                          pixmap.save(&buffer, "PNG");
                  
                          model->setData(index, bArray, Qt::EditRole);
                      }
                  }
                  
                  

                  This creates a Database with an entry on a desktop location. On startup click into the empty field and the popup should show up.

                  In my environment my Primary Screen has the app running but the popup shows up on my second screen.

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    I would say, there might be some patches applied to the Qt version shipped with KDE Neon. If you use the distribution provided Qt which is 5.12.3 at this time, the dialog opens as expected on the same screen.

                    I would recommend taking a look at the bug report system to see if there's anything related.

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    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