I've got a WinForm running on my main thread and a while(true) loop running on a separate thread. Each loop of that while(true) creates a new System::String^ and I want to paste that String into a TextBox on my UI.
My file structure includes GUI.h, GUI.cpp, and Other.cpp.
GUI.h contains all the automatically created code for the main (and only) Form. It also has some Get, Set, and ButtonClick methods.
//GUI.h
#pragma once
#include <string>
#include <vector>
#include <cliext\vector>
#include <conio.h>
#include <list>
#include <iostream>
extern void BufferRecieveLoop();
namespace GUI_Example_Receive {
static bool loopFlag = true;
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;
/// <summary>
/// Summary for GUI
/// </summary>
public ref class GUI : public System::Windows::Forms::Form
{
public:
GUI(void)
{
InitializeComponent();
}
std::vector<std::string> CollectText();
void ContinueNormally(); // Object^);
void DisableAllTextboxes();
void EnableAllTextboxes();
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~GUI()
{
if (components)
{
delete components;
}
}
private:
//Labels
//GroupBoxes
//Buttons
//SaveFile
public:
//TextBoxes
System::Windows::Forms::TextBox^ consoleTextBox;
private:
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
void InitializeComponent(void)
{
//automatically made, lightly edited
}
#pragma endregion
public:
void SetConsoleTextBoxText(System::String^ input)
{
this->consoleTextBox->Text = input;
this->consoleTextBox->Refresh();
}
void ClearConsoleTextBoxText()
{
this->consoleTextBox->Clear();
}
delegate void MyDelegate(System::String ^ str);
void ClearAndSetConsoleTextBoxText(System::String ^ input)
{
/***************************************************
if (InvokeRequired)
{
this->BeginInvoke(gcnew MyDelegate(this, &ClearAndSetConsoleTextBoxText), { input });
}
***************************************************/
ClearConsoleTextBoxText();
SetConsoleTextBoxText(input);
}
System::Void startButton_Click(System::Object^ sender, System::EventArgs^ e)
{
loopFlag = true; //able to loop through ContinueNormally()
ContinueNormally(); //method in GUI.cpp
}
};
//https://social.msdn.microsoft.com/Forums/vstudio/en-US/4da834f0-d8f8-4abb-a655-ef9e99d51eb2/how-to-create-a-global-object-of-a-ref-class-type?forum=vcgeneral
ref struct Globals {
static GUI ^gui; //using Globals::gui everywhere to access the one Form
};
}
Gui.cpp contains code to Run() the form, start a thread, and loop forever.
//GUI.cpp
void BufferRecieveLoop()
{
while (true)
{
size_t bytes_read = multicast.Receive(buffer, Example::MTU_SIZE);
incoming.Process(buffer, bytes_read, endian); //method in Other.cpp
}
}
void GUI::ContinueNormally()
{
System::Threading::Thread ^loopThread = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(BufferRecieveLoop));
loopThread->Start();
loopThread->Join();
}
static void Start()
{
Globals::gui = gcnew GUI;
System::Windows::Forms::Application::Run(Globals::gui);
}
int __cdecl main(int argc, char* argv[])
{
System::Windows::Forms::Application::EnableVisualStyles();
System::Windows::Forms::Application::SetCompatibleTextRenderingDefault(false);
Start();
return 0;
}
Other.cpp creates a String^ and calls a method within GUI.h to change the text in a textbox.
//Other.cpp
void Process(const DIS::Pdu& packet)
{
System::String^ sysStr2 = "stuff";
GUI_Example_Receive::Globals::gui->ClearAndSetConsoleTextBoxText(sysStr2);
//GUI_Example_Receive::Globals::gui->BeginInvoke(gcnew MyStringDelegate(GUI_Example_Receive::Globals::gui, &GUI_Example_Receive::GUI::ClearAndSetConsoleTextBoxText), { sysStr2 });
}
I don't know where to properly Invoke my methods. Nor do I know how to Invoke my methods. A lot of what I've found is C# and hasn't worked for me.
Do I invoke from Other.cpp or inside the method being called in GUI.h?
In case anyone else has issues with this in the future and, like me, doesn't find many c++ code examples, I'll post my solution.
In my GUI.h file, I've got a method to SetConsoleTextBoxText(). This is usable only by the thread which owns consoleTextBox. Therefore, any other thread which trys to call that method will need to Invoke() the method (which is to relinquish control back to the owning thread).
//GUI.h
delegate void MyDelegate(System::String ^ text);
void SetConsoleTextBoxText(System::String^ input)
{
if (this->consoleTextBox->InvokeRequired) //is a thread other than the owner trying to access?
{
MyDelegate^ myD = gcnew MyDelegate(this, &GUI::SetConsoleTextBoxText);
//GUI is the ref class. Replace with wherever your function is located.
this->Invoke(myD, gcnew array<Object^> { input }); //Invoke the method recursively
}
else
{
//Normal function of this method. This will be hit after a recursive call or from the owning thread
this->consoleTextBox->Text = input;
this->consoleTextBox->Refresh();
}
}
Related
I'm working in visual studio and I keep getting these error.
E0322 object of abstract class type "GameState" is not allowed
Error C2259 'GameState': cannot instantiate abstract class
Error C2665 'GameState::GameState': no overloaded function could convert all the argument types
I understand that I need to override the functions from the state class in the gamestate class and I thought that I did that but apparently not. Can anyone see where I am going wrong?
code:
state.h:
class State {
private:
sf::RenderWindow* window;
std::vector<sf::Texture> textures;
public:
State(sf::RenderWindow* window);
virtual ~State(); //this means that all child classes must define these
virtual void endState() = 0;
virtual void update(const float& dt) = 0;
virtual void render(sf::RenderTarget* target = nullptr) = 0; };
state.cpp
#include "State.h"
State::State(sf::RenderWindow* window)
{
this->State::~State(){}
gamestate.h
#include "State.h"
class GameState :
public State
{
private:
public:
GameState(sf::RenderWindow\* window);
virtual \~GameState();
void endState();
void update(const float& dt);
void render(sf::RenderTarget\* target);
};
Gamestate.cpp
#include "GameState.h"
GameState::GameState(sf::RenderWindow\* window)
: State(window){}
GameState::\~GameState(){}
void GameState::endState(){}
void GameState::update(const float& dt){}
void GameState::render(sf::RenderTarget* target = nullptr){}
game.h
#include "GameState.h"
class Game
{
//variables
sf::RenderWindow* window;
sf::Event sfEvent;
sf::Clock dtClock; //frame tracker
float dt; //deltatime
std::stack<State*> states;
//initialization
void initWindow();
void initStates();
public:
Game();
virtual \~Game();
void updateDeltaTime();
void updateSFMLEvents();
void update();
void render();
void run();
};
game.cpp
//I will be leaving out all the unnecessary code to save space
#include "Game.h"
void Game::initStates() {
this->states.push(new GameState(this->window)); //this is where the problem is
}
hovering over GameState says that State::endState()/render()/update() has no override
please help!!!
Following along Threaded Fortune Server Example I've created a similar server that receives json object from clients and it can handle around 3330 clients simultaneously without any issue.
If I increase the number of clients to 3400, I get:
CreateWindow() for QEventDispatcherWin32 internal window failed (The current process has used all of its system allowance of handles for Window Manager objects.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 1158, The current process has used all of its system allowance of handles for Window Manager objects.
How can I increase number of threads?
EDIT
Instead of FortuneThread I have ClientThread like this:
class ClientThread : public QThread
{
Q_OBJECT
public:
explicit ClientThread(qintptr socketDescriptor);
void run() override;
signals:
void readyRemove();
private:
qintptr socketDescriptor;
};
and in run() I am creating client:
void ClientThread::run()
{
Client c(socketDescriptor);
emit readyRemove();
}
and the Client is as usual:
class Client : public QTcpSocket
{
Q_OBJECT
public:
explicit Client(qintptr descriptor);
public slots:
void onReadyRead();
void onError(QTcpSocket::SocketError error);
};
and implemented as:
Client::Client(qintptr descriptor)
{
connect(this, &Client::readyRead, this, &Client::onReadyRead);
connect(this, static_cast<void (Client::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), this, &Client::onError);
setSocketDescriptor(descriptor);
waitForDisconnected();
}
void Client::onReadyRead()
{
QVariantMap map = QJsonDocument::fromJson(readAll()).object().toVariantMap();
qDebug() << map["Name"].toString() << map["Age"].toInt();
}
void Client::onError(SocketError error)
{
if(state() == ConnectedState && error == SocketTimeoutError)
waitForDisconnected();
}
Ofcourse, onReadyRead() can be problematic in this way. Server class takes care of ClientThread. It stores each client thread in a QVector and removes it when disconnected from host and here is its header:
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(qint16 port, QObject *parent = 0);
~Server();
protected:
void incomingConnection(qintptr descriptor) override;
public slots:
void removeClient();
private:
QVector<ClientThread*> clients;
};
and incomingConnection and removeClient do these:
void Server::incomingConnection(qintptr descriptor)
{
ClientThread *thread = new ClientThread(descriptor);
connect(thread, &ClientThread::readyRemove, this, &Server::removeClient);
thread->start();
clients.push_back(thread);
}
void Server::removeClient()
{
ClientThread *thread = (ClientThread*)sender();
thread->quit();
thread->deleteLater();
clients.removeOne(thread);
}
To test the Server application I've used the following Console application:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector<QTcpSocket*> clients;
for(int i = 0; i < 3300; i++){
QTcpSocket *sock = new QTcpSocket();
sock->connectToHost("127.0.0.1", 2000);
sock->waitForConnected();
clients.push_back(sock);
}
QJsonObject obj;
obj["Name"] = QString("TestName");
obj["Age"] = 1;
QJsonDocument doc(obj);
foreach (QTcpSocket *s, clients) {
s->write(doc.toJson());
s->flush();
}
foreach (QTcpSocket *s, clients) {
s->close();
s->deleteLater();
}
}
I'm trying to update gui label with an other thread information (QString).
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public Q_SLOTS:
void sl_appendInfo(QString p_text);
private:
Ui::MainWindow *ui;
QFuture<void> m_thread;
QFuture<void> m_engine;
engine* m_object;
};
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
m_object = new engine();
qRegisterMetaType<QString>();
bool success = connect(this->m_object, SIGNAL(engine::sig_appendInfo(QString)), this, SLOT(sl_appendInfo(QString)), Qt::QueuedConnection);
if(!success)
{
qDebug("success failed");
}
m_engine = QtConcurrent::run(this->m_object, &engine::eventLoop);
}
//slot declaration in mainwindow.cpp
void MainWindow::sl_appendInfo(QString p_text)
{
ui->label->setText(p_text.toLocal8Bit().constData());
}
class engine : public QObject
{
Q_OBJECT
public:
engine();
~engine();
void eventLoop();
Q_SIGNALS:
void sig_exitengine(void);
void sig_appendInfo(QString p_text);
};
void engine::eventLoop()
{
int state = false;
while(true)
{
state = getNextEvent(m_event);
if (state == true)
{
sig_appendInfo("information for gui: we handled a new event !");
state=false;
}
QThread::msleep(1000);
}
}
Now I use this link : My signal / slot connection does not work to build my own code but it didn't work, the connection failed... Can I have some help please?
Thank you
Your connect syntax is wrong. You shouldn't include the class name in the SIGNAL macro. If you use the old syntax, it should be:
bool success = connect(m_object, SIGNAL(sig_appendInfo(QString)), this, SLOT(sl_appendInfo(QString)), Qt::QueuedConnection);
Or if you want to use the new syntax:
bool success = connect(m_object, &engine::sig_appendInfo, this, &MainWindow::sl_appendInfo, Qt::QueuedConnection);
I'm making a unmanaged application to handle an event fired in c# here.
FYI:: I want to handle a custom event when my Name property in C# class is changed.
I have gone through the following links:
Explanation about passing pointer to member function as parameter
Something similar to my problem.But couldn't understand the solution
Now,
In NativeApp.cpp,I have a member function which is passed as a function pointer as parameter in a method present in the c++/CLI wrapper
//NativeApp.cpp
std::string Class1::FunctionToBePointed(std::string msg)
{
return msg;
}
void Class1::NativeMethod()
{
UnmanagedWrapperClass* unmanagedWrapperClass=new UnmanagedWrapperClass();
unmanagedWrapperClass->WrapperMethod(&Class1::FunctionToBePointed,"Hello")
}
In Wrapper.h,
//Wrapper.h
class __declspec(dllexport) UnmanagedWrapperClass
{
boost::signals2::signal<void(std::string)>signalEvent;
void WrapperMethod(std::string (*GetCallBack)(std::string),std::string value);
}
When I call the WrapperMethod from NativeApp.cpp,
I subscribe my EventHandlerWrapper to a c# event
connect the function pointer to my boost signal signalEvent.
Set the Name property of the CSharp Class
When the Name Property is set, c# event is fired, EventHandlerWrapper method in Wrapper.cpp is executed.Looks like this::
void EventHandlerWrapper(string value)
{
if(signalEvent.connected())
{
signalEvent(value);
}
For some reasons I can't make my FunctionToBePointed(std::string) method as a non-member function.
P.S:: All ears for any other design approach.
In your real use-case can you simply make FunctionToBePointed a static method?
static std::string Class1::FunctionToBePointed(std::string msg)
{
return msg;
}
If yes your code should work.
The reason is that instance methods are implicitly called with an hidden this pointer, this is the thiscall calling convention, whereas static methods simply use the cdecl convention because they don't work on any instance.
EDIT:
A sample with Boost::bind:
The MyClass C# class:
using System;
using System.ComponentModel;
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate{};
private string name;
public string Name
{
get
{
return name;
}
set
{
if (name != value)
{
name = value;
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
The C++/CLI wrapper:
Wrapper.h:
class WrapperPrivateStuff;
class __declspec(dllexport) UnmanagedWrapperClass
{
private: WrapperPrivateStuff* _private;
public: void changeIt(std::string newName);
public: void WrapperMethod(boost::function<std::string(std::string)> GetCallBack);
public: UnmanagedWrapperClass();
};
Wrapper.cpp:
#using "MyClass.dll"
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include "Wrapper.h"
#include <msclr\auto_gcroot.h>
#include <msclr\marshal_cppstd.h>
#include <msclr\event.h>
class WrapperPrivateStuff
{
public: boost::signals2::signal<void(std::string)>signalEvent;
public: msclr::auto_gcroot<MyClass^> a;
public: void EventHandlerWrapper(System::Object^, System::ComponentModel::PropertyChangedEventArgs^ args)
{
this->signalEvent(msclr::interop::marshal_as<std::string>(a->Name));
}
public: WrapperPrivateStuff()
{
a = gcnew MyClass();
a->PropertyChanged += MAKE_DELEGATE(System::ComponentModel::PropertyChangedEventHandler, EventHandlerWrapper);
}
BEGIN_DELEGATE_MAP(WrapperPrivateStuff)
EVENT_DELEGATE_ENTRY(EventHandlerWrapper, System::Object^, System::ComponentModel::PropertyChangedEventArgs^)
END_DELEGATE_MAP()
};
void UnmanagedWrapperClass::changeIt(std::string newName)
{
this->_private->a->Name = msclr::interop::marshal_as<System::String^>(newName);
}
UnmanagedWrapperClass::UnmanagedWrapperClass()
{
this->_private = new WrapperPrivateStuff();
}
void UnmanagedWrapperClass::WrapperMethod(boost::function<std::string(std::string)> GetCallBack)
{
_private->signalEvent.connect(GetCallBack);
}
And the native application, test.cpp:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include "Wrapper.h"
class Class1
{
private: std::string name;
public: Class1(std::string name)
: name(name)
{
}
public: std::string FunctionToBePointed(std::string msg)
{
std::cout << "Hey it's " << name << "! Got: " << msg << std::endl;
return msg;
}
};
int main(void)
{
UnmanagedWrapperClass wrapper;
Class1 class1("Ed");
wrapper.WrapperMethod(boost::bind(&Class1::FunctionToBePointed, &class1, _1));
wrapper.changeIt("azerty");
return 0;
}
Result:
>test.exe
Hey it's Ed! Got: azerty
I have a more generic solution but it is really ugly. :(
Let me know if this fix your issue...
The mainwindow.cpp:
#include "ui_mainwindow.h"
#include <QtCore>
/* ****** Thread part ****** */
myThread::myThread(QObject *parent)
: QThread(parent)
{
}
void myThread::run()
{
while(1){
qDebug("thread one----------");
emit threadSignal1();
usleep(100000);
}
exec();
}
myThread2::myThread2(QObject *parent)
: QThread(parent)
{
}
void myThread2::run()
{
while(1){
qDebug("thread two");
emit threadSignal2();
usleep(100000);
}
exec();
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
onethread = new myThread(this);
onethread->start(QThread::NormalPriority);
twothread = new myThread2(this);
twothread->start(QThread::NormalPriority);
connect(onethread, SIGNAL(onethread->threadSignal1()),
this, SLOT(mySlot1()));
connect(twothread, SIGNAL(threadSignal2()),
this, SLOT(mySlot2()),Qt::QueuedConnection);
}
void MainWindow::mySlot1()
{
ui->textEdit1->append("This is thread1");
}
void MainWindow::mySlot2()
{
ui->textEdit1->append("This is thread2");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
ui->textEdit1->append("textEdit1");
ui->textEdit2->append("textEdit2");
}
The mainwindow.h:
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
namespace Ui {
class MainWindow;
}
class myThread : public QThread
{
Q_OBJECT
public:
myThread(QObject *parent = 0);
void run();
signals:
void threadSignal1();
};
class myThread2 : public QThread
{
Q_OBJECT
public:
myThread2(QObject *parent = 0);
void run();
signals:
void threadSignal2();
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void mySlot1();
void mySlot2();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
myThread *onethread;
myThread2 *twothread;
};
#endif // MAINWINDOW_H
Please check the above code. It can give the qDebug output normally while the textEdit1/2 have no any output. And it seems to be a multi-thread signal/slot connect issue. Who can help? Thanks!
You need to define the slots as slots:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void mySlot1();
void mySlot2();
...
Also a few other things. You don't need the exec() call in each of the threads. They are going into an endless loop anyways and would never reach that statement. And, the purpose of exec() is to start an event loop in the thread so that it can receive and process events, like having its own slots. You are just emitting.
Are you sure this connection works?
connect(onethread, SIGNAL(onethread->threadSignal1()),
this, SLOT(mySlot1()));
It should probably be:
connect(onethread, SIGNAL(threadSignal1()),
this, SLOT(mySlot1()));
I believe QueuedConnection will be implied for the connections because they are targeting a slot on an owner in a different thread than the emitter.