从不同线程调用 Form 方法 (Invoke)
Call a Form method from a different thread (Invoke)
我在主线程上有一个 WinForm 运行,在单独的线程上有一个 while(true)
循环 运行。 while(true)
的每个循环都会创建一个新的 System::String^
,我想将 String
粘贴到我的 UI.
上的 TextBox
中
我的文件结构包括 GUI.h
、GUI.cpp
和 Other.cpp
。
GUI.h
包含所有自动创建的主(也是唯一)表单代码。它还具有一些 Get
、Set
和 ButtonClick
方法。
//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
包含 Run()
表单、启动线程并永远循环的代码。
//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
创建一个 String^
并在 GUI.h
中调用一个方法来更改文本框中的文本。
//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 });
}
我不知道在哪里可以正确地 Invoke
我的方法。我也不知道如何 Invoke
我的方法。我发现的很多东西都是 C# 的,但对我不起作用。
我是从 Other.cpp
调用还是在 GUI.h
调用的方法内部调用?
如果以后有人遇到这个问题,并且像我一样找不到很多 C++ 代码示例,我将 post 我的解决方案。
在我的 GUI.h
文件中,我有一个 SetConsoleTextBoxText()
的方法。这只能由拥有 consoleTextBox
的线程使用。因此,任何其他尝试调用该方法的线程都需要 Invoke()
该方法(这是将控制权交还给拥有线程)。
//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();
}
}
我在主线程上有一个 WinForm 运行,在单独的线程上有一个 while(true)
循环 运行。 while(true)
的每个循环都会创建一个新的 System::String^
,我想将 String
粘贴到我的 UI.
TextBox
中
我的文件结构包括 GUI.h
、GUI.cpp
和 Other.cpp
。
GUI.h
包含所有自动创建的主(也是唯一)表单代码。它还具有一些 Get
、Set
和 ButtonClick
方法。
//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
包含 Run()
表单、启动线程并永远循环的代码。
//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
创建一个 String^
并在 GUI.h
中调用一个方法来更改文本框中的文本。
//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 });
}
我不知道在哪里可以正确地 Invoke
我的方法。我也不知道如何 Invoke
我的方法。我发现的很多东西都是 C# 的,但对我不起作用。
我是从 Other.cpp
调用还是在 GUI.h
调用的方法内部调用?
如果以后有人遇到这个问题,并且像我一样找不到很多 C++ 代码示例,我将 post 我的解决方案。
在我的 GUI.h
文件中,我有一个 SetConsoleTextBoxText()
的方法。这只能由拥有 consoleTextBox
的线程使用。因此,任何其他尝试调用该方法的线程都需要 Invoke()
该方法(这是将控制权交还给拥有线程)。
//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();
}
}