C#, GDI+ ve UpdateLayeredWindow


C# ile Generic Clock

C# ile Generic Clock

Bir önceki yazımda Delphi ile GDI+ kütüphanesinin nasıl kullanılacağını açıklamaya çalışmıştım. Generic Clock bu konu hakkında yeterli olur sanırım. Daha detaylı bir örnek ise Hava Cıva! projesidir. Generic Clock projesini .NET platformunda da yapabilirsiniz aslında. İlgilenen arkadaşlar olabilir diye aynı projeyi bir de C# ile yazdım. Delphi ye göre fazla bir değişiklik yapmadan kolayca geçiş yapabilirsiniz. C# ile geliştirirken sadece Windows API fonksiyonlarının yazılması biraz can sıkabilir o kadar. Gerçi internette hazır birçok kod bulabilirsiniz. Ben üşenmedim ve belli başlı API fonksiyonlarını projeye import ettim. Windows.cs olarak proje dahil ettikten sonra gerisi çok kolay.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace GenericClock
{
internal class Windows
{
[DllImport("user32.dll", SetLastError = true)]
public extern static bool UpdateLayeredWindow(IntPtr handle, IntPtr hdcDst, ref Point pptDst, ref Size pSize, IntPtr hDc, ref Point pptSrc, int crKey, ref BlendFunction pBlend, int dwFlags);
[DllImport("user32.dll", ExactSpelling = false, SetLastError = true)]
public extern static long SetWindowLong(IntPtr handle, int index, IntPtr dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
public extern static IntPtr GetDC(IntPtr handle);
[DllImport("user32.dll", SetLastError = false)]
public extern static int ReleaseDC(IntPtr hWnd, IntPtr hDc);
[DllImport("user32.dll", SetLastError = false)]
public extern static bool ReleaseCapture();
[DllImport("user32.dll", SetLastError = true)]
public extern static int SendMessage(IntPtr handle, int msg, int wparam, int lparam);
[DllImport("gdi32.dll", SetLastError = true)]
public extern static IntPtr CreateCompatibleDC(IntPtr hDc);
[DllImport("gdi32.dll", SetLastError = true)]
public extern static bool DeleteDC(IntPtr hDc);
[DllImport("gdi32.dll", SetLastError = false)]
public extern static IntPtr SelectObject(IntPtr hDc, IntPtr hgdiObject);
[DllImport("gdi32.dll", SetLastError = true)]
public extern static bool DeleteObject(IntPtr hgdiObject);
public struct Point
{
public int X;
public int Y;
}
public struct Size
{
public int X;
public int Y;
}
public struct BlendFunction
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
public const byte AC_SRC_OVER = 0x00;
public const byte AC_SRC_ALPHA = 0x01;
public const int ULW_COLORKEY = 0x00000001;
public const int ULW_ALPHA = 0x00000002;
public const int WS_EX_LAYERED = 0x00080000;
public const int GWL_EXSTYLE = -20;
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_DRAGMOVE = 0xf012;
}
}

Projeyi Microsoft Visual Studio 2008 ortamında geliştirdim ve Target Framework' u .NET Framework 3.5 olarak seçtim. Ayrıca Microsoft Visual Studio 2010 ve .NET Framework 4.0 ile de denedim. Derleme ve çalışma sırasında hata oluşmadı. Gönül rahatlığı ile kullanabilirsiniz. Projenin içinde fonksiyonların kullanımı hakkında açıklamalar mevcut. Kaynak kodu incelemenizi şiddetle tavsiye ederim.

Generic Clock projesinin C# versiyonunu aşağıdaki linkten indirebilirsiniz.

generic-clock-csharp-source.rar [63 KB]

Etiketler: , , , , , , , , , , , , , , , , , ,

Yorumlar (2)

Delphi, GDI+ ve UpdateLayeredWindow


Delphi ile Generic Clock

Delphi ile Generic Clock

Son günlerde Delphi ve GDI+ ile ilgili oldukça mail almaktayım. Aslında uzun zamandır yazmak istediğim bir yazı bu. Yazının konusu Delphi bilen yazılımcı arkadaşları yakından ilgilendiriyor. Başlıktan da anlaşılacağı üzere Delphi ile GDI+ kullanımı hakkında. Geçen sene bir arkadaşımız bana mail göndermişti. Hava Cıva! kodunun karışık olduğunu söylüyodu. Hava Cıva! gibi bir arayüzün daha basit bir şekilde nasıl yapılacağını merak etmiş. Bende üşenmedim ona çok basit bir saat programı yazmıştım. Delphi ile temel GDI+ tekniklerinin nasıl kullanılacağını göstermiştim. İşte konumuz bu işlemin nasıl yapılacağını anlatıyor. Eğer Delphi biliyorsanız çok basit bir şekilde Hava Cıva! gibi bir arayüz tasarlayabileceksiniz. Hemen başlayalım...

Projenin adı Generic Clock. Adından da anlaşılacağı üzere temel bir saat projesi. Uygulama geliştirme ortamı olarak Delphi 7 kullandım. Ayrıca GDI+ kütüphanesi de gerekli bizim için. Gerçi projenin kaynak kodunda GDI+ kütüphanesi mevcut ama yine de orjinal kütüphaneyi indirmek isteyenler için adresi verelim: Delphi için GDI+ Kütüphanesi

1. TASARIM
Doğal olarak ilk önce ekran tasarımını yapmamız gerekiyor. Bunun için projenin ana formunda bazı değişiklikler yapılmalı. Bunlardan en önemlisi ana formun BorderStyle özelliğinin bsNone olarak ayarlanması. Neden mi? Widget (yada Gadget) tarzı arayüze sahip uygulamalarda pencerelerin kenarlı olması pek işimize yaramaz. Hatta işimizi daha da zorlaştırır. Bu uygulamada olduğu gibi zemin için bir resim seçeceğiz ve formumuzun zeminini seçtiğimiz resim ile kaplayacağız. Başlıksız ve kenarlıksız bir pencereye resmi uydurmak çok daha kolay olacaktır. Formun başlık bölümü olmadığına göre doğal olarak Kapat düğmeside olamıyor. Bu sorunu gidermek için formumuza bir Kapat düğmesi eklememiz gerekiyor. Bu düğmeyi ekledikten sonra bir StaticText ve bir de Timer bileşenin ekliyoruz. Son olarak pek önemli olmayan detaylar var. Örneğin ben ana formun Position özelliğini poScreenCenter olarak ayarladım. Ekranın ortasından başlasın diye. Diğer bileşenlerin boyutları ve konumları sizin isteğinize bağlı aslında. Ama örneğe sadık kalırsanız karışıklık olmadan anlayabilirsiniz. Tasarım kısmında hepsi bu. Tasarım için örnek bir resim aşağıda görüntüleniyor.

Delphi ile Generic Clock Tasarımı

Delphi ile Generic Clock Tasarımı

2. ALGORITMA
Bu bölümde GDI+ ile Delphi formlarının nasıl ilişkilendirileceğinden bahsedeceğim. İlk öğrenmemiz gereken kısım klasik GDI çizim tekniklerini formumuzda kullanamayacağımızdır. Eğer gölgeli, saydam ve şık bir arayüz istiyorsak GDI tarafından sağlanan araçlar işimizi görmez. En başta GDI' nin renk desteği zayıftır. Oysa GDI+ Alpha channel ile 32-bit renk desteği sağlar. Bu sayede saydam pencereler oluşturabiliriz.
Şimdi aklımızdan kesinlikle çıkarmamız gereken çok önemli bir kısma geldik: LayeredWindows! Katmanlı Pencereler olarak çevireceğiz bu terimi. Windows 2000 ile birlikte gelen bir pencere özelliğidir bu. Widget tarzı programların temelini oluşturur. Eğer formumuza katmalı pencere özelliği eklemezsek boşa uğraşmış oluruz. Peki nasıl yapacağız? O kısım oldukça kolay aslında. Formumuzun FormCreate olayına aşağıdaki kodu ekleyeceğiz.
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);Bu kodu ekledikten sonra diğer önemli bir kısımdan bahsetmek gerek. Microsoft MSDN' de belirttiği üzere "eğer pencereniz katmanlı olarak ayarlandıysa WM_PAINT mesajı oluşturulmaz!" MSDN' de bu yazıyı okuduktan sonra ne yapacağımı şaşırmıştım açıkçası. Windows'ta WM_PAINT mesajı oluşmuyorsa Delphi' de OnPaint olayı da oluşmaz! Bu karmaşayı aşmak için yine Windows API' den faydalanmamız gerekecek. Çözüm için UpdateLayeredWindow fonksiyonunu kullanacağız. Bu fonksiyon oldukça karışıktır. Benden söylemesi. Detaylı açıklamayı MSDN' den mutlaka okuyunuz (MSDN: UpdateLayeredWindow). Ben bu fonksiyonun nasıl kullanılacağını kaynak kod içinde gösterdim. UpdateLayeredForm yordamına bakmanız yeterlidir.
procedure TForm1.UpdateLayeredForm;
var
SrcDC, DestDC: HDC;
BitmapHandle, PrevBitmap: HBITMAP;
BlendFunc: _BLENDFUNCTION;
Size: TSize;
P, S: TPoint;
begin
{ Desktop ile uyumlu bir DC olustur. (Yada 0 yerine GetDesktopWindow yazabiliriz) }
SrcDC := CreateCompatibleDC(0);
{ Olusturdugumuz DC ile uyumlu yeni bir DC daha olusturmaliyiz. Kopyalama icin. }
DestDC := CreateCompatibleDC(SrcDC);
{ Cizim yaptigimiz resmin Windows tarafidan anlasilan HBITMAP turunden degiskene ata. }
{ Bu kisim onemli. Cizim yaptigimiz resmi gercek dunyaya getiriyoruz. }
{ BitmapHandle degiskeni artik Windows tarafindan kullanilanilabilir duruma geldi. }
FBitmap.GetHBITMAP(0, BitmapHandle); { 0 = Background transparent, out BitmapHandle }
{ SrcDC de bitmap secilmeli }
PrevBitmap := SelectObject(SrcDC, BitmapHandle);
{ Boyutlar ve konum }
Size.cx := Width;
Size.cy := Height;
P := Point(Left, Top);
S := Point(0, 0);
with BlendFunc do
begin
BlendOp := AC_SRC_OVER;
BlendFlags := 0; { Sifir olmali }
SourceConstantAlpha := FOpacity; { Ana formun donukluk degeri. 0 = tam saydam, 255 = tam donuk. }
AlphaFormat := AC_SRC_ALPHA;
end;
{ Microsoft'un sihirli fonksiyonu! Oylesine onemli ki, aslinda butun kiyamet burada kopuyor. }
{ Detayli aciklamayi MSDN' den mutlaka okuyunuz. http://msdn.microsoft.com/en-us/library/ms633556(VS.85).aspx }
UpdateLayeredWindow(Handle, DestDC, @P, @Size, SrcDC, @S, 0, @BlendFunc, ULW_ALPHA);
{ SrcDC yi eski haline getir. }
SelectObject(SrcDC, PrevBitmap);
{ ve Bitmap'i yok et. Yoksa hafiza sizmasi olur. }
DeleteObject(BitmapHandle);
{ DC leri yok et. }
DeleteDC(DestDC);
DeleteDC(SrcDC);
end;
Karmaşa hala devam ediyor... Madem windows bizim için WM_PAINT olayını oluşturmuyor o zaman bizim elle bu olayı tetiklememiz gerekiyor! Kendinizi resim yapıyor gibi düşünün. Önce zemini çizeceğiz sonra diğer bileşenleri vs. Böylelikle oluşan resmi formumuzda göstereceğiz. Mantık basit: Resmi çiz (RepaintForm) ve ekranda güncelle (UpdateLayeredForm).
Örneğin bu projede saati saniye saniye ekranda göstermemiz gerekiyor. Bu durumda her saniye form alanını güncellemeliyiz. Bunun için Timer bileşeninden faydalanacağız.
procedure TForm1.Timer1Timer(Sender: TObject);
begin
{ Her saniye form alanini yeniden cizmek zorundayiz. }
RepaintForm;
{ Ayrica cizdigimiz form alanini guncellemeliyiz. }
UpdateLayeredForm;
end;

Bu proje hakkında yazacaklarım şimdilik bu kadar. Widget tarzı programlarda can alıcı noktaları açıklamaya çalıştım. Projenin kaynak kodunu aşağıdaki linkten indirebilirsiniz.

generic-clock-source.rar [290 KB]

Etiketler: , , , , , , , , , , ,

Yorumlar (3)

Ruffles’ın Kazandıran En Kestirme Oyunu Bu Sitede Başlıyor


Dijital dünyada ilklere imza atmaktan sıkılmayan Ruffles, yine Türkiye’de ilk olan bir kurguya imza atmış. Eğlenceli bir ev partisi ile başlayan hikayede tanıştığımız güzel bir kızı elde tutmak için oldukça yoğun çaba harcıyoruz. Hikayeye dahil olmak için videoyu izlemeniz yeterli…

Özellikle Esra ve Ceyda kardeşler ile olan sahneler ve sürpriz sonu oldukça dikkat çekici olan kampanyada cep telefonu numaranızı verdiğiniz anda bedava 60 dakika ve 100 mb internet kazanılabiliyor. Esra ve Ceyda’nın aradığı numarayı her geri arayışınızda ise farklı bir sohbet sizi karşılıyor.

Oyunun en büyük özelliği ise tek bir mecrada değil birden çok mecrada birden oyunun oynanabilmesi! Nasıl bir hikaye seçeceğiniz ise size kalmış!

Benden de size bir kolaylık: Oyuna en kestirmeden bu linkten ulaşabilirsiniz: http://apps.facebook.com/enkestirmeruffles/


Bir bumads advertorial içeriğidir.

Yorum Yapın

Sayfa: << 1 2 3 ...7 8 9 10 11 ...34 35 36 >>