[BCB] Literki jako obiekty

0

Witam,

Mam "maly" problem. Potrzebuje wyswietlac literki na formatce glownej. Literki A-Z czcionka Arial. Czyli np Canvas i TexOut bylo by ok, eventualnie StaticText. Problem w tym iz musza byc to obiekty (tak zeby mozna bylo podpiac zdarzenia OnClick - powiekszanei i pomniejszanie, oraz ort! tych obiektow).

Na poczatku myslalem zeby wykorzystac jakies kwadratowe pole + text jednoliterkowy , ale odpada to ze wzgledu iz np przy literce A gorne rogi musza byc "niedoklikniecia" czyli po prostu obciete.

Jedyne rozwiazanei jakie widze to zrobic nowa formatke, dodac literke , i dla kazdej literki odpowiednio "przycinac" formatke funkcja SetWindowRgn(); np tak :

HRGN MyRgn;
TPoint P[4];
P[0].x = Formy->Width / 4;
P[0].y = 0;
P[1].x = Formy->Width  - (Formy->Width / 4);
P[1].y = 0;
P[2].x = Formy->Width;
P[2].y = Formy->Height;
P[3].x = 0;
P[3].y = Formy->Height;
MyRgn = CreatePolygonRgn(P, 4, WINDING);
SetWindowRgn(Formy->Handle, MyRgn, true);

Jesli jednak ma ktos latwiejszy sposob czekam na podpowiedz.

Z gory dzieki.
Sierpik

0

Na poczatku myslalem zeby wykorzystac jakies kwadratowe pole + text jednoliterkowy , ale odpada to ze wzgledu iz np przy literce A gorne rogi musza byc "niedoklikniecia" czyli po prostu obciete.

A po co aż taka dokładność???

Jedyne rozwiazanei jakie widze to zrobic nowa formatke, dodac literke , i dla kazdej literki odpowiednio "przycinac" formatke funkcja SetWindowRgn(); np tak :

Czyli okno dla każdej literki??? Przecież to czy kliknięto na daną literkę można obliczyć znając jej współrzędne, szerokość i wysokość (plus współrzędne kursora) ;)

0

Musi byc taka dokladnosc bo to ma byc Literka-Obiekt. Po nacisnieciu klawisza pojawia sie odpowiadajaca literka, literki moga sie nakladac np: dwie literki A przesuniete o 50% w dol i w lewo, i juz robi sie problem :/.

0

No dobra. A do czego to ma być??? te literki of coz :P

0

Zobrazuje moze to ponizszy obrazek user image To jest wersja z figurami. Zamiast figurek maja byc literki :>

0

Musi byc taka dokladnosc bo to ma byc Literka-Obiekt

Dla uściślenia. Nie twierdzę, że pomysł przedstawienia litery jako obiektu jest zły. Chodziło mi raczej o literę jako okno/kontrolka i to tylko po to, żeby przechwycić zdarzenie OnClick. Wracając do głównego problemu - czyli dokładności. Tu będzie problem. Musiałbyś mieć jakąś maskę, która pozwoliłaby określić czy dany pixel należy do litery czy też nie. Owszem, można sobie to zrobić ręcznie tak jak to zrobiłeś we wcześniejszym poście ale rozumiem, że te litery mogą być różnych rozmiarów(???), a to trochę komplikuje sprawę. Możesz spróbować z bitmapami. Tworzysz bitmapę o rozmiarach literki, "malujesz" ją i tworzysz maskę (przezroczystości) . Dzięki tej masce będziesz mógł określić czy dany pixel jest literą.... agrrrhhhh pisałem to już :P Na razie tyle przyszło mi do głowy. Może są jakieś prostsze rozwiązania.

0

Dokladladnie. Tyle ze to duzo roboty, a literki musza zmieniac rozmiar - od 0 do 128 pix, maja rozne kolory. Do tego dochodzi ich ilosc - czym wiecej obiektow i kombinowania tym duzo wolniej calosc dziala .

0

Tyle ze to duzo roboty

Czy aż tak dużo roboty to nie wiem ;) Jeżeli robisz to w Builderze to masz zadanie ułatwione.

[...] a literki musza zmieniac rozmiar - od 0 do 128 pix, maja rozne kolory. Do tego dochodzi ich ilosc - czym wiecej obiektow i kombinowania tym duzo wolniej calosc dziala .

