Co synchronizować w TCanvas

0

Witam,

Mam oto taką funkcję którą wywołuję w pętli co 0.2 s. na czas testów nie robię Sleep aby wykryc wszystkie błędy.

void TForm1::PrintScreen()
{
        int x = kalibracjaPx;
        int y = kalibracjaPy;

        TCanvas &PulpitCanvas = *new TCanvas();
        Graphics::TBitmap *Bmp = new Graphics::TBitmap;
        Bmp->Width = 94;
        Bmp->Height = 15;

        PulpitCanvas.Handle = GetDC(0);
        Bmp->Canvas->Lock();
        Bmp->Canvas->CopyRect(Rect(0, 0, 94, 15), &PulpitCanvas, Rect(x, y, x+94, y+15));
        Bmp->Canvas->Unlock();

        Image1->Canvas->Lock();
        Form1->Image1->Picture->Assign(Bmp);
        Image1->Canvas->Unlock();

        ReleaseDC(0, PulpitCanvas.Handle);
        delete &PulpitCanvas;
        delete Bmp;

        for(int i = 0; i<94; i++)
        {
                for(int j = 0; j<15; j++)
                {
                        pixtab[i][j].r = GetRValue(Form1->Image1->Canvas->Pixels[i][j]);
                        pixtab[i][j].g = GetGValue(Form1->Image1->Canvas->Pixels[i][j]);
                        pixtab[i][j].b = GetBValue(Form1->Image1->Canvas->Pixels[i][j]);
                        pixtab[i][j].sum = pixtab[i][j].r + pixtab[i][j].g + pixtab[i][j].b;
                }
        }
}

I teraz co sie okazuje - jeżeli kliknę Buttona a tam jest for(od 1 do 1000) i woła PrintScreen to wszystko jest ok.
Natomiast Jeżeli tworzę wątek i wywołuję w pętli powyższa funkcję to po kilkudziesięciu iteracjach mam error canvas does not allow drawing lub program wykona kilka dziesiąt iteracji i zachowuje się tak jakby nastąpiło zakleszczenie - Formy ani przesunąć, stoi na jednej iteracji w metodzie PrintScreen. W jaki sposób można to poprawić? Dodam że używam wątków WinApi a nie tych od Borlanda z klasy TThread.

Pozdrawiam.

0

Form1->Image1->Picture->Assign(Bmp);
Tego na pewno niewolno ci robić w wątku. Wszelkie operacje na kontrolkach VCL muszą być wykonywane w wątku głównym.
Poza tym po co przepisujesz piksele z canvas'u Image1 ?! Przerzuciłeś screen do bitmapy - i to już jest tablica pikseli. Nie przerzucaj tyle razy w różne miejsca, zwłaszcza nie wrzucaj nic na Canvas, żeby później z tego canvasu czytać. Każda operacja na canvasie wymaga przekonwertowania koloru do odpowiedniego formatu.

Proponuje coś takiego:

//niech to będzie twoja tablica pikseli
Graphics::TBitmap *pixtab = new TBitmap();
pixtab->PixelFormat = pf32bit;
pixtab->Width = 94;
pixtab->Height = 15;

//a tak możesz się odowłać do konkretnego piksela:
struct RGB32
{
	unsigned char X;
	unsigned char G;
	unsigned char B;
	unsigned char R;
};
for (int y = 0; y < 15; y++)
{
	RGB32 *linia = (RGB32*)pixtab->ScanLine(y);
	for (int x = 0; x < 94; x++)
	{
		RobCostamZWartosciamiRGB(linia[x].R, linia[x].G, linia[x].B);
	}
}

void TForm1::PrintScreen()
{
	int x = kalibracjaPx;
	int y = kalibracjaPy;

	static TCanvas &PulpitCanvas = *new TCanvas(); //tak jest ok puki obiekt ma istnieć przez cały czas trwania programu

	PulpitCanvas.Handle = GetDC(0);
	pixtab->Canvas->Lock(); //na pewno potrzebujesz ten lock ? inne watki korzystaja z tej bitmapy oprócz poniższego Synchronize ?
	pixtab->Canvas->CopyRect(Rect(0, 0, 94, 15), &PulpitCanvas, Rect(x, y, x+94, y+15));
	pixtab->Canvas->Unlock();

	ReleaseDC(0, PulpitCanvas.Handle);

	//jednak musisz użyć TThread
	ten_watek.Synchronize(AssignImageBmp);

}

void TForm1::AssignImageBmp() //tu chyba jakiś inny typ tej funkcji musi być, ale to sobie sprawdzisz
{
	Image1->Picture->Bitmap->Assign(pixtab);
}

I wypada zamienić te magiczne liczby 15 i 94 na jakieś stałe np. const int HEIGHT = 15.

1 użytkowników online, w tym zalogowanych: 0, gości: 1