Delphi programozás - Szoftverfejlesztés fórum

üzenetek

hozzászólások


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;


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?


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.


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.


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.


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ó?


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.
:)


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?


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...


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;


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 ]


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;


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 ]


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;  


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 ]


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.


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;


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.


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


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. :)


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


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.


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 ]


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.


Tomi_78
(tag)

Sziasztok!
Készülő programomban van egy ScrollBox, azon pedig egy TImage kép (terepVaszon néven). Erre a TImage-re szeretnék még rajzolni rácsvonalakat, de úgy, hogy ne legyenek a TImage részei, mert később a rácsvonalak nélkül szeretném elmenteni és a rácsvonalak mutatása ki/bekapcsolható legyen.
Mindennek megvalósítására létrehozok még egy TImage-et (tvracskep néven), amelynek a ScrollBox a szülője, hogy azon helyezkedjen el, és a TImage vásznához hozzárendelek egy BitMap képet, amelyen a rácsok rajzolása megtörtént.
Ki is rajzolódik a rács, de mindig egy fekete háttéren, amit sehogy nem bírok eltüntetni, és így nem látszik az alatta levő kép.
Lehetséges egyáltalán egy képen rajzolni valamit úgy, hogy a rajzkép áttetsző legyen a nem használt részein? Ha igen, hogyan?
Itt a teljes kód, amit írtam:
procedure TForm1.racsmutatoGombMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var bm: TBitmap;
  vszvonalhely,fugvonalhely: word;
begin
  if tvracsmutat=true then
  begin
     tvracsmutat:=false;
     if vantvracs=true then
     begin
       FreeAndNil(tvracskep);
       vantvracs:=false;
     end;
  end
  else
  begin
    tvracsmutat:=true;
    if vantvracs=false then
    begin
      tvracskep:=TImage.Create(tvScrBox);
      tvracskep.Parent:=tvScrBox;
      tvracskep.Left:=0;
      tvracskep.Top:=0;
      tvracskep.width:=terepVaszon.width;
      tvracskep.height:=terepVaszon.Height;
      tvracskep.Transparent:=true;
      bm:=TBitmap.Create;
      bm.width:=terepVaszon.width;
      bm.height:=terepVaszon.Height;
      bm.PixelFormat:=pf32Bit;
      bm.Transparent:=true;
      bm.Mask(clBlack);
      fugvonalhely:=csempeszel;
      vszvonalhely:=csempemag;
      bm.canvas.pen.color:=clBlue;
      while fugvonalhely<terepVaszon.width do
      begin
          bm.canvas.line(fugvonalhely,0,fugvonalhely,terepVaszon.height);
          inc(fugvonalhely,csempeszel);
      end;
      while vszvonalhely<terepVaszon.height do
      begin
          bm.canvas.line(0,vszvonalhely,terepVaszon.width,vszvonalhely);
          inc(vszvonalhely,csempemag);
      end;
      tvracskep.picture.graphic:=bm;
      tvracskep.picture.graphic.transparent:=true;
      FreeAndNil(bm);
    end;
    vantvracs:=true;
  end;
end;

üzenetek