C++ 在主线程中创建QDialog

C++ 在主线程中创建QDialog,c++,qt,C++,Qt,我是Qt的新手,在创建新对话框时遇到问题。这是它的类别: class MyDialog : public QDialog, public Ui::ConnectToSource { public: MyDialog(QMainWindow *p_Parent = 0); void keyPressEvent(QKeyEvent* e); }; MyDialog::MyDialog(QMainWindow *p_Parent) : QDialog(p_Parent) {

我是Qt的新手,在创建新对话框时遇到问题。这是它的类别:

class MyDialog : public QDialog, public Ui::ConnectToSource
{
public:
    MyDialog(QMainWindow *p_Parent = 0);
    void keyPressEvent(QKeyEvent* e);
};

MyDialog::MyDialog(QMainWindow *p_Parent) : QDialog(p_Parent) {
    setupUi(this);
}
在另一个线程而不是主线程中,我正在执行以下操作:

m_Dialog = new MyDialog(parent);
但这意味着我不能在另一个线程中创建新的小部件。所以我试着:

void MyQObject::initialize_m_Dialog(QMainWindow* p) { //slot
    m_Dialog = new MyDialog(p);
}
...
QMetaObject::invokeMethod(this, "initialize_m_Dialog", Qt::BlockingQueuedConnection, Q_ARG(QMainWindow*, parent));
但我真的不确定我在做什么……:) 这件事让我一筹莫展


如何实现这一点?

我在下面的不同线程中创建了一个UI组件创建演示,
MyThread
启动后将发出信号。如果UI线程接收到信号,将创建并显示
对话框

神话阅读:

#include <QThread>
#include <QDebug>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject* parent = 0) :
        QThread(parent){}
protected:
    void run(){
        qDebug()<<"Current thread:"<<QThread::currentThread();
        emit somethingHappened();
    }
signals:
    void somethingHappened();
};
#include <QMainWindow>
#include <QDialog>

class MyDialog : public QDialog
{
public:
    MyDialog(QWidget *parent = 0) :
        QDialog(parent)
    { show(); }

    void keyPressEvent(QKeyEvent* /*e*/){
        close();
    }
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0) :
        QMainWindow(parent),
        mDialog(Q_NULLPTR)
    {
        qDebug()<<"Current thread:"<<QThread::currentThread();
        MyThread* myThread = new MyThread(this);
        connect(myThread, &MyThread::somethingHappened,
                this, &MainWindow::createDialog, Qt::QueuedConnection);
        myThread->start();
    }
private slots:
    void createDialog(){
        qDebug()<<"Current thread:"<<QThread::currentThread();
        if(mDialog == Q_NULLPTR)
            mDialog = new MyDialog(this);
    }
