我的解决方案是第二次更新
我写了一个类,它本质上是一个无限循环,它对网络事件作出反应。这在控制台应用程序中运行良好
我现在试图在Qt GUI应用程序中使用所述类。该窗口只包含一个QPlainTextEdit(以及一个尚未使用的QLineEdit),我希望我的类能够在控制台上输出它通常输出的内容。
为此,我创建了一个回调函数(在bot类中称为outputLine
),调用plainTextEdit.appendPlainText
并将其提供给我的类,以便使用boost::function
和boost::bind
使其发挥作用。
当在此处调用回调函数时(bot类源文件)发生访问冲突:
char outputData[MAXDATASIZE];
iResult = recv(s, receive_buf, MAXDATASIZE, 0);
if (iResult > 0){
numbytes = iResult;
receive_buf[numbytes]='\0';
sprintf(outputData, "%s: <<< %s", time_now(), receive_buf);
outputLine(std::string(outputData));
有趣的是,这不会导致访问冲突:
char temp[100];
sprintf(temp, "test %i", someInteger);
outputLine(temp);
如果我注释掉appendPlainText(t)
行(参见下一个代码块),可以防止访问冲突,如果我这样做,一切正常(我通过检查机器人连接到的IRC服务器确认了这一点) :它加入频道并回答我的命令。)
以下是Qt源文件中的相关代码:
void QtTigerAutomaton::outputLine(std::string t){
ui.plainTextEdit->appendPlainText(t.c_str());
}
QtTigerAutomaton::QtTigerAutomaton(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
bot.setupBot("NICK somenick\r\n", "USER guest host server :some name\r\n",
boost::bind(&QtTigerAutomaton::outputLine, this, _1));
}
void QtTigerAutomaton::onConnectClick(){
botThread = new boost::thread(boost::bind(&IrcBot::start, &bot));
}
这是来自bot类的(希望)相关代码:
头文件:
typedef boost::function<void (std::string)> callbacktype;
/* ... */
callbacktype outputLine; //outputLine is assigned in setupBot
导致此访问冲突的原因是什么?如何阻止它?
PS:关于如何在Qt中显示机器人类输出的更好解决方案当然也非常受欢迎。我的目标是能够使用其使用我之前使用的控制台应用程序格式的GUI发送我的机器人命令。
更新
感谢答案,我现在认为问题是QWidgets等不是线程安全的,因此我将我的机器人转换为QObject,现在正尝试使用信号/插槽机制,如下所示:
在QtTigerAutomaton的构造函数中,我添加了
connect(&bot, SIGNAL(bot.outputSignal(const QString)), this,
SLOT(onOutputNeeded(const QString)));`
我意识到我可以直接使用ui.plainTextEdit->appendPlainText(const QString)
,但我希望能够更好地控制调试目的。
更相关的代码:
/* IrcBot.h */
public:
void testLine(){
emit outputSignal("testing");
};
signals:
void outputSignal(const QString);
然而,调用bot.testLine()
什么都不做。我错误地使用了连接功能,或者我的错误是什么?
更新
connect语句的正确语法是
connect(&bot, SIGNAL(outputSignal(const QString)), this, SLOT(onOutputNeeded(const QString)));
它现在似乎确实有效。
问题的解决方案确实是使用信号/插槽机制,这显然比回调函数更优雅,它确实有效。谢谢大家的帮助!
这是一步一步:
将我的IrcBot类转换为QObject类并添加了要发出的信号:
#include <qobject.h>
class IrcBot : public QObject
{
Q_OBJECT
/* ... */
signals:
void outputSignal(const QString);
像这样连接信号:
connect(&bot, SIGNAL(outputSignal(const QString)), ui.plainTextEdit,
SLOT(appendPlainText(const QString)));
每当产生一些输出时,发出信号如下:
emit outputSignal("some text"); //or various ways to generate output QStrings
现在,没有发生访问冲突,文本显示在我希望的plainTextEdit中。
PS:有没有办法将我的问题标记为现在的答案?由于我不能回答我自己的问题,我不知道如何:x我是新来的。