Ok teraz powinno działać pod win 32
@XA: coś ten Twój program nie działa zbyt dobrze, obejrzyj film z załącznika.
Nadal twierdzisz, że jest sens oszczędzać na linijkach kodu? ;)
W załączniku dodaję plik wykonywalny swojego narzędzia – pobaw się.
Z nudów – czekając na Twoją wersję – dodałem u siebie kotwice do rozciągania w pionie i poziomie (oprócz diagonalnych), a także automatyczne ukrywanie tych kotwic, jeśli rozmiar zaznaczenia jest zbyt mały. Kotwice nie są też widoczne podczas przesuwania lub rozciągania zaznaczenia – aby nie przeszkadzały.
W razie gdyby nie podobała Ci się wielkość kotwic to klawiszami + i - zwiększa się je lub zmniejsza (minimum to 3 piksele, natomiast maksimum to 45 pikseli).
Edit: Obrazek znajdujący się w archiwum jest potrzebny – program używa go jako tła.
Skończyłem ten wcześniej zaczęty program – byłem ciekaw co mi z tego wyjdzie.
Ramkę da się przesuwać, da się ją też rozciągać (we wszystkich kierunkach). Kursor reaguje co do piksela na kotwice oraz samą ramkę zaznaczenia, a także prawidłowo zmienia się podczas samego rozciągania ramki (w przypadku rozciągania w dwóch osiach jednocześnie). Obsługuje też zaznaczanie o szerokości lub wysokości 0px – i będąc w takim rozmiarze, daje się przesunąć.
Z takich bajerów to dodałem opcję ukrywania przycisków do rozciągania względem jednej osi, jeśli rozmiar zaznaczenia jest zbyt mały. No i zostawiłem też opcję zmiany rozmiaru kotwic klawiszami + i - – po pierwsze, aby sprawdzić poprawność działania mechanizmów przesuwania i rozciągania, ale też po to, aby móc określić odpowiedną ich wielkość dla własnych potrzeb.
Pełne źródła dla Lazarusa w załączniku, również ze skompilowanym plikiem wykonywalnym. Have fun. ;)
W załączniku jest kod tej procedury która mi szuka kolorów :)
Tylko się nie śmiej że taki nobowaty :(
ko :=KodowanieKolorHtml(KoKolor);
kp := KodowanieKolorHtml(KpKolor);
możesz zakomentować b to tylko do "logów" wykorzystywałem
O rany… aleś sposób wybrał…
Masz na wejściu kod koloru (w postaci ciągu znaków), musisz znaleźć w bitmapie piksele o takim samym kolorze, co zadany. Po co w środku konwertujesz kolory na łańcuchowe kody?
ale za to if ładnie wygląda :P To jak to to powinno wyglądać ?
Masz ramkę funkcji:
function CountColorInBitmap(ABitmap: TBitmap; AR, AG, AB: UInt8): UInt32;
begin
end;
Uzupełnij ją w kod zliczający wystąpienia zadanego koloru (bez używania zmiennych globalnych).
Edit: tak przy okazji – nagłówki typów potrzebnych do iterowania po pikselach powinny wyglądać tak:
type
TRGBTriple = packed record
B, G, R: UInt8;
end;
type
PRGBTripleArr = ^TRGBTripleArr;
TRGBTripleArr = packed array [0 .. MaxInt div SizeOf(TRGBTriple) - 1] of TRGBTriple;
A więc ta funkcja powinna wyglądać +- chyba tak :
function CountColorInBitmap(ABitmap: Graphics.TBitmap; AR, AG, AB: UInt8): UInt32;
var
Skaner: PRGBTripleArr;
Y,X,licznik: Integer;
begin
licznik:=0;
for Y:= 0 to ABitmap.Height - 1 do
begin
Skaner := ABitmap.ScanLine[Y];
for X:= 0 to ABitmap.Width - 1 do
begin
with Skaner^[X] do
begin
if (R = AR) and (G = AG) and (B = AB) then
begin
inc(licznik);
end;
end;
end;
end;
Result := licznik;
end;
Ok, a wywołanie tak (chyba) :
procedure TForm1.Button2Click(Sender: TObject);
var
ColorT : LongInt;
R, G, B : Byte;
begin
Memo1.Clear;
ColorT := ColorToRGB(Shape1.Brush.Color);
R := GetRValue(ColorT);
G := GetGValue(ColorT);
B := GetBValue(ColorT);
// RGB()
Memo1.Lines.Add('RGB('
+ IntToStr(R) + ','
+ IntToStr(G) + ','
+ IntToStr(B) + ')');
//CountColorInBitmap(bmp,R,G,B);
Memo1.Lines.Add(IntToStr(CountColorInBitmap(bmp,R,G,B)));
end;
I co mam z tym zrobić ? :/
Mniej więcej dobrze, oprócz zbędnych zmiennych lokalnych i nadmiarowych bloków grupujących. W skrócie:
function CountColorInBitmap(ABitmap: Graphics.TBitmap; AR, AG, AB: UInt8): UInt32;
var
Pixel: PRGBTripleArr;
Y, X: Integer;
begin
Result := 0;
for Y := 0 to ABitmap.Height - 1 do
begin
Pixel := ABitmap.ScanLine[Y];
for X:= 0 to ABitmap.Width - 1 do
with Pixel^[X] do
if (R = AR) and (G = AG) and (B = AB) then
Result += 1;
end;
end;
Drugi kod też nie jest zły, ale można krócej. Np. ekstrakcję składowych koloru do trzech zmiennych można zrealizować za pomocą jednej funkcji:
Graphics.RedGreenBlue(Shape1.Brush.Color, R, G, B)
Zwrócić uwagę trzeba też na to, że jeśli nie używasz systemowych kolorów (czyli np. clMenuHighlight
i temu podobnych) to nie potrzebujesz korzystać z funkcji ColorToRGB
– nie ma ona zastosowania w przypadku podstawowych kolorów.
Reszta w porządku, choć nie podoba mi się używanie zmiennych globalnych. Takie rzeczy opakowuje się w przyjemne klasy, a nie deklaruje byle gdzie i daje do nich dostęp zewsząd. Wyczuwam bajzel w kodzie – tak się kończy sklejanie projektu z gotowców, bez głębszego zastanowienia. Tym bardziej nabieram do tego przekonania, widząc kontrolki o domyślnych (i nic nie mówiących) nazwach.
Co w tym zrypałem że mi podaje złe współrzędne koloru w linijce Memo2.Lines.Add('X:'+IntToStr(X)+'Y:'+IntToStr(Y)); ?
for Y := 0 to screen.height -1 do
begin
Pixel := bmp.ScanLine[Y];
for X:= 0 to screen.width -1 do
with Pixel^[X] do
begin
if (R = AR) and (G = AG) and (B = AB) then
begin
if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then // obszar wybrany do skanowania ???
begin
Memo2.Lines.Add('X:'+IntToStr(X)+'Y:'+IntToStr(Y));
SetCursorPos(X, koY);
klikanie();
break;
end;
end;
end;
end;
Samo przeszukiwanie bitmapy jest poprawne.
if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then // obszar wybrany do skanowania ???
Co to za cholerstwo?
// współrzędne kwadratu np:
//kp_x:=100;
//kp_x1:=200;
// kp_y:=100;
// kp_y1:=200;
//a to mi ma tylko blokować lup pokazywać w memo pozycje danego koloru na wybranym obszarze
if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then
Słyszałeś o czymś takim jak TRect
i PtInRect
? Hmm?
Tak! nawet go wykorzystuje do rysowania ramki :)
var
ramka_rect : TRect;
x,y,x2,y2,szerokosc, wysokosc: Integer;
...
szerokosc:=x-x2;
wysokosc:=y-y2;
...
with ramka_rect do begin
Left:=x;
Top:=y;
Right:=Left+szerokosc;
Bottom:=Top+wysokosc;
...
end;
Ale tu po prostu będę wszystkie x-y brał w tablice więc taka prowizorka do czasu ustalenia czemu nie działają mi prawidłowe współrzędne XY
Pisanie prowizorek nie ujdzie Ci na sucho. W końcu zrozumiesz dlaczego – jak opadniesz na dno globalno-proceduralnego bagna. I wtedy nie będzie łatwo poprawić tego co zchrzaniłeś, nie projektując aplikacji w należyty sposób.
Przy okazji – rekord typu TRect
posiada właściwości Width
i Height
.
Tylko w czym może leżeć problem, bo zmiennej X to nigdzie nie wykorzystuję :/ a z nią mam problem że się przesuwa w prawo
Skoro nigdzie jej nie używasz, to po co jest zadeklarowana?
if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then
Ten warunek wygląda na skopany – kp_x1
jest zawsze większe lub równe kp_x
? I tak samo z kp_y1
?
x nigdzie poza tą funkcją, tak zawsze musi kp_x być mniejsze od kp_x1 lub równe bo jeśli równe to oznacza że ramka obejmuje 1px a jak większe to kp_x1 szerokość
No to skoro kp_x
zawsze jest większe lub równe kp_x1
to powinieneś odwrócić kolejność tych warunków, bo wprowadzają w błąd. A tak w ogóle to powinieneś w tym przypadku skorzystać z funkcji Math.InRange
i mieć czytelny zapis:
if InRange(X, kp_x, kp_x1) and InRange(Y, kp_y, kp_y1) then
Czytelny po warunkiem, że nazwiesz sensownie zmienną kp_x
i pozostałe.
Teraz zauważyłem, że ten warunek znajduje się wewnątrz pętli skanującej piksele. Źle to robisz, bo nie powinieneś sprawdzać współrzędnych w tym warunku, ani nawet w żadnym innym. Powinieneś na podstawie zadanego obszaru poprawnie określić iteratory pętli i ich zakres.
Masz schemat:
Pobierasz do pomocniczej zmiennej kolor z lewego górnego rogu bitmapy wzorca (zaznaczonej na niebiesko) i w pętli skanujesz obszar zaznaczony na żółto. Jeśli nie znajdziesz dopasowania w tym obszarze to znaczy, że bitmapa-wzorzec nie znajduje się w całości na bitmapie-tle.
kp_x jest zawsze mniejsze od kp_x1 lub równe a nie większe :) dla mnie kp_x jest czytelne bo przechowuje dane ze zmiennej kontener_pobierania_x :)
if (X <= kp_x1) and (X >= kp_x) and (Y <= kp_y1) and (Y >= kp_y)then
mam zamienić na:
for Y := kp_y to kp_y1 do
...
for X :=kp_x to kp_x1 do
czy o coś innego chodzi z zadanym obszarem?
Nie używam bitmapy wzorca a sam kolor przechowuje, który później wysyłam do tej procedury która szuka koloru
XA napisał(a):
kp_x jest zawsze mniejsze od kp_x1 lub równe a nie większe :) dla mnie kp_x jest czytelne bo przechowuje dane ze zmiennej kontener_pobierania_x :)
Nie, nie jest czytelne – kp_x
absolutnie nic nie mówi o tej zmiennej, kontener_pobierania_x
również… Znaków podkreślenia używa się wyłącznie do nazewnictwa stałych i symboli – do zmiennych używa się PascalCase
.
Czytałeś kiedykolwiek Object Pascal Style Guide?
mam zamienić na:
for Y := kp_y to kp_y1 do ... for X :=kp_x to kp_x1 do
Oczywiście – masz przeglądać wyłącznie zadany obszar, a nie całą bitmapę. Poza tym, jeśli funkcja ma znaleźć zadany piksel w bitmapie, to ma go znaleźć i nic więcej. Wszelkie cuda pokroju klikanie
, SetCursorPos
czy Memo2.Lines.Add
należy robić gdzieś indziej, uprzednio pozyskując współrzędne piksela.
Znaków podkreślenia używa się wyłącznie do nazewnictwa stałych i symboli – do zmiennych używa się PascalCase.
O tym to ja nawet nie wiedziałem...
Tylko jak pozyskać te współrzędne :/ jeśli X mnie oszukuje
Użyj debuggera.
Na razie ustaliłem że jeśli program jest zbudowany w wersji "Poziom wykonywania: aslnvoker" wszystko o dziwo działa dobrze a gdy zmienię na "Poziom wykonywania: wymaga administratora " zaczyna pokazywać złe współrzędne :/ to może być spowodowane jakimś błędem w lazarusie ?
Że co? Ten cały poziom wykonania to po prostu jedna wartość w manifeście XML, umieszczonym w pliku wykonywalnym, więc jak miałaby oddziaływać z algorytmami, które nie są od niego uzależnione?
Już wcześniej pisałem Ci, że masz poważne braki jeśli o podstawy programowania chodzi, i że piszesz ten program kompletnie na pałę – to są powody ciągłych problemów. I będzie tylko gorzej.