TP

WinForms - Screensaver a kreslení pomocí GDI+

Co tento článek ukazuje

Screensaver v akci

Screensaver s červíky

V tomto článku vytvoříme screensaver na kterém se budou po obrazovce pohybovat "červíci". Červík je objekt který má barvu a pozici a oboje se může měnit. Červík se v každém kroku nakreslí (jako kruh) a posune se. Po nakreslení se ještě smaže část okna a to tak, že se přes okno nakreslí na náhodá místa několik černých kružnic, které tak smažou dříve nakreslené červíky. Pomocí objektového návrhu vytvoříme dva různé typy červíka a každý se bude chovat jinak, ale v hlaní aplikaci s nimi bude možné pracovat stejným způsobem (takže by nebyl problém přidat například třetí typ).

Jak funguje screensaver?

Screensaver je obyčejný spustitelný soubor, jenom má místo připony exe příponu scr. Program se spouští několika různými způsoby, podle toho co chce uživatel dělat a tento způsob je aplikaci předán jako parametr příkazové řádky. Pokud se screensaver normálně spouští je na příkazové řádce předán parametr /s. Při kliknutí na tlačítko "Nastavení" je screensaveru předán parametru /c. Poslední parametr a to /p je aplikaci předán když se má kreslit náhled (v nastavení screensaveru ve windows).

(Zpracování posledního parametru vyžaduje znalost WinAPI, takže se jím zde nebudeme zabývat, nicméně kód který jej obsluhuje naleznete například v aplikaci [1])

static void Main(string[] args) 
{
  if (args.Length==0||args[0].StartsWith("/s"))
    // Spustit screensaver
  else if (args[0].StartsWith("/c"))
    // Nastaveni screensaveru
  else if (args[0].StartsWith("/p")) 
    // Vykreslovani nahledu
}

Po spuštění screensaveru je také potřeba, aby hlavní formulář aplikace zabral prostor celé obrazovky. Nejsnadnější způsob jak toho dosáhnout je vytvořit maximalizovaný formulář bez okrajů (a také je třeba skrýt ukazetel myši).

// Bez okraje, maximalizovany a skryt mys
FormBorderStyle=FormBorderStyle.None;
WindowState=FormWindowState.Maximized;
Cursor.Hide();

Objektový návrh aplikace

Pomocí objektově orientovaného programování je možné snadno vytvořit několik typů "červíka", se kterými bude aplikace moci pracovat stejným způsobem, ale jednotlivé objekty se budou chovat odlišně (v OOP terminologii se toto nazývá polymorfismus). Vytvoříme si nejprve bázovou třídu Cervik, která bude obsahovat to co je pro všechny červíky společné a poté vytvoříme třídy CervikJedna a CervikDva, které budou odvozené od bázové třídy a budou do ní doplňovat specifické chování (pohyb a změnu barvy). Objekty pro práci s červíky jsou graficky znázorněné na následujícím diagramu:

Diagram tříd
// Bazova trida - Zdedene tridy
// musi doplnit zmenu pozice a barvy public abstract class Cervik { // Pozice, velikost a barva protected Point Position; protected Size Size; protected Color CurrentColor; #region Abstraktni metody // musi byt implementovane v odvozene tride
// Tato metoda meni pozici a velikost cervika // - parametry width a height urcuji velikost okna // (aby cervik nevylezl mimo obrazovku)
protected abstract void ChangePosAndSize(int width,int height); // Tato metoda meni barvu cervika - protected abstract void ChangeColor(); #endregion // Kresli cervika a zavola virtualni // metody na posunuti a zmenu barvy public void DrawFrame(Graphics gr,int width,int height) { // kresleni (bude popsano pozdeji)... // zmenit pozicic a barvu ChangePosAndSize(width,height); ChangeColor(); } }

Pro kompletní zdrojový kód se podívejte do přiloženého zdrojového kódu.

Třída Cervik obsahuje dvě abstraktní virtuální metody (virtuální znamená, že je možné měnit její chování a abstraktní znamená, že ve třídě Cervik nemá žádné tělo). Tyto dvě metody jsou volány z DrawFrame, protože v odvozených třídách již budou tyto metody implementované a bude tedy možné je volat. Pomocí těchto dvou metod dáváme najevo co je potřeba v odvozených třídách doplnit za chování aby "červík" mohl fungovat tak jak má. Jakmile tedy při psaní odvozených tříd doplníme tyto dvě metody, získáme funkčního "červíka" a nebude nutné znovu psát metodu DrawFrame, která obsatrává kreslení na obrazovku (které bude vždy stejné).

// Prvni cervik - Ukazuje jak vytvorit funkcniho cervika
public class CervikJedna : Cervik
{
  // Implementace zmeny pozice
  protected override void ChangePosAndSize(int width,int height)
  {
    // TODO: Zmenit pozici cervika
    Position.X+=1;
    Position.Y+=1;
  }

  // Implementace zmeny barvy
  protected override void ChangeColor()
  {
    // TODO: Zmenit barvu cervika
    CurrentColor=Color.Red;
  }
}

Kompletní kód opět hledejte v přiloženém souboru.

Jak jsem již psal, je možné tímto způsobem vytvořit několik různě se chovajících tříd, které se ale mohou tvářit jako základní třída Cervik. Tímto způsobem je také možné s třídami pracovat, takže při vytváření formuláře uložíme různé typy červíků v poli a při kreslení již budeme volat kreslení červíka aniž bychom věděli se kterou třídou pracujeme.

// Do pole cerviku lze dat ruzne typy
Cervik[] cervici=new Cervik[2];
cervici[0]=new CervikJedna();
cervici[1]=new CervikDva();

// Ale pri kresleni s nimi lze pracovat jednotne
foreach(Cervik worm in cervici)
  worm.DrawFrame(gr,width,height);

Kreslení červíků

V článku jsem zatím nezmínil jak funguje samotné kreslení na obrazovku, takže je na čase to napravit. Vzhledem k tomu, že se jedná o screensaver (se stále se měnícím obsahem) je potřeba kreslit na obrazovku co nejčastěji, proto je upravená metoda Main tak, aby se stále v cyklu volala metoda obstarávající kreslení. Pro samotné kreslení je nejprve potřeba získat objekt Graphics pro kreslení na hlavní formulář. K tomu slouží metoda CreateGraphics. Tento objekt je také po dokončení kreslení nutné uvolnit (a to zavoláním metody Dispose). K tomuto slouží v C# konstrukce using:

using(Graphics gr=CreateGraphics())
{
  // Zde se provede kresleni...
} // Po opusteni bloku using se vola gr.Dispose()

Samotné kreslení červíků je poměrně jednoduché, protože se kreslí pouze kružnice různých barev (při kreslení červíka) a nebo černé kružnice při mazání. Při kreslení barevných kružnic je nejprve potřeba vytvořit Brush (štětec) dané barvy pomocí kterého se bude kreslit. Tento objekt má metodu Dispose, kterou je nutné po dokončení kreslení zavolat (u objektů na kreslení je většinou nutné volat Dispose, protože tyto objekty je potřeba uvolnit co nejdříve). Kreslení barevné kružnice vypadá tedy takto:

// kresli na aktualni pozici pomoci aktualni barvy
using(Brush br=new SolidBrush(CurrentColor))
{
  // Vykresli se kruznice se stredem v bode
  // Positon a velikosti urcenou pomoci Size
  gr.FillEllipse(br,Position.X-Size.Width/2,
    Position.Y-Size.Height/2,Size.Width,Size.Height);
}

Soubory na stažení a odkazy

Published: Monday, 11 April 2005, 9:29 PM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: