2009-07-17 12 views
9

Tôi mới sử dụng QT và tôi đang học một số.QT + Cách gọi khe từ mã C++ tùy chỉnh đang chạy trong một luồng khác

Tôi muốn kích hoạt một khe có thể sửa đổi tiện ích GUI từ chuỗi C++ (Hiện tại là Qthread).

Đáng tiếc là tôi nhận được: ASSERTION không thành công tại: Q_ASSERT (qApp & & qApp-> thread() == QThread :: currentThread());

đây là một số mã:

(MAIN + lớp Thread)

class mythread : public QThread 
    { 
    public: 
     mythread(mywindow* win){this->w = win;}; 
     mywindow* w; 
     void run() 
     { 
      w->ui.textEdit->append("Hello");  //<--ASSERT FAIL 
      //I have also try to call a slots within mywindow which also fail. 
     }; 
    }; 

    int main(int argc, char *argv[]) 
    { 
     QApplication* a = new QApplication(argc, argv); 
     mywindow* w = new mywindow(); 

     w->show(); 
     mythread* thr = new mythread(w); 
     thr->start(); 

     return a->exec(); 
    } 

Window:

class mywindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    mywindow (QWidget *parent = 0, Qt::WFlags flags = 0); 
    ~mywindow(); 
    Ui::mywindow ui; 

private: 



public slots: 
    void newLog(QString &log); 
}; 

Vì vậy, tôi tò mò về cách cập nhật phần gui bởi mã trong một chủ đề khác nhau.

Cảm ơn bạn đã trợ giúp

Trả lời

6

Ngoài stribika's answer, tôi thường tìm thấy nó dễ dàng hơn để sử dụng kết nối tín hiệu/khe. Bạn có thể chỉ định rằng nó phải là một kết nối xếp hàng đợi khi bạn kết nối nó, để tránh các vấn đề với các tín hiệu của thread nằm trong ngữ cảnh của đối tượng sở hữu nó.

class mythread : public QThread 
{ 
signals: 
    void appendText(QString); 
public: 

    mythread(mywindow* win){this->w = win;}; 
    mywindow* w; 
    void run() 
    { 
     emit (appendText("Hello")); 
    }; 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication* a = new QApplication(argc, argv); 
    mywindow* w = new mywindow(); 

    w->show(); 
    mythread* thr = new mythread(w); 
    (void)connect(thr, SIGNAL(appendText(QString)), 
        w->ui.textEdit, SLOT(append(QString)), 
        Qt::QueuedConnection); // <-- This option is important! 
    thr->start(); 

    return a->exec(); 
} 
+3

Lớp huyền thoại cần chứa macro Q_OBJECT – CiscoIPPhone

4

Bạn cần sử dụng QMetaObject::invokeMethod. Ví dụ:

void MyThread::run() { 
    QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello")); 
} 

(Đoạn mã trên xuất phát từ đây: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)

+0

... và điều đó sai :) –

+0

@ MarcMutz-mmutz bạn cũng có thể giải thích điều gì sai với mã này không? Tôi nghi ngờ nó là macro SLOT, nhưng có thể là bạn đã có một số điểm khác ;-) – FourtyTwo

+0

'invokeMethod' chỉ lấy tên hàm (' '" setText "' '), không phải là kết quả của' SLOT'. –

2

Tôi không nghĩ bạn được phép gọi trực tiếp những thứ dẫn đến sự kiện sơn từ bất kỳ chủ đề nào khác ngoài chủ đề chính. Điều đó sẽ dẫn đến một vụ tai nạn.

Tôi nghĩ bạn có thể sử dụng vòng lặp sự kiện để gọi mọi thứ không đồng bộ sao cho chuỗi gui chính chọn lên và sau đó cập nhật từ chuỗi chính, đó là những gì cjhuitt gợi ý.

11

stribika nhận nó gần như ngay: right

QMetaObject::invokeMethod(textEdit, "append", Qt::QueuedConnection, 
          Q_ARG(QString, myString)); 

cjhuitt của, mặc dù: Bạn thường muốn khai báo một tín hiệu trên các chủ đề và kết nối nó với khe append(), để có được quản lý đối tượng suốt đời miễn phí (tốt, với giá của một thay đổi giao diện nhỏ). Trên một sidenote, lập luận thêm:

   Qt::QueuedConnection); // <-- This option is important! 

từ câu trả lời cjhuitt là không cần thiết nữa (đó là, trong Qt < = 4,1), vì connect() mặc định là Qt::AutoConnection mà bây giờ (Qt> = 4.2) không đúng sự điều và chuyển đổi giữa chế độ kết nối xếp hàng và trực tiếp dựa trên QThread::currentThread() và ái lực chủ của người nhận QObject tại thời điểm phát ra (thay cho mối quan hệ người gửi và người nhận khi kết nối).

+2

Tôi không biết rằng kết nối hiện đang ở thời gian phát ra ... điều này vẫn hoạt động với các đối tượng chuỗi, "sống" trong chuỗi được tạo, chứ không phải chuỗi được sinh ra khi QThread :: run được gọi? (Chúng tôi vừa có một cuộc tranh luận về điều này một vài tuần trước tại nơi làm việc, và quyết định rằng an toàn hơn để chỉ định tùy chọn QueuedConnection trong những trường hợp đó.) –

+1

Tôi đã sử dụng điều này để phát ra tín hiệu từ Chủ đề không phải là Qthreads. . Hoạt động tốt để gửi các sự kiện _to_ vòng lặp chính của Qt. Ngoài ra, không bao giờ phải chỉ định QueuedConnection với Qt 4.3 trở lên. – Macke

1

Điều gì sẽ xảy ra nếu mối quan hệ luồng của chúng tôi nói GUI, nhưng chúng tôi không nằm trong luồng GUI, cũng như trong QThread?

Ý của tôi là, một chuỗi không Qt (thông báo) gọi phương thức giao diện của QObject, trong đó chúng ta phát ra tín hiệu AutoConnected.Mối quan hệ Thread của QObject là Main thread, nhưng thủ tục này thực sự được gọi từ một thread khác. Qt sẽ làm gì ở đây?