Вызов метода Form из другого потока (Invoke) - PullRequest
0 голосов
/ 27 июня 2018

У меня WinForm работает в моем основном потоке, а цикл while(true) работает в отдельном потоке. Каждый цикл этого while(true) создает новый System::String^, и я хочу вставить этот String в 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?

1 Ответ

0 голосов
/ 17 июля 2018

В случае, если у кого-то еще возникнут проблемы с этим в будущем, и, как и я, он не найдет много примеров кода на c ++, я опубликую свое решение.

В моем файле 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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...