[英]How can I emit a signal of another instance from _clicked() event?
可運行的項目在這里:在此處輸入鏈接描述
我真誠地很高興有您的詳細答案來解決這個問題,但我仍然對這個問題感到困惑:
案例一:把socket_session
的成員變量
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
SocketThread* socket_session;
private:
...
但這不是訪問setFlag
的解決方案,即使我像這樣更改了 `Form1::on_qpushButton__set_white_level_0_clicked()' 函數:
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
仍然沒有意義,因為form1
實例沒有從mainwindow
實例化的socket_thread
實例。 我認為有一個解決方案是創建另一個類,其中包含我想從主mainwindow
內部使用的所有實例,但我認為這不是一個好的解決方案,因為我正在使用線程並訪問包含所有實例的全局大實例類對於像我這樣的人來說,“共享”不是一個好主意。
#include <form1.h>
#include <ui_form1.h>
#include "socketthread.h"
Form1::Form1(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form1) {
ui->setupUi(this);
}
Form1::~Form1() {
delete ui;
}
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
我知道我對此缺乏了解,但是,我想做一些沒有人做的事情嗎......? 我認為每個人都希望清楚地分離所有對象及其方法,並通過信號或從交付的對象實例調用函數進行通信......
案例 2:...讓我先試試你建議如何實現...
我可以閱讀 C++ 代碼和整體結構,但我不知道為什么我必須為此而掙扎,所以請幫助我,親愛的 Guru。
在 socketthread.h 上:
class SocketThread : public QThread {
Q_OBJECT
public:
QTcpSocket *socket_session;
SocketThread();
~SocketThread(){}
bool connectToServer(QString, int);
void sendData(const char*, int, int);
void run(void);
private:
QString message;
volatile bool threadFlag;
signals:
void changedThreadFlag(void);
void changedMessageStr(void);
void setThreadFlag(bool);
void setMessageStr(QString);
private slots:
void setStr(QString);
void setFlag(bool);
void socketError(QAbstractSocket::SocketError);
};
它的實現是......
SocketThread::SocketThread() {
socket_session = NULL;
threadFlag = false;
message = "NULL";
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
}
...
void SocketThread::setStr(QString str) {
message = str;
}
void SocketThread::setFlag(bool flag) {
threadFlag = flag;
}
void SocketThread::run() {
while(true) {
if(threadFlag) {
QThread::msleep(100);
qDebug() << message;
} else
break;
}
qDebug() << "loop ended";
}
我有一個帶有按鈕的表單,我像這樣放置了一個 clicked() 插槽......
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
--how can I emit the signal of the one of socketthread from here??
}
現在,主窗口是這樣的:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
QString addr_server = "223.194.32.106";
int port = 11000;
SocketThread* socket_session = new SocketThread();
socket_session->connectToServer(addr_server, port);
ui->setupUi(this);
Form1* form1;
form1 = new Form1();
ui->stackedWidget_mainwindow->addWidget(form1);
ui->stackedWidget_mainwindow->setCurrentWidget(form1);
socket_session->run();
...
我只是想從 QPushbutton_clicked() 插槽內部發出 socketthread 的信號 setThreadFlag 。 一旦socket_session->run()
啟動,我需要通過從正在運行的線程中發出一個人的setThreadFlag()
單擊按鈕來更改threadFlag
。 而我只是卡在這里。
甚至有可能嗎? 還是我從一開始就做錯了?
我只是想從 QPushbutton_clicked() 插槽內部發出 socketthread 的信號 setThreadFlag 。
不需要信號——只需調用函數。
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
// --how can I emit the signal of the one of socketthread from here??
// E.g. this way:
socket_session->setThreadFlag(true);
}
為了使這成為可能,需要另一個修復:
socket_session
是 OP 公開代碼中的局部變量。
為了使其“持久”,它必須成為例如成員變量。
因此,必須更改構造函數MainWindow::MainWindow()
:
// Nope: SocketThread* socket_session = new SocketThread();
// Instead:
socket_session = new SocketThread();
和SocketThread* socket_session;
必須添加到class MainWindow
成員變量中。
要使其在Form1
可訪問,還必須將其傳遞給Form1
。 這可以通過例如使其成為Form1
的成員變量來完成,該變量也用構造函數參數初始化(或之后從MainWindow
設置)。
(我必須承認,我從未使用過 Qt UI builder QtDesigner,而是專門通過 C++ 代碼構建我所有的 UI。)
但是,現在,另一個修復是必要的:
volatile
不會使變量適合線程間通信。 (這是在 C++11 開始支持多線程之前的古代使用的。)
然而,這是錯誤的: volatile 對線程有用嗎?
一個適當的解決方法是使用std::atomic
代替:
// Wrong for interthread-com.
//volatile bool threadFlag;
// Correct:
std::atomic<bool> threadFlag; // #include <atomic> needed
僅供參考: SO:多線程程序卡在優化模式但在 -O0 中正常運行
最后,在SocketThread::SocketThread()
:
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
在這種情況下是沒有必要的。 SocketThread::setThreadFlag()
可以直接調用SocketThread::setFlag()
,甚至自己寫threadFlag
:
void setThreadFlag(bool flag) { threadFlag = flag; }
由於我(建議)使threadFlag
原子化,因此可以從任何線程訪問它而不會導致數據競爭。
更新:
OP更新問題后:
我只是想從 QPushbutton_clicked() 插槽內部發出 socketthread 的信號 setThreadFlag 。
按鈕(從 UI Form1
創建)也可以在MainWindow
連接(不使用Form1
任何方法):
QObject::connect(form1->button1, &QPushButton::clicked,
socket_session, &SocketThread::setThreadFlag,
Qt::QueuedConnection);
筆記:
關於form1->button1
,我不太確定。 我注意到 UI 生成的表單中的小部件可以通過這種方式訪問,但我不知道確切的細節(因為我自己從未使用過 Qt UI 構建器)。
我使用了QObject::connect()
的 Qt5 風格。 這是我無論如何都會推薦的。
Qt5 風格在編譯時驗證。 – C++ 類型檢查檢測到錯誤連接。
此外,可以使用任何具有匹配簽名的函數——不再需要顯式暴露插槽。
通過使用同樣受支持的 C++ lambda,甚至可以轉換不匹配的簽名或添加其他參數。
Qt:基於字符串和基於函子的連接之間的差異
可以連接不同線程的信號和槽。 我使用Qt::QueuedConnection
標記為線程間通信。
(但是,我大致記得 Qt 可能能夠自己檢測到它。請參閱文檔Qt::AutoConnection
這是默認設置。
進一步閱讀: Qt:信號和插槽
順便提一句。 使用 Qt 信號進行線程間通信將排除使SocketThread::threadFlag()
原子化的SocketThread::threadFlag()
。 它可以變成一個簡單的普通bool threadFlag;
反而。 在這種情況下,插槽SocketThread::setThreadFlag()
在QThread
的 Qt 事件循環中被QThread
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.