I tak i nie. To zależy kiedy ten rozmiar się zmienia. Jeżeli rozmiar określany jest przy tworzeniu instancji litery-obiektu, a cała pula liter tworzona jest raz na jakiś (dłuższy) czas to chyba żaden problem??? ;)

//EDIT

Ta funkcja może się przydać GetGlyphOutline.

0

Po pierwszym poscie widac, ze robisz w C++ Builder tam sprawa przedstawia sie bardzo prosto: tworzysz sobie klase np TLiterka, ktora dziedziczy po TLabel i juz po klopocie. Mozesz sobie dodac metody do rozmiarow, kolorow i czego tam chcesz.

0

Sierpik a jak byś srobił coś takiego, że na formie rysujesz literki (nie są one żadnymi obiektami, po prostu są rysowane) i potem w OnClick dla formy sprawdzał byś kolor pixela który właśnie znajduje się pod kursorem i jeśli by był on inny niż kolor tła to "cuś by się stało", problem pojawia się wtedy gdy chcesz np: żeby kliknięcie każdej literki powodowało różne zdarzenia, a każda literka była by innego koloru.

0

Bru2s: z tym sprawdzaniem koloru pod kursorem to kiepski pomysł. Mój ojciec kiedyś napisał w ten sposób program i później się okazało, że jeśli klient ma np. 256 kolorów (lub chyba nawet 16 bitów) to program nie działał, bo kolor piksela pod kursorem był inny niż on założył na 32 bitach.

0

No i o to sie rozchodzi caly czas ;( .

Z tym TLabelem bylo by nawet duzo latwiej Ma on takze wlasciwosc Transparent wiec moga sie nakladac.

Pozostaje wiec problem sprawdzenia czy dany pixel [X][Y] nalezy do tej literki w ktora chcemy kliknac, ale mam najdzieje ze sobie z tym jakos poradze.

Dzieki za odpowiedzi. [green] [browar]

p.s.: Kolor ja ustawiam dla danej literki przy tworzeniu, wiec wiem jaki to jest... Tyle ze kolory na pewno beda sie powtarzac. Chyba przedstawie wstepne rozwiazanie szefowi. Moze On cos podpowie :/ ;P

0

Może nieco "na chama", ale pewnie skuteczne :)

  1. Tworzymy sobie "tymczasowego" TLabela i po kolei rysujemy na nim każdą literkę w takim rozmiarze i takim fontem, jakim chcemy, po czym zczytujemy z Canvasa GetPixelem do jakiejś tablicy "na boku" (dla każdej literki), 1 tam, gdzie piksel jest różny od tła, 0 gdzie indziej. W ten sposów otrzymamy maski literek w wybranym kroju czcionki.
  2. Potem, tak jak opisałeś, każda literka na swoim TLabelu. Po kliknięciu zbierasz wszystkie Labele, które są pod kursorem (będzie więcej niż jeden, jeśli się nakładają) - nie możesz polegać na zdarzeniu OnClick bezpośrednio, bo wywoła się tylko dla labela "na wierzchu", ale możesz w tym OnClicku przelecieć wszystkie podkomponenty na formie i ręcznie sprawdzić które są pod kursorem i dodać je do listy.
  3. Jak już masz listę labeli pod kursorem, to dla każdego sprawdzasz przy pomocy utworzonej wcześniej maski, czy "wpadło" w daną literkę. Coś w rodzaju
    if (maska[label.literka][mouse.x-label.left][mouse.y-label.top] != 0) { ... }

No i masz rozwiązanie. Tak wymyśliłem na szybko, ale nie wiem, czy w 100% zadziała :)

0

sorki, pierwszy raz jestem na tym forum i poknociłem tytuł posta z autorem :)

0

Tez tak mysle. Chyba najlepsze rozwizanie dla tego problemu bez zmiany "wymagan".

co do postu nizej [rotfl] :d

0
  1. Tworzymy sobie "tymczasowego" TLabela i po kolei rysujemy na nim każdą literkę w takim rozmiarze i takim fontem, jakim chcemy, po czym zczytujemy z Canvasa GetPixelem do jakiejś tablicy "na boku" (dla każdej literki), 1 tam, gdzie piksel jest różny od tła, 0 gdzie indziej. W ten sposów otrzymamy maski literek w wybranym kroju czcionki.

