4 Temmuz 2013 Perşembe

Windows XP Stillerinin Kontrollere Uyarlanması

Herşeyden önce bu isteğimizi gerçekleştirmek için isteğimizi uygulayacağımız bir sınıfa sahip olmamız gerekir. Ne yazık ki standart ProgressBar sınıfı “sealed” olduğu için ben sınıfımı Control sınıfından türettim:

public class XPProgressBar:Control
{
}
Daha sonra yapmamız gereken standart ProgressBar özelliklerini (Maximum, Minimum, Value, Step) özelliklerini sınıfımıza uygulamaktır. Bu özelliklerin hepsi integer’dir. Kolay olduğu için bu kısmı geçiyorum. Dikkat edilmesi gereken nokta Value özelliğine bir değer geçerken sınıf örneğimizin yeniden boyanmasını sağlamaktır. Bunu da Refresh() fonksiyonu ile yapabiliriz. Uygulamamızın amacı XP sitillerinin uygulanması olduğu için Style isminde bir özellik tanıtırız. Bu özellik Normal ve System isimlerinde iki enum değeri tutar. Eğer özelliğimizin değeri System ise XP sitili uygulanır.

public Styles Style
{
get {<return FStyle;}
set
{
FStyle=value;
Refresh();
}
}
Şimdi sınıfımızın boyanması için OnPaint metoduna geçebiliriz. İlkönce Normal değerini görelim.
<SPANSTYLE16739" ?? New="FONT-SIZE:9PT;COLOR:BLUE;FONT-FAMILY:'COURIER

designtimesp="protected<SPANSTYLE16740" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" override void OnPaint(PaintEventArgs e)
{
<SPANSTYLE16749" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" Rectangle rect = ClientRectangle;
<SPANSTYLE16753" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" rect.Width-=6;
<SPANSTYLE16757" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" rect.Height-=6;
<SPANSTYLE16761" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" if(Maximum!=Minimum)
{
rect.Width =(Value-Minimum)*100/(Maximum-Minimum)*rect.Width/100;
}
<SPANSTYLE16778" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" if(Style==Styles.Normal)
{
ControlPaint.DrawBorder3D(e.Graphics,ClientRectangle,Border3DStyle.Sunken);
<SPANSTYLE16794" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" rect=new Rectangle(new Point(rect.X+3,rect.Y+3),rect.Size);
<SPANSTYLE16800" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" e.Graphics.FillRectangle(Brushes.Blue,rect);
}
else
{
//Burada Styles.System değerini uygulayacağız.
}
}
Yukarıdaki kodda yapılan Maximum ve Minimum değerlerine göre boyanacak alanın bulunup daha sonra boyanmasıdır. Dikkat edeceğiniz gibi segment şeklinde değil de düz boya şeklinde boyanmıştır. Eğer isterseniz bu aşamada bileşenimizi test edebilirsiniz.
Dikkat edeceğiniz gibi standart bir ProgressBar’ın yapacağı işlemleri gerçekleştirdik. Şimdi asıl amacımız XP sitillerinin uygulanması olduğuna göre bu aşamaya geçelim.
Öncelikle kullandığımız işletim sisteminin yapacağımız bu işlemi desteklemesi için Windows XP olması lazım. Bunu nasıl anlayacağımızı görelim:
<SPANSTYLE16846" ?? New="FONT-SIZE:9PT;COLOR:BLUE;FONT-FAMILY:'COURIER

