Graphics / Hooking / Handling / Windows Mesaj Sistemi

@ 16 Aralık 2004 tarihinde yazdı. Yazıya yorum yazın.

Bu dersin ilk kisminda Vb.Net Graphics / Hooking / Handling / Windows Mesaj sistemi konularini ve Vb.net’te ocx yapimini anlatacagim.
Bu bölümde vb.net de graphics kullanımı öğreneceğiz.
Tabi bunu uygulamalı olarak bir usercontrol de göstermek hem daha faydalı olur hemde bu çalışma taamlandığında elimize bir usercontrol geçmiş olur.
VB 6′dan bildiğimiz kadarıyla çizgi veya elips çizme ve bunun gibi işlemler için Line Circle Point gibi metodları kullanıyorduk.

Aslında bilindiği gibi bunlar API lerin biraz daha kolaylaştırılmış halidir.
Örnek :


Form1.CurrenX=0
Form1.CurrenY=0
Form1.Print "deneme"

yazıldığında (paint olayına) 0,0 koordinatına “deneme” metni yazılmış olacaktır
Bunun arka zemininde yatan kod ise:


Declare Function DrawText Lib _
"user32" Alias "DrawTextA" _
(ByVal hdc As Long, ByVal lpStr As String, _
ByVal nCount As Long, lpRect As RECT, _
ByVal wFormat As Long) As Long
(r as rect)
DrawText Me.hdc, "deneme", Len("deneme"), R, DT_CENTER

gibi bir koddur HDC = device content yani aygıt içeriği
Aksi olmadıkça windows’a tanımlı hemen hemen her tür pencere oluşturulurken otomatik olarak birde HDC alırlar. Tabi bundan önce bir HANDLE numarası alırlar. HANDLE = HWND
Handle of window yani pencerenin tutamacıdır. Daha açık olmak gerekirse, her pencereye verilen yegane!!! bir sayıdır. İki farklı pencere aynı hwnd yi alamaz. Aynı şekilde hdc de yeganedir.
Yapılacak çizim işlemleri HDC ye yapılır, yani pencere içeriğine, diğer bütün işlemlerde HANDLE denilen bu numara sayesinde yapılır
Örnek:


Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" _
(ByVal hwnd As Long, ByVal lpString As String) As Long

Bu API, bir pencerenin başlığını değiştirmeye yarar. HWND’ye pencerenin numarası, lpString e de başlığı girilir.
API, girilen handle daki, pencerenin başlığını değiştirir. Windows TEMELDE bu sistemde çalışır. Genel olarak düşündüğünüz bütün propertyler yani özellikler bir pencereye gönderilen mesajlardır.
Yani siz forma bir buton koyup Caption özelliğini değiştirdiğinizde aslında VB6, yukardaki api yi çağırır.
Bir property ataması yapmak için 2 yol vardır
1. si yukardaki gibi gerekli apiyi kullanıp gerekli işlem gerçekleştirilir
2. si ve daha temeli, SENDMESSAGE API siyle bir pencere ye doğrudan mesaj göndermektir.
Aslında SetwindowText apisi, SENDMESSAGE apisini kullanarak pencereye bir mesaj gönderir
Windows Sendmessage temeline oturmuş bir sistemdir.


Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

HWND = handle
wMSG = Gönderilecek mesaj
w ve l param lar da 2 ayrı parametredir

Pencerelerle ilgili tüm işlemleri bu apiyle yapabilirsiniz. Hatta EVENT dediğimiz MouseMove Click DblClick te bir pencereye gönderilen mesajlardır.
VB6, çalıştığında, bu mesajları HOOK eder yani, tutar ve izini sürer, gelen mesajlar ne ise ona göre o işlemi çalıştırır. Çok ayrıntıya girmeden HDC konusuna geri dönelim.
Evet, bir pencerenin hdc si ile, çizim ve boyama işlemleri yapılır.Aynı mantıkla Vb6 yapılmıştır ve aynı mantıkla VB.Net yapılmıştır.
(Tabi diğer tüm programlama dilleri de. Ancak bizi VB ilgilendiriyor)
VB.Net’te, VB6 dan farklı olarak bir objenin bir olayı çağrıldığında (yani event tetiklendiğinde) çalıştırılan,


Private Sub Command1_Click()
End Sub

yerine,


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
End Sub

bulunur.
sender , bu olayı çağıran objeyi ifade eder.
e ise bu olayın çağrılmasında ek özellikleri tutan bir değişkendir
Örneğin, eğer MouseMove olayı çağırılıyor olsaydı e.X ve e.Y bize koordinatları,
e.Button bize buttonu verecekti.
VB6 da da benzer bir kavram bulunuyor hatırlarsak.
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
gibi.
İşte VB.Net bunu bütün event lara eklemiş ve biraz daha toparlayarak.
Gelelim son bölüme
Handles Button1.Click
İşte burası çok önemli. Az önce bahsettiğim hooking handling terimleri burda görebiliyoruz
Bu prosedür, Button1 in Click Event ını TUTUYOR. Yani handle ediyor.
Böylece Button1 in Click event ı çağrıldığında, bu prosedür çalıştırılıcaktır.
VB6 da bu prosedür ismini değiştirmek imkansızdı. Ancak VB.Net te bunu yapabiliriz