Tylko problem w tym, że ten tymczasowy Label będzie widoczny - to nie jest komponent z uchwytem, a Device Context jest właściciela, który musi być/jest oknem.

  1. Potem, tak jak opisałeś, każda literka na swoim TLabelu. Po kliknięciu zbierasz wszystkie Labele, które są pod kursorem (będzie więcej niż jeden, jeśli się nakładają) - nie możesz polegać na zdarzeniu OnClick bezpośrednio, bo wywoła się tylko dla labela "na wierzchu", ale możesz w tym OnClicku przelecieć wszystkie podkomponenty na formie i ręcznie sprawdzić które są pod kursorem i dodać je do listy.

Zastanawia mnie jedna rzecz. Jaką jest korzyść z wykorzystania komponentu TLabel w tym przypadku???

Co do tworzenia masek to wcześniej podałem funkcje GetGlyphOutline - może znacznie ułatwić sprawę. Tylko nie wiem czy uwzględnia aktualny rozmiar czcionki. No ale to trzeba sprawdzić ;)

0

A ja dalej stawiam na TLabel ;)
Nie testowalem bardzo dokladnie, ale wyglada, ze dziala

class TLitera : private TLabel{
 private:
  static class TPoruszanie{
   private:
    int dx, dy;
    bool przes;
    TLabel * l;
   public:
    void __fastcall MouseMove(TObject *Sender, TShiftState Shift, int X, int Y);
    void __fastcall MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
    void __fastcall MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
  } poruszanie;
 public:
  TLitera(TForm1 * f, TColor kolor, char znak) : TLabel(f){
    Parent = f;
    Font->Color = kolor;
    Text = znak;
    AutoSize = true;
    Transparent = true;
    OnMouseMove = poruszanie.MouseMove;
    OnMouseDown = poruszanie.MouseDown;
    OnMouseUp = poruszanie.MouseUp;
    Cursor = crHandPoint;
  }
  void ustaw_pozycje(int x, int y){
    Left = x;
    Top = y;
  }
  void ustaw_rozmiar(int r){
    Font->Size = r;
  }
};

TLitera::TPoruszanie TLitera::poruszanie;

void __fastcall TLitera::TPoruszanie::MouseMove(TObject *Sender, TShiftState Shift, int X, int Y){
  if (przes){
    l->Left += X - dx;
    l->Top += Y - dy;
  }
}

void __fastcall TLitera::TPoruszanie::MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){
  l = (TLabel *)Sender;
  if ((l->Font->Color == l->Canvas->Pixels[X][Y]) && !przes){
    dx = X;
    dy = Y;
    przes = true;
  } else l->SendToBack();
}

void __fastcall TLitera::TPoruszanie::MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){
  przes = false;
  l->SendToBack();
}
0

Tu masz przykład innego sposobu określenia czy kliknięto literę (wystarczy wkleić do handlera OnMouseDown).

void __fastcall TForm1::__on_ms_down(TObject *Sender, TMouseButton Button,
      TShiftState Shift, int X, int Y)
{
 HRGN hrgn;
 char litera[]="A";

 this->Canvas->Brush->Color=clBlack;
 this->Font->Name="tahoma";
 this->Font->Size=80;

 BeginPath(this->Canvas->Handle);
 SetBkMode(this->Canvas->Handle,TRANSPARENT);
 TextOut(this->Canvas->Handle,10,10,litera,1);
 EndPath(this->Canvas->Handle);

 hrgn=PathToRegion(this->Canvas->Handle);

 if(PtInRegion(hrgn,X,Y))
   MessageBeep(0xFFFFFFFF);
 
 TextOut(this->Canvas->Handle,10,10,litera,1);
 DeleteObject(hrgn);
}
//---------------------------------------------------------------------------
0

Przystapilem do implementacji za pomoca TLabel'ow. Niestety problem juz jest na samym poczatku ... ;(

Z obrazuje to najlepiej maly przyklad.

user image

Klikniece w punkt :

  1. Trafia w C , a powinno w A (lub w nic..)
  2. Trafia w C, powinno w C
  3. Trafia w C, a powinno w D
  4. Trafia w A, powinno w A

Sprawdze jeszcze rozwiazanie Foflika...

Skutecznosc ...

0

rzystapilem do implementacji za pomoca TLabel'ow. Niestety problem juz jest na samym poczatku ...

I co, nie mówiłem??? :P

0

Wiadomos od Szefa...

Wpisz litere w prostokąt. Kliknięcie w prostokąt powoduje znikniecie.
Inaczej litery zaczną tworzyć dziwne figury

No i problem sam sie rozwiazal :)

Mimo wszytko ogromne dzieki za pomoc :D Postaram sie kiedys to odrobic [browar]

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