Friday, April 25, 2008

Jak vidíte, ještě než dojde k samotnému testování a případnému přesouvání (přichycování) okna, uloží se nejprve původní rozměry okna, které jsou na konci celé procedury opět na okno aplikovány. Kdyby jsme to neudělali, okno by mělo tendenci během přichycování či "odtrhávání" od okraje plochy měnit svoje rozměry.
Příklad je tedy velmi jednoduchý a jistě sami přijdete na mnohá zlepšení. Určitě by se například slušelo uložit hodnoty tolerance okrajů do konstant pro snadnější modifikaci. Další drobná vada, kterou byste časem jistě objevili, je to, že pokud změníte polohu nabídky Start až po spuštění aplikace, nebude se k menu přichytávat správně. To je celkem samozřejmé, protože rozměry plochy zjišťujeme v události OnCreate. Pokud by tedy přichytávání mělo být ještě o něco dokonalejší, museli bychom hlídat i případnou změnu polohy nabídky Start (či její automatické schovávání) a také rozlišení obrazovky. Ale to již ponechám na vašem uvážení a každý jistě zvládne úpravu kódu tak, jak bude potřebovat.

Saturday, April 19, 2008

Kromě samotné procedury, která hlídá pohyb okna, ještě přidáme do programu jeden krátký řádek kódu do události OnCreate formuláře. Ten zjistí rozměry pracovní plochy, abychom věděli, jestli se okno aplikace přiblížilo k okraji nebo ne. Zároveň se tím vyřeší i "problém" s nabídkou Start a bez ohledu na to, na kterém okraji plochy ji máte umístěnu a zda máte nastaveno automatické schovávání, okno naší aplikace se k ní stejně přichytí.
Celý kód jednoduchého formuláře, který se přichycuje k okrajím plochy, tedy vypadá takto:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;

type
TWMMoving = record
Msg: Cardinal;
Side: Longint;
Coord: PRect;
Unused: longint;
end;

TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure WMMoving(var Message: TWMMoving); message WM_MOVING;
public
{ Public declarations }
Desktop: TRect;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.WMMoving(var Message: TWMMoving);
var
OriginalWidth, OriginalHeight: integer;
begin
OriginalWidth := Width;
OriginalHeight := Height;
if (WindowState = wsNormal) and Visible then
begin
if (Message.Coord.Left < (Desktop.Left + 10)) then Message.Coord.Left := Desktop.Left;
if (Message.Coord.Top < (Desktop.Top + 10)) then Message.Coord.Top := Desktop.Top;
if (Message.Coord.Bottom > (Desktop.Bottom - 10)) then Message.Coord.Top := Desktop.Bottom - Height;
if (Message.Coord.Right > (Desktop.Right - 10)) then Message.Coord.Left := Desktop.Right - Width;
end;
Message.Coord.Right := Message.Coord.Left + OriginalWidth;
Message.Coord.Bottom := Message.Coord.Top + OriginalHeight;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
SystemParametersInfo(SPI_GETWORKAREA, 0, @Desktop, 0);
end;

end.

Wednesday, April 09, 2008

Tipy a triky v Delphi

Tipy a triky v Delphi,

Dnes budeme přichytávat okno formuláře k okrajím pracovní plochy. Tato funkce se stává poměrně oblíbeným vylepšením uživatelského prostředí řady programů a proto si ukážeme, jak na to.
Věřím, že jistě všichni víte, o čem je vlastně řeč. Mnoho programů (namátkou třeba populární Winamp) umožňuje uživateli nastavit, že když přesouváte okno aplikace po pracovní ploše a přiblížíte se k některému okraji, okno aplikace se automaticky "přichytí" k tomuto okraji. Pokud tedy chce uživatel umístit okno například do pravého horního rohu pracovní plochy, nemusí se složitě strefovat a má práci velmi usnadněnou. Přesně touto funkcí se dnes budeme zabývat.
Celá věc se dá udělal různými způsoby (jako ostatně většina věcí), ale jako obvykle jsem se snažil o pokud možno co nejjednodušší a také nejkratší kód. Slovní popis celého principu je poměrně logický a jasný. Sledujeme pohyb okna (prostřednictvím zpráv systému) a když se okno přiblíží k některému z okrajů plochy na námi definovanou vzdálenost (v našem případě je to 10 bodů), posuneme okno tak, aby se daného okraje dotýkalo (přichytíme jej).