designtimesp="bool<SPANSTYLE16847" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" IsThemedos()
{
if(Environment.OSVersion.Platform != PlatformID.Win32NT
<SPANSTYLE16859" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" || Environment.OSVersion.Version.Major < 5
<SPANSTYLE16863" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" || Environment.OSVersion.Version.Minor < 1)
<SPANSTYLE16867" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" return <SPANSTYLE='COLOR:BLUE'false;
<SPANSTYLE16873" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp="
<SPANSTYLE16876" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" return <SPANSTYLE='COLOR:BLUE'true;
}
Yukarıdaki fonksiyonda yapılan kullanılan işletim sisteminin version numaralarına bakarak Windows XP olup almadığını anlamaktır. Eğer değilse program XP sitillerinin kullanımına izin vermeyecektir.
Şimdi burada bir ara verip XP sitillerinin kullanımına olanak veren WinApi leri tanıtmak istiyorum. Öncelikle kullanacağımız dll “UxTheme.dll” dir. Bizim bu programda kullanacağımız 4 tane WinApi fonksiyonu var. Şimdi bunları tanıyalım:
HTHEME OpenThemeData( HWND hwnd,LPCWSTR pszClassList);
Bu fonksiyon bir window için ilgili sınıfın datasını açar. Dönüş değeri IntPtr dir. “pszClassList” parametresi ise kullanacağımız sınıfın string değeridir. Bizim örneğimizde bu değer "PROGRESS" dir.
BOOL IsAppThemed(VOID);
Bu Api bir kontrol fonksiyonudur. uygulamamızın visual sitilleri uygulayıp uygulamayacağını sorgular.
BOOL IsThemeActive(VOID);
Bu da başka bir kontrol fonksiyonudur. Visual sitillerin uygulamamız için aktif olup olmadığını denetler.
HRESULT DrawThemeBackground(     
    HTHEME hTheme,
<SPANSTYLE='FONT-SIZE:12PT'    HDC hdc,
<SPANSTYLE='FONT-SIZE:12PT'    int iPartId,
<SPANSTYLE='FONT-SIZE:12PT'    int iStateId,
<SPANSTYLE='FONT-SIZE:12PT'    const RECT *pRect,
<SPANSTYLE='FONT-SIZE:12PT'    const RECT *pClipRect
<SPANSTYLE='FONT-SIZE:12PT');
Uygulamamızın belki de en can alıcı Api si budur. Bu fonksiyonla visual sitillerin çizim işlemini gerçekleştiriyoruz. Dönüş değeri integer dir. Parametrelerine gelince:
hTheme: OpenThemeData fonksiyonu ile elde ettiğimiz IntPtr değerini kullanacağız.
hdc: Controlümüzün hdc değeri. <SPANSTYLE16960" ?? New="FONT-SIZE:10PT;FONT-FAMILY:'COURIER designtimesp="CreateGraphics().GetHdc() ile elde edilir.
iPartId ve iStateId: Bu parametreler çizeceğimiz kontrolün bölümlerini ifade eder. Visual Studio nun yardım indeksi bölümüne “Parts and States” yazarsak konuyla ilgili dökümanı bulabiliriz. Bu durumda Controlümüzün arkaplanını çizeceksek iPartId 1 değerini, eğer öndeki ilerleme bölümünü çizeceksek 3 değerini almalıdır. StateId değeri ise ProgressBar için kullanılmaz. Eğer dökümanı iyice incelersek yapacağımız diğer uygulamalarda XP sitillerini nasıl uygulayacağımız kolaylıkla anlaşılır.
pRect ve pClipRect: <SPANSTYLE='MSO-SPACERUN:YES' Bu parametreler <SPANSTYLE='MSO-SPACERUN:YES' çizeceğimiz dörtgen bölümü ifade eder. ClipRect “null” değerini alabilir.
Şimdi programımıza geri dönüp anlattığımız Api lerin kullanımına geçebiliriz. Öncelikle sınıfımızın yapıcısında <SPANSTYLE='MSO-SPACERUN:YES' OpenThemeData apisini kullanarak XP sitilimizin değerini tutabilirz. Daha sonra sınıfımızın OnPaint metodunda boş bıraktığımız “else” ifadesini dolduralım.
<SPANSTYLE16974" ?? New="FONT-SIZE:9PT;COLOR:BLUE;FONT-FAMILY:'COURIER

designtimesp="if<SPANSTYLE16975" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp="(IsThemedos() && IsAppThemed() && IsThemeActive())
{
DrawThemeBackground(e.Graphics,1,1,ClientRectangle);
DrawSystemSegments(e.Graphics,rect);
}
<SPANSTYLE16994" ?? New="FONT-SIZE:9PT;COLOR:BLUE;FONT-FAMILY:'COURIER

designtimesp="private<SPANSTYLE16995" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" void DrawSystemSegments(Graphics g, Rectangle rc)
{
int segwidth = 8;
<SPANSTYLE17008" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp="
<SPANSTYLE17011" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" int Count = ((rc.Width)/(segwidth+2))+((rc.Width<=0)?0:1);
<SPANSTYLE17016" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp="
<SPANSTYLE17019" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" Rectangle rect = new Rectangle(3,3,Count*(segwidth+2),rc.Height);
<SPANSTYLE17024" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" if (rect.Width>(Width-2*3))
{
<SPANSTYLE17033" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" rect.Width = rc.Width;
<SPANSTYLE17038" ?? New="FONT-SIZE:9PT;FONT-FAMILY:'COURIER

designtimesp=" }

DrawThemeBackground(g,3,1,rect);
}
Öncelikle kontrolümüzün arka planını çizdik. Daha sonra DrawSystemSegments fonksiyonu ile segmentleri hesaplayıp sonra da bunu çizdirdik.


Hiç yorum yok:

Yorum Gönder