0

我下载了 c++ builder xe2 的试用版,并试图了解如何访问和更改控件属性(示例:从不同的线程更改 TLabel 的文本)。我知道您可以使用以下方法在同一个线程上更改它:

Label1->Caption = " Text ";

但我需要做的是从另一个函数中改变它。到目前为止,在我拥有的表单的头文件中:

//---------------------------------------------------------------------------

#ifndef Hello_VCLH
#define Hello_VCLH

#define IN
#define INOUT
#define OUT

//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ComCtrls.hpp>
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published:    // IDE-managed Components
    TLabel *Label1;
    TButton *Button1;
    TProgressBar *ProgressBar1;
private:    // User declarations
public:     // User declarations
    __fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
#endif

在表单的 .cpp 文件中,我尝试将 TForm2::Label1->Caption = "test"; 但这没有用。我尝试将静态放在控件前面,但是当我这样做时,xe2 声称表单代码是错误的。任何人都知道如何使它可以从除主函数或线程之外的另一个函数或线程访问控件的位置吗?谢谢!

编辑**:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Hello_VCL.h"
#include <tchar.h>
#include <windows.h>
#include "wimgapi.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;

//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}


DWORD
WINAPI
SampleCaptureCallback(
    IN      DWORD msgId,    //message ID
    IN      WPARAM param1,   //usually file name
    INOUT   LPARAM param2,   //usually error code
    IN      void  *unused
    )
{
    //First parameter: full file path for if WIM_MSG_PROCESS, message string for others
    TCHAR *message  = (TCHAR *) param1;
    TCHAR *filePath = (TCHAR *) param1;
    DWORD percent   = (DWORD)   param1;

    //Second parameter: message back to caller if WIM_MSG_PROCESS, error code for others
    DWORD errorCode = param2;
    DWORD *msg_back = (DWORD *) param2;
    DWORD seconds = (DWORD) param2;


    switch ( msgId )
    {
        case WIM_MSG_PROGRESS:

            // Prints out the current progress percentage.
            //

            //lbl->Caption="Test";

            Label1->Caption = (String)param1 + " % completed";
            //Label1->Caption = (DWORD)param1;
            //wprintf(L"__________________\n\n| Capture process|\t\t(c) 2012 Andrew Butler\n__________________\n\n%d %% captured. About %i seconds(s) remaining - %i minute(s)", (DWORD)param1, ((INT)seconds / 1000), ((INT)seconds / 60000));

            break;
        case WIM_MSG_PROCESS:

            //This message is sent for each file, capturing to see if callee intends to
            //capture the file or not.
            //
            //If you do not intend to capture this file, then assign FALSE in msg_back
            //and still return WIM_MSG_SUCCESS.
            //Default is TRUE.
            //

            //In this example, print out the file name being applied
            //
            //_tprintf(TEXT("FilePath: %s\n"), filePath);

            break;

        case WIM_MSG_ERROR:

            //This message is sent upon failure error case
            //
            //printf("ERROR: %s [err = %d]\n", message, errorCode);
            break;

        case WIM_MSG_RETRY:

            //This message is sent when the file is being reapplied because of
            //network timeout. Retry is done up to five times.
            //
            //printf("RETRY: %s [err = %d]\n", message, errorCode);
            break;

        case WIM_MSG_INFO:

            //This message is sent when informational message is available
            //
            //printf("INFO: %s [err = %d]\n", message, errorCode);
            break;

        case WIM_MSG_WARNING:

            //This message is sent when warning message is available
            //
            //printf("WARNING: %s [err = %d]\n", message, errorCode);
            break;
    }

    return WIM_MSG_SUCCESS;
}

void
SampleCaptureCleanup ( HANDLE hWim, HANDLE hImg, FARPROC callback )
{
    if (hImg) {
        WIMCloseHandle (hImg);
    }

    if (hWim) {
        WIMCloseHandle (hWim);
    }

    if (callback) {
        WIMUnregisterMessageCallback( NULL, callback );
    }
}

//---------------------------------------------------------------------------


void __fastcall TForm2::Button1Click(TObject *Sender)
{
    //Label1->Caption = "Test";
}

编辑 2 *

FARPROC callback = (FARPROC) SampleCaptureCallback;

if (WIMRegisterMessageCallback( NULL,
                                callback,
                                NULL ) == INVALID_CALLBACK_VALUE) {
    printf ("Cannot set callback\n");
    return 3;
}

我已经对其进行了编辑以包含 cpp 文件。我想在 SampleCallback 函数中更改 case WIM_MSG_PROGRESS: 下的标签。

4

1 回答 1

1

调用的最后一个参数WIMRegisterMessageCallback指定了一个自定义用户数据,您可以使用该数据将信息传递给您的回调函数(在其最后一个参数中,当前名为unused)。

您可以通过修改注册调用将指向您的TForm2对象的指针传递给回调

WIMRegisterMessageCallback( NULL, callback, form)

form上面提到的指针在哪里。

然后,您可以在回调中使用该用户数据,如下所示:

DWORD  WINAPI  SampleCaptureCallback(
  IN      DWORD msgId,
  IN      WPARAM param1,
  INOUT   LPARAM param2,
  IN      PVOID  udata)
{
  TForm2* form = reinterpret_cast<TForm2*>(udata);
  udata->SetLabel1Caption("my text");
  //...
}

SetLabel1Caption的以下函数在哪里TForm2

void SetLabel1Cation(String str)
{
  WaitForSingleObject(hLabel1Mutex, INFINITE);
  Label1->Caption = str;
  ReleaseMutex(hLabel1Mutex);
}

其中hLabel1互斥锁是成员变量Tform2

HANDLE hLabel1Mutex;

并在TForm2的构造函数中初始化为:

hLabel1Mutex = CreateMutex (NULL, FALSE, NULL);
if (hLabel1Mutex == NULL)
{
  // failed to create mutex, throw exception
}

请注意,此示例仅适用于使用Label1. 如果您想同时更新多个控件,您可以使用相同的互斥锁,否则您应该使用自己的互斥锁来保护每个控件。

注意: 这些 文章中阅读有关 Win32API 中互斥锁的更多信息作为入门。

更新:Remy 指出传统的保护机制(互斥量/信号量)不适用于全线程安全。相反,各个线程需要协同工作并与主线程通信以委托对 UI 控件的访问。

于 2012-06-18T16:00:02.553 回答