Monday, April 07, 2008

procedure TForm1.FileListBox1Change(Sender: TObject);
begin
Label1.Caption := '';
Label2.Caption := '';
Label3.Caption := '';
Label4.Caption := '';
Label5.Caption := '';
if FileListBox1.FileName <> '' then
begin
ReadWAV(FileListBox1.FileName, soubor);
if HeaderOK(soubor) then
begin
Label1.Caption := 'Hlavička souboru v pořádku - soubor rozpoznán';
case Soubor.FormatID of
1: Label2.Caption := 'Windows PCM';
2: Label2.Caption := 'Microsoft ADPCM';
6: Label2.Caption := 'A-LAW';
7: Label2.Caption := 'MU-LAW';
17: Label2.Caption := 'DVI/IMA ADPCM';
85: Label2.Caption := 'MPEG Layer III';
else
Label2.Caption := 'Neznámý formát';
end;

case Soubor.ChannelNumber of
0: Label3.Caption := 'Neznámý typ';
1: Label3.Caption := 'Mono';
2: Label3.Caption := 'Stereo';
end;

Label4.Caption := IntToStr(Soubor.BitsPerSample) + ' bit';
Label5.Caption := IntToStr(Soubor.SampleRate) + ' Hz';
end
else
Label1.Caption := 'Hlavička souboru není v pořádku - soubor nerozpoznán';
end;
end;
A to je pro dnešek vše. V některém z příštích dílu se určitě také podíváme na další zvukové formáty jako třeba MP3. Tento díl je zároveň první, ve kterém jsem se pokusil na základě reakcí některých čtenářů zlepšit čitelnost kódu zvýrazněním klíčových slov. Pokud vaše ohlasy budou kladné, začneme s tím od příště natrvalo.

Wednesday, April 02, 2008

except
Result := false;
end;
end;
Ještě než se dostaneme k samotnému zpracování načtených dat a jejich zobrazení, vytvoříme si jednoduchou funkci, která nám otestuje hlavičku souboru a zjistí, zda je platná či ne a jestli má tím pádem smysl, pokoušet se vypisovat nějaké informace. Funkci pak poté využijeme v další části kódu.
function HeaderOK(const WAVData: WAVRecord): Boolean;
begin
Result := true;
if WAVData.RIFFHeader <> 'RIFF' then Result := false;
if WAVData.WAVEHeader <> 'WAVE' then Result := false;
if WAVData.FormatHeader <> 'fmt ' then Result := false;
if (WAVData.ChannelNumber <> 1) and (WAVData.ChannelNumber <> 2) then Result := false;
end;
A teď už se konečně dostáváme k výpisu informací na obrazovku. Jak jsme si řekli na začátku, výpis bude součástí události OnChange komponenty FileListBox. Když se podíváte na strukturu načítaných dat na začátek článku a porovnáte s těmi daty, které vypisujeme, jistě vidíte, že jsme nepoužili všechny možnosti, ale nechtěl jsem ukázku příliš prodlužovat. Myslím, že struktura záznamu je svými názvy dostatečně popsána a tak pro vás nebude problém vypsat i další informace. Proto jsou v našem příkladu převážně ty údaje, které jsou vlastně konstantami (a asi by se slušelo je jako konstanty nadefinovat, tak promiňte to zjednodušení). Vše ostatní již z názvů v záznamu pochopíte.