2012-06-18 100 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

相關問題