Hirdetés

2024. április 19., péntek

Gyorskeresés

Hozzászólások

(#2101) Tomi_78 válasza Tomi_78 (#2100) üzenetére


Tomi_78
tag

Na, ez is sikerült: fehér színűvé tettem a .BMP képcsíkban a hátteret és transparent utasítás helyett a gpkatallkep[i].mask(clWhite);-ot alkalmaztam.
Csak még az a baj, hogy - ahogy eddig is - az alképek bal oldalán egy fekete csík látható. Ezt hogy lehet eltüntetni? Lehet, hogy rossz értéket adtam meg a kép téglalapjának (Rect)? Próbáltam 0 helyett 1-et, 2-t, de ezekkel sem jó, pedig azt hittem, beljebb kéne kezdeni a ciklust ezen értékekkel.

(#2102) Tomi_78 válasza Tomi_78 (#2101) üzenetére


Tomi_78
tag

Fekete csík problémája is megoldva!
Ugyanis - nem tudom, miért, de - ki kellett egészítenem a t2 téglalap beállításait annak left-top-right-bottom tulajdonságainak megadásával.
Pedig azt hittem, a width-height is elég lesz, de úgy látszik, nem. :U

(#2103) vz12 válasza Tomi_78 (#2102) üzenetére


vz12
tag

Szuper!
A kitartó kísérletezgetéssel rengeteg tapasztalatot lehet szerezni, ami tudássá tud alakulni és jó esetben még élvezi is az ember. :)

(#2104) Tomi_78


Tomi_78
tag

És az assembler hibákat hol lehet megnézni, hogy az a kódomban hol van, amikor SIGSEGV osztályú kivétel hibaüzenetet kapok?
Ilyenkor csak megjelenik az Assembly-kódsor és nem tudok mit csinálni, csak hogy bezárom azt az ablakot. Az a baj, hogy gőzöm sincs, hogyan kell debuggolni...

(#2105) Tomi_78 válasza Tomi_78 (#2104) üzenetére


Tomi_78
tag

Megvan, miért jelenik meg a hiba, de sejtelmem sincs, hogy miért és hogyan oldható meg.
Így törlöm a TEgysegek objektum egy példányát, ha már nem kell, mert a letezik változója hamisra állítódott:
if egysegdb>0 then
 begin
   for edb:=0 to egysegdb-1 do
   begin
      if egysegek[edb].letezik=false then FreeAndNil(egysegek[edb])
      else

Ezt az ellenőrzést a pályafrissítő időzítő futtatja le 25 időegységenként. De amikor bekövetkezik ez a FreeAndNil(), akkor dob ki hibával a program.
Akkor nem is ezzel kellene példányt törölni? Próbáltam a Free-t meg a FreeInstance-t is, de mind hibát jelzett, mikor lefutottak.

(#2106) vz12 válasza Tomi_78 (#2105) üzenetére


vz12
tag

0. Meg kellene nézni (debug), hogy az "egysegek[edb]" véletlenül se legyen NULL. (valószínűleg nem az, de legyél teljesen biztos benne)

1. Lehetne ezt a mintát követni, a "véletlen" problémák kivédése okán:
if Assigned(x) then FreeAndNil(x);

2. A fent említett mutatóra CAST-olnám a saját típusát, szintén csak a biztonság kedvéért, ez amúgy SOHASEM árt.
/ FreeAndNil(TDeklaráltTipus(egysegek[edb])); /

3. Megpróbálnám ezt is, ez az "eredeti" pascal megoldás, 2 lépésből áll:
dispose(TDeklaráltTipus(egysegek[edb]);
egysegek[edb]:=nil;
/ Tudom, hogy a "FreeAndNil" is elvileg pontosan ezt csinálja, csak 1 lépésben, de azért gyakorlati tapasztalat szerzése céljából én kipróbálnám. /
---------------------
Én a típuskényszerítéstől várnám a megoldást, mert a "sima Free" túl általánosnak tűnik, "mindenre" IS működnie kell, ezért valószínűleg sima "Pointer" vagy "TObject" hivatkozásokkal dolgozik.

[ Szerkesztve ]

(#2107) Tomi_78 válasza vz12 (#2106) üzenetére


Tomi_78
tag

Köszi a választ, de egyelőre még nem jó. :(
Az imént próbáltam ezzel is a FreeAndNil() helyett: delete(egysegek,edb,1); de hiába - bár most más Assembly utasítást dobott fel.
A másik, bár kevésbé lényeges probléma, hogy ha ez a kóddarab van a FormPaint-ban:
if egysegdb>0 then
          begin
            for edb:=0 to egysegdb-1 do
            begin
              if egysegek[edb].letezik=true then
              begin
             if egysegek[edb].tulaj='jatekos' then
                  canvas.brush.Color:=clBlue
               else
                   canvas.brush.Color:=clYellow;
               radarobj.left:=2+Round(egysegek[edb].xhely / (palyakep.canvas.width / opanelkep.width+2));
               radarobj.top:=radyeltol+Round(egysegek[edb].yhely / (palyakep.canvas.height / opanelkep.width+6));
               radarobj.right:=radarobj.left+2;
               radarobj.bottom:=radarobj.top+2;
               canvas.rectangle(radarobj);
              end;
            end;
end;
akkor miért mindig kék színű lesz a radarobj téglalap? Még a nem játékos irányította egységeknél is? Mert azoknál sárga kellene, hogy legyen.

(#2108) Tomi_78 válasza Tomi_78 (#2107) üzenetére


Tomi_78
tag

Na, most így sikerült kijavítanom:
if egysegek[edb].letezik=false then
      begin
           delete(egysegek,edb,1);
           dec(egysegdb,1);
      end

Bár az a gyanúm, hogy ez be fog kavarni kicsit, mert ha átrendeződik az egységek sorrendje, akkor a játékosé átkerülhet a számítógépéhez és fordítva, stb.
Na mindegy, ez majd kiderül.
De a radarobj miért kék még mindig? :O

(#2109) vz12 válasza Tomi_78 (#2107) üzenetére


vz12
tag

Ezt leginkább csak debug-olással lehet kideríteni, nálad.
Legyen egy töréspont az "if"-en, és sor léptetésekkel haladva le kell kérdezgetni a kérdéses adatokat. A számítógépnek biztos, hogy igaza van, vagyis valahol valamilyen érték nem fog stimmelni, onnan kell majd tovább nyomozni.

(#2110) Tomi_78


Tomi_78
tag

Sziasztok!
Azt szeretném megtudni, hogy Lazarus FreePascal-ban ha Assembly hibaüzenetet kapok, mint a mellékelt képen, akkor abból hogyan deríthetem ki, hogy az a forráskódban melyik sort jelenti?
Sajnos a debugoláshoz egyáltalán nem értek, de a programom valami "External SIGSEGV osztályú kivétel" hibaüzenettel, majd az Assembly ablakkal áll le.

(#2111) vz12 válasza Tomi_78 (#2110) üzenetére


vz12
tag

Hello!

A pontos választ nem tudom, de gyors kereséssel az alábbi lehetséges okokat dobta a Google:

If a program gets a segmentation fault (SIGSEGV), it references a memory address outside of the memory available to it.
The most frequent causes for a segmentation fault are:
An array index is outside the declared range.
The name of an array index is misspelled.
The calling routine has a REAL argument, which the called routine has as INTEGER.
An array index is miscalculated.
The calling routine has fewer arguments than required.
A pointer is used before it is defined.

Valószínűleg ezek csak példák, tehát lehetséges más ok is, de kiindulási alapnak talán elegendő.
A debugolást tessék megtanulni, nagyon leegyszerűsíti a hibakeresést, a Delphi-ben a beépített debugger nagyon egyszerűen és kiválóan működik, a Lazarus-ban lévő pedig a képek alapján kb. ugyanaz lehet.
Az első G-s találat a "debug in Lazarus"-ra ez, ránéztem, tök jó:
[link]

Egyébként ezt a hibát NEM biztos, hogy lehetséges könnyű megtalálni, mert ha pl. iterációban, időzített futásban, stb., tehát ha NEM az első ráfutáskor, hanem később "menet közben valamikor egyszercsak" jelentkezik a probléma, a változók változásai miatt, vagy ha a debugolás miatti megállások megváltoztatják a környezeti (idő) feltételeket, akkor bizony rá kell szánni az időt. És neked még azt is be kell határolni, hogy vajon HOVA kellene töréspontot tenni (ahol - még egyszer mondom - lehet hogy az első N db alkalommal akár minden rendben is van, tehát hiába állítod meg ott a programot, csak utána romlik el ugyanott "valamikor"). Először az F8-akat kellene nyomkodni, és ha megvan, hogy miben száll el, akkor (elölről kezdve) ugyanott F8 HELYETT F7-tel kellene OTT mélyebbre menni, ahol 1-gyel mélyebb szinten először szintén F8, utána F7. Amikor már nem lehet mélyebbre menni (F7), akkor megtaláltad a hibapontot, és kiakadás előtt meg kell vizsgálni a változók, objektumok, tömbök, stb. tartalmait akár ezek "watch"-olásával, akár az egér sima elem fölé húzásával, ahogy a fenti videóban is mutatják, és a kiírt értékek alapján NEKED már látnod kellene a problémát.

A fentiek alapján MEGELŐZÉSSEL is lehetne kísérletezni, brutál validációkkal (kissé túl erőltetettnek tűnő IF-ezéssel) a tömb indexek és a mutatók/pointerek felhasználását tekintve. A rossz függvény paraméterezést kevéssé tartom valószínű oknak, azt talán "rendesen" is meg tudja mondani a Lazarus, de ki tudja.
Esetleg (de ez csak ötlet) ha képernyő/pálya frissítésével függ össze a hiba, akkor LEHET, hogy a megadott frissítési idő kevés, ezért "összetorlódnak" a feladatok, amit már nem bír elviselni a rendszer, vagyis próbálkozni lehet a frissítés idejének megnövelésével is VAGY a pályaméret csökkentésével VAGY a frissítéskor lefutó kód gyorsításával, amennyiben az még nem optimális.

[ Szerkesztve ]

(#2112) Tomi_78 válasza vz12 (#2111) üzenetére


Tomi_78
tag

Hű, köszönöm, Vz12, a gyors és alapos választ!
Még tegnap ezt találtam a SIGSEG-vel kapcsolatban, amikor kerestem:
[link]
Be is kapcsoltam a kipipálható dolgokat a Hibakeresőben, és azután nem jelentkeztek a hibák. Csak hát én kipipálás nélkül is szeretném tudni az okokat és akkor is hibamentesnek szeretném tudni a programomat, nameg érteni azt, hogy mit pipáltam ki.
Ma kivettem a jelölőnégyzetekből a pipákat és erre megint hibát dob fel egy kis idő után.
A videót is köszönöm; még ma megnézem okvetlenül. És az F8-asozást is kipróbálom.

(#2113) Tomi_78 válasza Tomi_78 (#2112) üzenetére


Tomi_78
tag

Eddig ezt a hibaüzenetet sikerült kinyernem az F8-cal:
"Cannot find bounds of current function".

(#2114) Tomi_78


Tomi_78
tag

Na, most ezzel a töréspontozással sikerült teljesen futtathatatlanná tenni a programomat, mert F9-re is ezt írja ki:

És hiába lépek ki majd indítom újra a Lazarus-t, mindig ez jön be. :F

(#2115) vz12 válasza Tomi_78 (#2114) üzenetére


vz12
tag

> "Cannot find bounds of current function"
És van a függvénynek eleje/vége? El sem kellene indulnia a programnak, ha ilyen hiba van benne, ez az üzenet számomra nagyon furcsa, gyakorlatilag értelmezhetetlen.

> F9-re is ezt írja ki
Újraindítás után, MIELŐTT F9-et nyomnál, próbáld meg törölni az összes töréspontot:
Nézet/Hibakereső ablakok/Töréspontok (Ctrl+Alt+B)
Nyilván itt ki kellene jelölni az összes töréspontot, majd törlés.
Ha utána sikeresen elindul, akkor - ha még nem ment el a kedved tőle - meg lehet próbálni a futtatást.
A Shift+Ctrl+F9-cel a "Futtatás/Futtatás hibakeresés nélkül" esetén elvileg szintén nem szabadna annak a csúnya "Hibakereső Hiba" ablaknak megjelennie, hiszen nincs hibakeresés. De ez már lehet hogy egy Lazarus hozzáértő segítségét kívánja.
Ha "megjavult", akkor ÉN nagyon óvatosan (messziről haladva, egyesével, vagy csupán csak 1-et) megpróbálnám újra felvenni a törésponto(ka)t.
Akkor tudok ilyen hiba ablakot esetleg elképzelni, ha a töréspont a hiba UTÁN lett téve, és a hiba hatására valamilyen kezelhetelen állapotban beragadt a Lazarus.
Bízom benne, hogy teljes újratelepítés NEM szükséges, mert az durva lenne.
Sosem voltam ilyen helyzetben, tehát ezt nem tudom.

(#2116) Tomi_78 válasza vz12 (#2115) üzenetére


Tomi_78
tag

Huhhh, úgy látszik, sikerült megtalálnom és eltávolítanom a töréspontot és most már elindul a program - persze a hibával együtt. Érdekes módon hibakeresés nélküli futtatáskor nem áll le...

(#2117) Tomi_78


Tomi_78
tag

Amúgy ennek a lehetőségnek mi értelme van a Projekt beállításai/Hibakeresés-ben:
Hibakeresési információk létrehozása a GDB számára (lassabb / nagyobb exe-méret) ?
Mert én ezt most kikapcsoltam, hogy ne legyen olyan óriási az EXE. De ha visszakapcsolnám és futtatnám az EXE-t, akkor rendesen kiírná a hibát vagy mi?

(#2118) Tomi_78


Tomi_78
tag

Talán megvan a hiba oka: ha megsemmisül egy játékegység, akkor lép ki a program - legalábbis úgy látom.
A játékobjektumok példányainak van egy letezik boolean típusú tulajdonsága, ami false lesz, ha megsemmisül. Ezt mindig ellenőrzöm, hogy true vagy false, bármikor szóba kerül egy objektum.
Amikor ciklussal végigmegyek a példányokon, ellenőrzöm, hogy létezik-e, ha meg nem, akkor jön a FreeAndNil (vagy a Delete, de azzal sem jó). Ha meg létezik, akkor jöhetnek vele a műveletek.
De ilyen ciklusok nemcsak a pályafrissítés eljárásban, hanem sok másban is vannak velük, pl. a FormPaint-ben. De mindig leellenőrzöm, hogy létezik-e, ha műveletet végzek velük.
Akkor ez most nem jó megoldás a példányok kezelésére, törlésére? Lehet, hogy a dinamikus tömb kezelése nem jó, ami tartalmazza őket? Vagy hogy kell ezt csinálni szabályosan?

(#2119) vz12 válasza Tomi_78 (#2117) üzenetére


vz12
tag

Nem tudom, próbáld ki. :)
Ha nem jön be, akkor majd visszakapcsolod.

(#2120) vz12 válasza Tomi_78 (#2118) üzenetére


vz12
tag

Nos, ha timer-rel frissíted "valamikor" a pályát MIKÖZBEN esetleg a törlések éppen zajlanak, az nem tűnik szerencsésnek. Itt valamilyen minimális szervezésnek illene lennie, pl. egy logikai változónak, hogy éppen "karbantartás" zajlik, ilyenkor a frissítés legyen blokkolva. A karbantartás végeztével a logikai változó megváltozásával ismét mehet a frissítés. Tehát a törlések UTÁN a megváltozott állapotra kell ráengedni a frissítést.

Esetleg - ez még jobb - lehet 2 db logikai változó is, oda-vissza ellenőrzéssel, addig nincs frissítés, amíg karbantartás van, illetve addig nem kezdődik karbantartás, amíg zajlik a frissítés.

Mondom ezt csak ötletként, a pontos kód ismerete nélkül, de amúgy lehet, hogy eddig is ez az egyidejűség okozta a problémádat.
Ezek a változók lennének az ún. "szemafor"-ok, ennek van hagyománya a programozásban, és kb. ilyen esetekben használják őket, az egyidejűség elkerülésére, hogy ne legyen "karambol".

(#2121) Tomi_78 válasza vz12 (#2119) üzenetére


Tomi_78
tag

Igen, a bekapcsolásával már érthetőbb lett az üzenet: pontosan kiírta, hogy melyik sor a hibás! :K Igaz, ezzel nem jutottam közelebb a megoldáshoz, mert nem tudom, hogy miért nem jó az. :N
Lehet, hogy mégis a frissítéssel van a gond, ahogy írod? A példányok törlése valóban így megy 25 fps-es "invalidate"-enként:
procedure TForm1.palyafrissites(Sender: TObject);
begin
ha nem létezik, törlés, különben műveletek vele.
with canvas do invalidate;
end;

(#2122) Tomi_78


Tomi_78
tag

Az imént átírtam ezeket:
egysegek[edb].letezik=true
erre:
egysegek[edb]<>nil
és így úgy tűnik, megszűntek a hibák. Valamint a törlést:
freeandnil(egysegek[edb]);
dec(egysegdb,1);
setlength(egysegek,egysegdb);
az eddigi egyetlen, letezik=false jelölésű helyről áttettem minden olyan helyre, ahol eddig ezt a letezik változót hamisra állítottam.
De akkor ezek szerint a FreeAndNil() nem azonnal töröl? Csak nil-re állítja az objektumpéldányra a mutatót?

(#2123) vz12 válasza Tomi_78 (#2122) üzenetére


vz12
tag

Nagyon jó változtatásnak tűnik a "letezik" helyett a "nil"-re vizsgálni, jó ötlet volt. :K

> a FreeAndNil() nem azonnal töröl?
A neve alapján illene azonnal törölnie.
Ezt találtam gyorsan róla a neten: It calls an object's destructor
Vagyis elvileg valóban töröl, megsemmisít, de többet erről csak az tud, aki írta a forráskódját ...

Ha tényleg megszűntek a hibák, akkor "megérte" ennyit foglalkozni vele, valószínűleg sokáig megmaradó tapasztalatot szereztél vele, csak így tovább.

(#2124) Tomi_78 válasza vz12 (#2123) üzenetére


Tomi_78
tag

Köszönöm a segítséget és a bátorítást! :K
Mit mondjak... néha nem könnyű a programozás, főleg ha az embernek más segítsége nincs a környezetében, csak a világháló bújása meg a fórumok.

(#2125) vz12 válasza Tomi_78 (#2124) üzenetére


vz12
tag

Nincs mit. :)
Valóban nem könnyű, és ezt a "civilek" legtöbbször nem látják, sokszor téves elképzeléseik vannak magáról a feladatról is, meg annak adott körülmények közötti megvalósításáról is, pl. időigény, stb. Az még a legszerencsésebb helyzet, ha az ember "nyomás nélkül" saját magának írja a programot, és van rá elég ideje meg elhivatottsága is.

(#2126) Tomi_78


Tomi_78
tag

Na de ez a hibajelenség miért van:
Van egy kilépésgomb a programomban, melyet így hozok létre és rendelem hozzá a kilépés kezelését végző függvényt:
kilepgomb:=TButton.Create(form1);
            kilepgomb.Parent:=form1;
            kilepgomb.Top:=2;
            kilepgomb.Left:=2;
            kilepgomb.Caption:='Esc';
            kilepgomb.OnClick:=@kilepgombkatt;
Ugyanakkor az ESC billentyű lenyomásával is szeretném vezérelni a kilépést, ezért ez van a FormKeyDown-ban:
if Key=VK_ESCAPE then
     kilepgombkatt(form1)
  else (...)
A kilepgombkatt()-ban ez történik:
procedure TForm1.kilepgombkatt(Sender: TObject);
var valasz,stilus: integer;
begin
 stilus:=MB_ICONQUESTION + MB_YESNO;
 valasz:=Application.MessageBox('Biztosan ki akarsz lépni?', 'Megerősítés', stilus);
 if valasz=IDYES then close;
end;
Ha rákattintok egérrel a gombra és a NO-t választom, és utána egér helyett az ESC gombbal próbálnám ezt megint aktivizálni, akkor nem történik semmi. Magyarán ezután csak az egérkattintással tudok kilépni.
Miért van ez így; mi történik a programban és hogyan javítható?

(#2127) vz12 válasza Tomi_78 (#2126) üzenetére


vz12
tag

kilepgomb:=TButton.Create(form1);
kilepgomb.Parent:=form1;
kilepgomb.Top:=2;
kilepgomb.Left:=2;
kilepgomb.Caption:='Esc';
kilepgomb.OnKeyDown:=@FormKeyDown;
kilepgomb.OnClick:=@kilepgombkatt;

Amikor a kilépés gombon állsz, akkor nem aktív a form, vagyis a bill. lenyomás NEM a form keydown-ja, hanem a button keydown-ja.
Pl. a fenti módon át lehet irányítani az eseményeket, így "közös" keydown-ja lesz a gombnak és a formnak.
:)

(#2128) Tomi_78 válasza vz12 (#2127) üzenetére


Tomi_78
tag

Köszönöm ezt is; kipróbálom!
Csak azt nem értem, hogy amikor az egérrel nem a kilépés gombon vagyok, akkor is miért nem lehetett a billentyűt használni? Ezek szerint ha egyszer rákattintottam, akkor utána megmaradt nem aktívnak a Form?

(#2129) Tomi_78 válasza vz12 (#2127) üzenetére


Tomi_78
tag

Valami hibát okozott a vastagbetűs sor beszúrása. Mellékeltem róla képet, mert nekem ez semmit nem mond...

(#2130) vz12 válasza Tomi_78 (#2128) üzenetére


vz12
tag

"Focus is the ability to receive user input through the mouse or keyboard. Only the object that has the focus can receive a keyboard event. Also, only one component per form can be active, or have the focus, in a running application at any given time.
Some components, such as TImage, TPaintBox, TPanel and TLabel cannot receive focus. In general, components derived from TGraphicControl are unable to receive focus. Additionally, components that are invisible at run time (TTimer) cannot receive focus."
-----------------
Itt van még valami:
To trap keystrokes at the form level instead of passing them to the form's components, set the form's KeyPreview property to True (using the Object Inspector). The component still sees the event, but the form has an opportunity to handle it first - to allow or disallow some keys to be pressed, for example.

Magát a formot közvetlenül NEM bill. inputra tervezték (az a rátehető objektumok egy részének a feladata), de eseménykezelője van, a form csak úgy figyel a háttérben.

Ha a formon beállítod a "KeyPreview=true"-t, akkor ELSŐDLEGESEN (központosítva) a form eseménykezelője dolgozza fel a bill. eseményeket, pl. a keydown-t is, MAJD AZUTÁN annak az objektumnak (pl. gombnak) a pl. keydown-ja is lefut, ahonnan a bill. lenyomás érkezett. A sorrend fontos, a form eseményben trükközni is lehet, mielőtt az objektum feldolgozná a bill. nyomást.

Ha a "KeyPreview=false", akkor a form bill. kezelő eseményei hatástalanok (ez történt nálad is, mert a "false" az alapértelmezett). Ilyenkor az általam írt "központosítás", mint módszer/trükk használható, tehát a formon lévő OBJEKTUM eseménykezelője kapja el a bill. nyomást (mert a formé nem fogja), de a form eseménykezelője hajtra végre. Ez jó akkor, ha pl. nem akarod, hogy minden objektum esetén végrehajtódjon a "központi" kód, csak azoknál amelyeknél beállítod, illetve nem akarsz többszörösen (redundánsan) kódolni.

A gyakorlatban: (a kilepgomb.OnKeyDown ki van kommentelve)

form1.KeyPreview:=true;
kilepgomb:=TButton.Create(form1);
kilepgomb.Parent:=form1;
kilepgomb.Top:=2;
kilepgomb.Left:=2;
kilepgomb.Caption:='Esc';
// kilepgomb.OnKeyDown:=@FormKeyDown;
kilepgomb.OnClick:=@kilepgombkatt;

(#2131) vz12 válasza Tomi_78 (#2129) üzenetére


vz12
tag

Hát, nem tudok mit mondani, vettem a fáradtságot, és LAZARUS-ban kipróbáltam, mielőtt beküldtem ide, és nálam működött.

A form "KeyDown"-ja valóban a "FormKeyDown" eljárásra mutat? Nálad is az a neve? Nem változtattad meg? Mert ha igen, akkor a megváltoztatott eljárás nevet kell odaírni a vastagbetűs sorba, de ez triviális.

Nem tudom, hogy mi a problémája a pupup menüvel, meg hogy milyen töréspontokról van szó, meg hogy milyen köze van a "keydown"-hoz, szerintem semmi.

[ Szerkesztve ]

(#2132) Tomi_78 válasza vz12 (#2131) üzenetére


Tomi_78
tag

Az lehet baj, hogy maga a gomb létrehozás is a FormKeyDown() eseményben van? A következőképpen:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState
  );
begin
  if Key=VK_ESCAPE then
     kilepgombkatt(form1)
  else
  begin
    case jatallapot of
    2: begin
            kilepgomb:=TButton.Create(form1);
            kilepgomb.Parent:=form1;
            kilepgomb.Top:=2;
            kilepgomb.Left:=2;
            kilepgomb.Caption:='Esc';
            kilepgomb.OnKeyDown:=@FormKeyDown;
            kilepgomb.OnClick:=@kilepgombkatt;

(#2133) vz12 válasza Tomi_78 (#2132) üzenetére


vz12
tag

Szerintem az baj, bizony.
Én a FormCreate-be tettem, illetve a programozott létrehozásokat, valamint a kezdeti beállításokat a fő formra vonatkozóan mindig odateszem.
Legfeljebb ELREJTEM addig, amíg nem kell.

Ahogy látom, a "jatallapot=2" esetén lehet, hogy elég sokszor létrehozza azt a gombot és esetleg besokall a gép, persze nem ismerem a vezérlésedet, de onnan tedd át máshova gyorsan, ami garantáltan egyszer fut le, pl. a FormCreate-be.

[ Szerkesztve ]

(#2134) Tomi_78


Tomi_78
tag

És az miért van, hogy ebben a kis képméretező programomban mindig eredeti, nagy méretben mentődik el a betöltött kép, holott ha más értékeket adok meg neki az Edit1 és Edit2-ben, akkor abban mutatja a Form-on, de elmenteni mindig az eredetiben menti el?
procedure TForm1.Button2Click(Sender: TObject);
var ujkep: TImage;
begin
  if ListBox1.ItemIndex<>-1 then
  begin
     ujkep:=TImage.Create(Self);
     ujkep.parent:=Form1;
   ujkep.autosize:=false;
     ujkep.Proportional:=true;
     ujkep.Stretch:=true;
     ujkep.picture.bitmap.setsize(strtoint(Edit1.Text),strtoint(Edit2.Text));
     ujkep.Picture.LoadFromFile(mappa+ListBox1.Items.Strings[0]);
    ujkep.picture.SaveToFile(mappa+'PROBA.png');
     //ujkep.free; //Mutatja a Form-on a kisképet, ha kommentelt.
  end;
end;  

(#2135) vz12 válasza Tomi_78 (#2134) üzenetére


vz12
tag

Nos, nem nagyon értek hozzá, de nem gondolnám, hogy csupán property-k állítgatásával újraÉPÍTI (konvertálja) a kép tartalmát, ezért menthette az eredeti képet. A property-k a vizualitásra hatással lehetnek, de BELÜL a kép szerintem NEM változik.

Ezen link alapján (ott "procedure TForm1.Button2Click(Sender: TObject);") írtam egy egyszerű működő példát Delphi-ben, még a képernyőn sem jelenítettem meg semmit (a gombon kívül), csak gombnyomásra legyártja egy kép kicsinyített mását a méretarány megtartásával.
1280x905 helyett 100x71 pixel.
672 Kb helyett 5 Kb.
Ja, a példa JPG-vel dolgozik, tehát JPG-ből JPG-t csinál (a köztes állapot BMP).
Ha fontos a PNG, azt Te nyomozd ki.

procedure TForm1.Button1Click(Sender: TObject);
var Source: TJPEGImage;  Dest,Temp: TBitmap;
begin
  Source:=TJpegImage.Create;
  try
    Dest:=TBitmap.Create;
    try
      Temp:=TBitmap.Create;
      try
        Source.LoadFromFile('VALAMI.JPG');
        Source.DIBNeeded;
        Dest.Assign(Source);
        Temp.width:=100;
      Temp.height:=Round(Source.height*(Temp.width/Source.width));
        Temp.Canvas.StretchDraw(Rect(0,0,Temp.width,Temp.height), Dest);
        Source.Assign(Temp);
        Source.SaveToFile('PROBA.JPG');
      finally
        Temp.Free;
      end;
    finally
      Dest.Free;
    end;
  finally
    Source.Free;
  end;
end;

A "Temp.SetSize()" nálam nem működött, azért változtattam meg.
Olyan sok képformátumot NEM kezel a Delphi/Lazarus, tehát egy "általános" képkonvertáló program írására a fenti egyszerű módszerrel nem lehet messzire jutni.
Kép méretezésre jó lehet JPG, BMP esetén.

[ Szerkesztve ]

(#2136) Tomi_78 válasza vz12 (#2135) üzenetére


Tomi_78
tag

Köszönöm, ezt kipróbálom. Jó lenne, ha az átlátszóságot is tudná kezelni, mert az is fontos most.

(#2137) Tomi_78 válasza vz12 (#2135) üzenetére


Tomi_78
tag

Jó lett, csak átlátszóság nincs, hanem fekete keretben van a képecske. Akkor lehet, hogy azt nem is tudja kezelni? Ez a kódom:
procedure TForm1.Button2Click(Sender: TObject);
var tarolokep,kiskep: TBitmap;
  ujkep: TPortableNetworkGraphic;
begin
  if ListBox1.ItemIndex<>-1 then
  begin
     kiskep:=TBitmap.Create;
     ujkep:=TPortableNetworkGraphic.Create;
     tarolokep:=TBitmap.Create;
     ujkep.transparent:=true;
     kiskep.transparent:=true;
     tarolokep.transparent:=true;
     kiskep.Width:=strtoint(Edit1.Text);
     kiskep.Height:=strtoint(Edit2.Text);
     ujkep.LoadFromFile(mappa+ListBox1.Items.Strings[0]);
     tarolokep.assign(ujkep);
     kiskep.canvas.StretchDraw(rect(0,0,kiskep.width,kiskep.height),tarolokep);
     ujkep.assign(kiskep);
     ujkep.savetofile(mappa+'PROBA.png');
     kiskep.free;
     ujkep.free;
     tarolokep.free;
  end;
end;

(#2138) vz12 válasza Tomi_78 (#2137) üzenetére


vz12
tag

Itt van valami spéci megoldás Lazarus-ra (PNG): [link]

Ha a Lazarusban van "TPNGImage", az máris megoldhatja, a régebbi Delphi-kben ez külső library lehetőségként megvolt, az újabbakban talán már benne van.

Egyébként Google :), én sosem csináltam ilyet.

(#2139) Tomi_78 válasza vz12 (#2138) üzenetére


Tomi_78
tag

Végül megtaláltam erre az áttetszőséges gondra a megoldást, ugyanis hirtelen ötlettől vezérelve megnéztem a bitmélységét a forrásképnek és az elmentettnek, és az előbbinek 32, míg az utóbbinak csak 24 bit.
Ennek alapján ki kellett egészítenem a kódot ezzel a sorral:
ujkep.pixelformat:=pf32bit;
Az is fontos, hogy ez a kiegészítés a StretchDraw-ot tartalmazó sor elé kerüljön, különben ha utána tesszük, valamiért egy üres képet eredményez elmentve!
Úgy örülök, hogy sikerült megcsinálni, mert sok képszerkesztési munkától fog megkímélni ez a kis program, ha végül készen lesz. :DD

(#2140) vz12 válasza Tomi_78 (#2139) üzenetére


vz12
tag

> ujkep.pixelformat:=pf32bit;

Az előző válaszomban lévő első sorban a "spéci" linken lévő megoldásnak is ez a lényege.
Örülök, hogy örülsz, jó érzés megtalálni a megoldást egy problémára. :)

(#2141) Tomi_78 válasza vz12 (#2140) üzenetére


Tomi_78
tag

Bizony jó érzés, és még jobb végre elkészülni a programmal. Ez egy kis képszerkesztő, amivel egyszerre nagy mennyiségű képet lehet átméretezni és átnevezni. Talán másoknak is jól jöhet, ezért beillesztem ide a letöltési címét: [link]
És még egyszer, ezer köszönet a segítségért, Vz12! Bár a programfejlesztéssel ezzel nem állok le, sőt, vannak egyéb játékok és felhasználói programok még, amik megvalósításra várnak, ezért nem kizárt, hogy jövök még ide. :K

(#2142) Tomi_78


Tomi_78
tag

Sziasztok!
Valaki tud nekem segíteni abban a problémámban, hogy hogyan lehet átdefiniálni a programban a gombokat? Tehát most pl. a nyíl gombokkal irányítok, de szeretném, ha a felhasználó ezeket kedve szerint állíthatná be.
Hogy lehet a lenyomott gomb kódját eltárolni és felhasználni? Milyen adattípus kell hozzá?
Most VK_LEFT, VK_RIGHT, VK_UP és VK_DOWN van használatban.

(#2143) vz12 válasza Tomi_78 (#2142) üzenetére


vz12
tag

Hááát, szerintem a help-ben benne kellene lennie a kódoknak, vagy a Google is segít, pl. a "Delphi key codes" keresése után, rengeteg találat van.
Ha a numerikus kódokat saját szemeddel akarod látni, akkor pl. az OnKeyDown bemenő paramétereit írasd ki, ezeket el is tudod tárolni, mondjuk egy INI fájlban, majd később ezeket vissza is tudod olvasni, szövegből numerikus típussá alakítva vizsgálni is tudod. A régebbi Delphi-kben ez WORD típus, az újakban nem tudom. Kis/nagybetűkre figyelj.

[ Szerkesztve ]

(#2144) Tomi_78 válasza vz12 (#2143) üzenetére


Tomi_78
tag

Köszi, akkor megnézem azt a keresési feltételt és próbálkozom az OnKeyDown paramétereinek kiíratásával.

Copyright © 2000-2024 PROHARDVER Informatikai Kft.