2012-06-18 165 views
0

我下载了C++ Builder的XE-2的试验中,我试图找出如何访问和修改控件属性(例如:从不同的线程更改的TLabel的文本)。我知道你可以改变它在同一个线程使用:如何让控件在C++ Builder的XE2其他线程访问?

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->标题=“测试”;但那不起作用。 我试图在控制前把静态的,但是当我这样做,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"; 
} 

EDIT 2 *

FARPROC callback = (FARPROC) SampleCaptureCallback; 

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

我已经编辑到包括cpp文件。我想更改WIM_MSG_PROGRESS情况下的标签:在SampleCallback函数中。

+0

您可以传递想要访问另一个线程的控件的指针(例如在其创建时),然后可以通过该指针访问控件。 _注意:确保使用某种互斥/信号来保护对该控件的访问,以避免访问中的竞争条件。做到这一点的一种方法是在主窗体的成员函数中包装对desirec控件的访问,并将(主指针)主窗体传递给线程,以便它可以调用该函数 – Attila

+0

我是C++的新手,会你介意张贴一个例子吗?如果我猜测我是否会在头文件中声明另一个TLabel,或者究竟是什么? –

+0

你如何开始你的其他线程? – Attila

回答

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"); 
    //... 
} 

其中SetLabel1CaptionTForm2以下功能:

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

其中hLabel1互斥的Tform2

一个成员变量
HANDLE hLabel1Mutex; 

TForm2的构造函数initilized为:

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

这个例子是专为只使用Label1。如果你想在同一时间更新多个控件,您可以使用使用相同的互斥体,否则你应该保护其自身的互斥每个控制。

:了解更多关于在Win32API的inthesearticles作为首发互斥。

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

+0

感谢您的帮助!我将给出一个tru –

+1

在这种情况下,互斥量不足以保护,因为主线程不参与它。 VCL UI控件不是线程安全的,不能从主线程的上下文之外访问。期。工作者线程必须委托给主线程以安全地访问UI。可以使用静态的'TThread :: Synchronize()'方法,或使用'AllocateHWnd()'创建一个辅助窗口,您可以使用'SendMessage()'发送自定义消息。 –

+0

@RemyLebeau - Thx的更正,我不知道这个限制 – Attila

相关问题