Döviz.NET: C# ile Online Döviz Programı
Kategori C#, Döviz.NET, Genel, Programlama, Oluşturulma Dec.22, 2011
Uzun zamandır öğretici bir makale yazamadım. Özellikle C# ile Widget yada Gadget tarzı program geliştirme konusunda oldukça fazla mail aldım. Aslında önceki yazılarımda bu konuya açıklık getirmeye çalışmıştım ama sanırsam bazı sıkıntılar olmuş. Elimden geldiğince bu sorunları gidermeye çalışacağım. Projenin adını Döviz.NET olarak seçtim. Adından anlaşılacağı üzere masaüstü için online döviz takip programı. Tabiki şimdilik sadece Dolar ve Euro bilgisini ekrana getirebiliyor. Projenin öğretici olması amacıyla karmaşadan uzak kalmaya çalıştım. Zaten amacım tam teşekküllü program yazmak değil, temel bazı ipuçları vermek. Başlayalım...
1. TASARIM
Döviz.NET projesini Microsoft Visual Studio 2008 ile .NET FrameWork 3.5 temel alarak geliştireceğiz. Tasarım aşaması oldukça basit. Normal bir Windows Form tasarımı ile aynı. Buradaki amacım daha az kod yazarak işimizi kolaylaştırmak. Malum C#, GDI+ ve UpdateLayeredWindow başlıklı yazımda tasarım kısmına pek değinememiştim. Kod kısmı fazla olduğu için anlaşılmasında sıkıntı yaşanmış. Zaten bu yazının amacıda bu karmaşayı gidermek. Aşağıda resimde tasarım aşamasından bir ekran görüntüsü mevcut. Bu formu normal bir form tasarımı yapar gibi yapabilirsiniz. Form üzerindeki resimler için PictureBox bileşenini, yazılar için ise Label bileşenini kullandım. Burada en önemli kısım formun başlık kısmının kaldırılması. Bu işlem için formun FormBorderStyle özelliğini None olarak ayarlamalıyız. Widget tarzı programlarda pencere başlığı bizim için zorluk çıkartır. Çalışma alanımızda ekstra bir çizim istemiyoruz. Gereken tüm çizimleri kendimiz halledeceğiz. Dikkat edilmesi gereken bir konuda şu: Form tasarımında resimlerin ve etiketlerin görüntüsü çalışma zamanındaki ile farklı. Özellikle bileşenlerin zemin kısımlarına dikkate edin. Hiçbiri saydam (transparent) değil. Tüm bileşenlerin zeminleri kendi backColor rengi ile doldurulmuş. Tabiki bu istemediğimiz bir durum. Bu sorunun sonraki aşamada nasıl giderileceğinden bahsedeceğim. Tabiki kod yazarak...
2. KOD
Asıl zevkli kısma geldik... Önceki yazılarımda bahsettiğim gibi ilk önce temel felsefeyi anlamamız gerekiyor: Normalde tasarım yaptığımız bir Windows formunu Run ettiğimizde ekstra bir çizim yapmadan görüntüyü elde ederiz. Çünkü işletim sistemi gereken tüm çizimleri bizim için yapar. Örneğin formumuzun zemini o anki sistem renklerine bağlı olarak dikdörtgen şeklinde çizilir. Oysa biz daha yumuşak ve kıvrımlı bir görüntü elde etmek isteyebiliriz. Mesela PhotoShop' ta tasarlanmış parıldayan top şekli yada kenarları yuvarlatılmış gölgeli (drop shadow) bir çerçeve. Ekranda oldukça şık dururdu değil mi? Şunu unutmayın ki Widget tarzı programlarda pencere yapısı klasik pencerelerden farklıdır. Bu tip pencerelere Layered Windows denir. Katmanlı Pencere olarak çevirebiliriz dilimize. Windows 2000 ile birlikte kullanılmaya başlanan bir özellik bu. Normal bir pencerenin ExStyle özelliğine WS_EX_LAYERED değerini ekleyerek elde edilir. Böylece sisteme oluşturduğumuz pencerenin katmanlı olduğunu bildiriyoruz. Kod kısmı en basit olarak şöyle yazılabilir:
long style = CreateParams.ExStyle;
style |= Win32.WS_EX_LAYERED;
Win32.SetWindowLong(this.Handle, Win32.GWL_EXSTYLE, (IntPtr)style);
Yukarıdaki kod parçasını formunuzun OnLoad olayına yerleştirirseniz pencereniz katmanlı duruma geçer. Ama iş bu kadarla da bitmiyor tabiki. Bir de formun çizim alanının güncellenmesi gerekiyor. Yani katmanlı pencerenin yeniden çizilmesi gerekiyor. Bu işlem için yine Windows API fonksiyonlarından olan UpdateLayeredWindow' dan faydalanacağız. Güncelleme işlemi için elimizde formumuzun o anki görüntüsü olmalı. UpdateLayeredWindow fonksiyonu DC (Device Context) ile parametrik çalışır. Bu yüzden elimizde bir bitmap olsa çok iyi olurdu diyoruz. GDI+ ile çizim yapmanın en pratik yollarından biri de Bitmap sınıfından bir nesne ile ilişkilendirilmiş bir Graphics nesnesi. Graphics sınıfının GetHdc fonksiyonu ile aranan DC' yi çok kolay bir biçimde elde edebiliriz. Aşağıdaki kod parçasında Bitmap ile Graphics nesnelerinin nasıl kullanıldığını görebilirsiniz.
/* Form boyutlarinda bir Bitmap olustur */
bitmap = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb);
/* Bitmap ile baglantili ana Graphics nesnesi */
graphics = Graphics.FromImage(bitmap);
UpdateLayeredWindow için gereken DC' yi Graphics nesnesinin alabiliriz ama bu fonksiyonun bi' dünya parametresi var değil mi? Kaynak kod içinde UpdateLayeredForm() prosedürü UpdateLayeredWindow fonksiyonunun nasıl kullanıcağını gösteriyor. Alternatif kullanım şekilleri de mevcut ama ben klasik kullanımdan yana olduğum için bu kodu tercih ediyorum. Size de tavsiye ederim ve mutlaka inceleyin derim.
Geldik biraz karışık işlemlere... Aslında bu yazının temel öğretici amacını oluşturan kısım burası. Tasarım kısmında görünen kontrollerin tamamını bizim yeniden çizmemiz gerekiyor. Üstelik normalden farklı olarak. Dikkat ettiyseniz tasarım aşamasında resimlerin ve etiketlerin bir background' u var. Oysa programın çalışması sırasında bu background çizimleri görünmüyor. Transparent Label ve PictureBox oluşturmak C# ile oldukça kolay. Bu işlem için biraz kod yazmak gerek. Bende üşenmedim ve RepaintLayeredForm() adında bir prosedür yazdım. Bu prosedür form ekranındaki kontrolleri tekrardan transparent olarak çiziyor. Çizim esnasında biraz farklılık oluşuyor ama göze pek çarpmıyor. Aslında daha detaylı uğraşmak gerekiyordu fakat kaynak kod içinde karmaşıklığa yol açacağından gerek görmedim.
private void RepaintLayeredForm()
{
/* Herseyi sil */
graphics.Clear(Color.FromArgb(0));
/* Dikkat form uzerindeki bilesenler tersten siralanir */
for (int index = this.Controls.Count - 1; index >= 0; index--)
{
Control control = this.Controls[index];
/* Bilesen gorunmezse cizim yapma */
if (!control.Visible) continue;
if (control is PictureBox)
{
/* Bilesen PictureBox turundense Image ozelligini ciz */
PictureBox picture = control as PictureBox;
graphics.DrawImage(picture.Image, picture.Bounds);
}
else if (control is Label)
{
/* Bilesen Label turundense durum biraz karisik. Normalde DrawToBitmap fonksiyonu
* transparent cizim yapmaz. Biz zeminin cizilmesini istemiyoruz. Orjinalden biraz
* farkli bir cizim yapiyoruz.
*/
Label label = control as Label;
this.DrawTransparentLabel(label);
}
else
{
/* Diger turdense varsayilan cizim */
control.DrawToBitmap(bitmap, control.Bounds);
}
}
}
Evet. Bu kadar yazıdan fazlası okunmaz herhalde... C# ve GDI+ ilgilenen arkadaşlara bir yol gösterme amacıyla yazdığım bu makalenin sonuna geldik. Döviz.NET projesinin içinde burada bahsetmediğim bazı kodlar da var elbet. Özellikle internet bağlantısı yapılan kısımlar maalesef Thread kullanılmadan yazılmıştır. Ben kaynak kodu elimden geldiği kadar sade tutmaya çalıştığım için bu proje gerçek zamanlı ve son kullanıcıya hitap eden bir proje değildir. Hali hazırda eksiklikleri çoktur. Projenin kaynak kodunu aşağıdaki linkten indirebilirsiniz.
doviz.net-source.rar [277 KB] |
December 29th, 2011 on 7:13 pm
Merhaba;
Öncelikle bu güzel kodları paylaştığınız için çok teşekkür ediyorum.
Dev-C++ programı ile bu kodları çalıştırıp, exe olarak kaydedebilir miyim?
December 29th, 2011 on 7:57 pm
Kodlar C# ile yazıldığından C++ ile uyumlu değildir. Bunun için ayrı bir proje yapmak gerek. Kolay gelsin…
March 30th, 2012 on 8:27 pm
Merhaba ;
Gerçekten C# ta çok güzel uygulamalar yapmışsın… Bunları bizimle paylaştığınız için teşekkür ederim…
_____________________________________________________
Adobe photoshopta hazırladığım bir png resmim vardı. Etrafına gölge efektide vermiştim C# da formuma koyduğumda etrafında gölge yerine formumun renkleri geliyordu. Sonra çok araştırdım ama sizin sitenizde bulabildim. Sizin sayenizde düzelttim güzel bir form dizynı oldu. Bunun için teşekkür ederim. Ama bu seferde formuma Textbox ekleyipte çalıştırdığımda textboxa hiç bir şey yazılmıyor acaba bunun hakkında bilginiz var mı? Şimdiden teşekkür ederim çalışmalarınızın devamını dilerim.
March 30th, 2012 on 9:02 pm
Beğendiğinize sevindim, güle güle kullanın.
Sorununuzun çözümü oldukça karmaşıktır aslında. TextBox katmanlı pencerelerde hep sıkıntı olmuştur. Gerçekte TextBox’a yazılıyor ama maalesef görüntülenemiyor. Aynı sorunlarla bende uğraştım. Kısmen bazı çözümler ürettim ama en kesin çözümü WPF kullanarak bulabildim (WPF ve C# ile Yeniden Analog Saat Yapalım). Bu konuyu diğer arkaşlara da açılamaya çalıştım. Bir bakmanızda fayda var: C#, GDI+ ve UpdateLayeredWindow TextBox sorunu
TextBox haricinde diğer kontrollerde de sıkıntı var. Örneğin katmanlı pencere yapısına (UpdateLayeredWindow ile kullanılan) hiçbir zaman bir WebBrowser bileşeni ekleyemiyorsunuz. Microsoft geliştirdiği bileşenleri transparent olarak yazmamış. Maalesef hepsinde bir background var. Tüm sorun buradan kaynaklanıyor.
March 31st, 2012 on 6:56 pm
Tekrar teşekkür ederim. söylediklerinizi deniyeceğim…