Private Sub emre(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
End Sub

gördüğünüz gibi isim değişti ancak, Handles kısmı değişmediği için yine buton 1 tıklandığında bu prosedür çalıştırılacaktır.
Peki, madem ki Button1.Click deniliyor sonda, bir daha ne diye sender diye bir değişken kullanarak, bu işlemi yaptıran obje belirtiliyor?
Güzel soru. VB.Net te doğrudan Control Array oluşturma kaldırıldı. Eskiden olsa (VB6), bir nesnenin birden fazla control array ini yapıp hepsini aynı eventlara bağlayarak işlerimizi kolaylaştırıyorduk
Hatırlarsanız bir INDEX numarası geliyordu. Bizde onu kullanarak hangi array in bu event ı tetiklediğini buluyorduk.
Ancak VB.Net te yeni bir özellik bulunuyor. Öyleki runtime oluşturduğunuz bir nesnenin eventlarını bir prosedüre bağlayabiliyorsunuz.

Örneğin;

Dim i As New Button
Me.Controls.Add(i)
AddHandler i.Click, AddressOf Button1_Click

Addhandler yazdıktan sonra yazılan obje ismi ve nokta sonrasında gelen Event artık belirttiğiniz prosedürü tetikleyecektir.
Tabi ek bir özellik daha belirteyim. Aynı prosedüre design time da da 1 den fazla objenin event ını atamanız mümkün.
Örnek:


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click,Button2.Click

Konuyu iyice dağıttık.
Şimdi bir bileşen düşünün, bir buton. Temelde yapacağımız 1 çerçeve, 1 Metin,1 de tıklama anında içe doğru göçme.
Yeni bir usercontrol ekleyip paint event ına geçiyoruz.


Private Sub UserControl1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
End Sub

Çerçeveyi çizelim. Ancak 3 boyutlu bir görünüm vermeliyiz ki güzel görünsün. Bu aldatmacaya yıllardır farkında olmadan kanarız. Aslında bilgisayarda 3 boyutlu birşey olamaz. Ancak derinlikle yapılabilir.
Peki bir buton nasıl oluyorda üstüne basıldığında içeri gömülüyor? İşte bunu birazdan anlatacağım. Bundan önce bilmemiz gereken bir butonun 4 çizgi ve bir metinden oluştuğudur.

4 çizgi içinde iki tanesi koyu iki tanesi açık renk olmalıdır.
Sol ve Üst çizgiler açık sağ ve alt koyu olacaktır.
Bundan önce .net teki bir yeniliğe dikkat çekmek istiyorum. .Net 2003 te 5000 den fazla class var. Bu kadar çok class olması işimizi çok kolaylaştırıyor.
Örneğin;
Pen adlı class, bir çizim için bir pen yani kalem oluşturmalıyız. Kalemin 2 özelliği vardır. Birincisi renk, ikincisi kalınlıktır.


Dim P As New Pen(Color.White)

İşte yukardaki kod bize beyaz bir kalem hazırlar (kalınlık verilmediği için 1 olarak alınır).
Color class ı sayesinde bir renk oluşturmamız mümkündür.
Şimdi kodumuza dönelim:


Private Sub UserControl1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim p As New Pen(Color.White)
e.Graphics.DrawLine(p, 0, 0, Me.Width - 1, 0)'üst
e.Graphics.DrawLine(p, 0, 0, 0, Me.Height - 1)'sol
p = New Pen(Color.FromKnownColor(KnownColor.ControlDarkDark)) ' buton renklerinin iki koyusunu seçtik
e.Graphics.DrawLine(p, 0, Me.Height - 1, Me.Width - 1, Me.Height - 1)'alt
e.Graphics.DrawLine(p, Me.Width - 1, 0, Me.Width - 1, Me.Height - 1)'sağ
End Sub

Gördüğünüz gibi Vb6 daki Line yerine burada DrawLine bulunuyor.
DrawLine (Pen,X1,Y1,X2,Y2)
Böylece çerçevemiz bitmiş oldu. Şimdi sıra Metin kısmında. Metin yazdırmak için VB6 da CurrentX CurrentY ve Print kullanırdık
Şimdi ise DrawString kullanıyoruz.


Dim sf As New StringFormat
sf.LineAlignment = StringAlignment.Center
sf.Alignment = StringAlignment.Center
e.Graphics.DrawString("Buton1", Me.Font, New SolidBrush(Me.ForeColor), New RectangleF(0, 0, Me.Width, Me.Height), sf)

String format bir yazının hizalamasını ayarlamak için veya diğer ek özelliklerini ayarlamak için kullaılır. İkinci ve üçüncü satırda dikey ve yatay hizalamayı
ayarladık.
Sonra son satırda metini yazdırdık (‘Buton1′).
Solidbrush yine Pen’ e benzeyen bir classtır. Ancak kalınlık özelliği bulunmamaktadır. Genelde bir alanı doldurma veya metin yazımlarında kullanılır.
RectangleF bir dikdörtgen alan belirtmeye yarar. Aynı vb6 daki Rect Type ı gibi. 0,0 X ve Y, me.width ve me.height ise genişlik ve yüksekliği verir.
.Net te bütün user controllerde Font Backcolor ForeColor gibi özellikler vardır.

Emre YAZICI
[CodingMaster]