private:
    MyDialog* mDialog;
};
#包括
#包括
类MyThread:publicqthread
{
Q_对象
公众:
显式MyThread(QObject*parent=0):
QThread(父级){}
受保护的:
无效运行(){

qDebug()我在下面的不同线程中创建了一个UI组件创建的演示,
MyThread
启动后将发出一个信号。如果UI线程收到该信号,将创建并显示
对话框

神话阅读:

#include <QThread>
#include <QDebug>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject* parent = 0) :
        QThread(parent){}
protected:
    void run(){
        qDebug()<<"Current thread:"<<QThread::currentThread();
        emit somethingHappened();
    }
signals:
    void somethingHappened();
};
#include <QMainWindow>
#include <QDialog>

class MyDialog : public QDialog
{
public:
    MyDialog(QWidget *parent = 0) :
        QDialog(parent)
    { show(); }

    void keyPressEvent(QKeyEvent* /*e*/){
        close();
    }
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0) :
        QMainWindow(parent),
        mDialog(Q_NULLPTR)
    {
        qDebug()<<"Current thread:"<<QThread::currentThread();
        MyThread* myThread = new MyThread(this);
        connect(myThread, &MyThread::somethingHappened,
                this, &MainWindow::createDialog, Qt::QueuedConnection);
        myThread->start();
    }
private slots:
    void createDialog(){
        qDebug()<<"Current thread:"<<QThread::currentThread();
        if(mDialog == Q_NULLPTR)
            mDialog = new MyDialog(this);
    }
private:
    MyDialog* mDialog;
};
#包括
#包括
类MyThread:publicqthread
{
Q_对象
公众:
显式MyThread(QObject*parent=0):
QThread(父级){}
受保护的:
无效运行(){

qDebug()现有代码的设计已经过时。让我们从对话框开始修复它

Ui::
类不应该是公共基础。它们是一个实现细节,不应该暴露在对话框之外的任何地方。对话框是一个抽象:您可以对其执行一些操作。它们应该是方法,并且可以在内部访问
Ui::
对象。对话框也不应该依赖于任何特定对象父窗口的lar类型。如果对话框应与其他对象交互,则应发出信号,然后连接到主窗口等

为了演示它,假设对话框有一个
QLineEdit
元素。可以设置文本,并通知其他人文本中的更改。它的设计应如下所示:

class ConnectToSource : public QDialog {
  Q_OBJECT
public:
  ConnectToSource(QWidget *parent = {}) : QDialog(parent) {
    ui.setupUi(this);
    connect(ui.edit, &QLineEdit::textChanged,
            this, &ConnectToSource::textChanged); // forward the signal
  }
  Q_SLOT void setText(const QString & text) {
    ui.edit->setText(text);
  }
  QString text() const {
    return ui.edit->text();
  }
  Q_SIGNAL void textChanged(const QString &);
protected:
  void keyPressEvent(QKeyEvent *) override { ... }
private:
  Ui::ConnectToSource ui;
};  
现在,让我们看看如何从任何线程访问它。关键是发送一些代码在主线程中执行。有关详细信息,请参阅。这段代码(函子)应包含设置对话框所需的所有数据

然后:

//https://stackoverflow.com/a/21653558/1329652
模板
静态void postToThread(F&&fun,QThread*thread=qApp->thread());
无效设置对话框(主窗口*父窗口、常量字符串和文本){
postToThread([=]{//functor按值捕获父对象和文本
自动对话框=新的ConnectToSource(父级);
对话框->设置文本(文本);
连接(对话框,&ConnectToSource::textChanged,父窗口,&MainWindow::useText);
对话框->显示();
dialog->setAttribute(Qt::WA_DeleteOnClose);//不要泄漏对话框
});
}
setupDialog
函数是线程安全的,只要线程不超过父线程的寿命,就可以在任何线程中执行


请注意,上面的代码基本上是非阻塞的。函子被包装在事件中,并被传递到主线程的事件分派器,然后由该事件分派器执行函子。执行
setupDialog
的线程可能只会在主线程的事件队列的互斥对象上得到满足。该互斥对象仅偶尔被持有,时间非常长时间很短。

现有代码的设计已经过时。让我们从对话框开始修复它

Ui::
类不应该是公共基础。它们是一个实现细节,不应该暴露在对话框之外的任何地方。对话框是一个抽象:您可以对其执行一些操作。它们应该是方法,并且可以在内部访问
Ui::
对象。对话框也不应该依赖于任何特定对象父窗口的lar类型。如果对话框应与其他对象交互,则应发出信号,然后连接到主窗口等

为了演示它,假设对话框有一个
QLineEdit
元素。可以设置文本,并通知其他人文本中的更改。它的设计应如下所示:

class ConnectToSource : public QDialog {
  Q_OBJECT
public:
  ConnectToSource(QWidget *parent = {}) : QDialog(parent) {
    ui.setupUi(this);
    connect(ui.edit, &QLineEdit::textChanged,
            this, &ConnectToSource::textChanged); // forward the signal
  }
  Q_SLOT void setText(const QString & text) {
    ui.edit->setText(text);
  }
  QString text() const {
    return ui.edit->text();
  }
  Q_SIGNAL void textChanged(const QString &);
protected:
  void keyPressEvent(QKeyEvent *) override { ... }
private:
  Ui::ConnectToSource ui;
};  
现在,让我们看看如何从任何线程访问它。关键是发送一些代码在主线程中执行。有关详细信息,请参阅。这段代码(函子)应包含设置对话框所需的所有数据

然后:

//https://stackoverflow.com/a/21653558/1329652
模板
静态void postToThread(F&&fun,QThread*thread=qApp->thread());
无效设置对话框(主窗口*父窗口、常量字符串和文本){
postToThread([=]{//functor按值捕获父对象和文本
自动对话框=新的ConnectToSource(父级);
对话框->设置文本(文本);
连接(对话框,&ConnectToSource::textChanged,父窗口,&MainWindow::useText);
对话框->显示();
dialog->setAttribute(Qt::WA_DeleteOnClose);//不要泄漏对话框
});
}
setupDialog
函数是线程安全的,只要线程不超过父线程的寿命,就可以在任何线程中执行


请注意,上面的代码基本上是非阻塞的。函子被包装在事件中,并被传递到主线程的事件分派器,然后由该事件分派器执行函子。执行
setupDialog
的线程可能只会在主线程的事件队列的互斥对象上得到满足。该互斥对象仅偶尔被持有,时间非常长短时间。

消息是正确的,您不应该在另一个线程中创建GUI元素。请阅读以下内容:为什么要使用另一个线程?我真的不想…我收到一个大程序要修复,它是以这种方式发生的。嗯,您的设计很糟糕,大程序意味着什么?您可以声明
MyDialog
在主线程的类(父类本身)中,并触发其实例化,并使用子类发出的信号显示,您正在尝试使用c