Perubahan dalam Model Pemrograman

Bagian berikut menjelaskan beberapa cara agar pemrograman dengan Windows GDI+ berbeda dengan pemrograman dengan Windows Graphics Device Interface (GDI).

Konteks Perangkat, Handel, dan Objek Grafis

Jika Anda telah menulis program menggunakan GDI (antarmuka perangkat grafis yang disertakan dalam versi Windows sebelumnya), Anda terbiasa dengan gagasan konteks perangkat (DC). Konteks perangkat adalah struktur yang digunakan oleh Windows untuk menyimpan informasi tentang kemampuan perangkat tampilan dan atribut tertentu yang menentukan bagaimana item akan digambar pada perangkat tersebut. Konteks perangkat untuk tampilan video juga dikaitkan dengan jendela tertentu pada tampilan. Pertama Anda mendapatkan handel ke konteks perangkat (HDC), dan kemudian Anda meneruskan handel tersebut sebagai argumen ke fungsi GDI yang benar-benar melakukan gambar. Anda juga meneruskan handel sebagai argumen ke fungsi GDI yang mendapatkan atau mengatur atribut konteks perangkat.

Saat menggunakan GDI+, Anda tidak perlu khawatir dengan handel dan konteks perangkat seperti yang Anda lakukan saat menggunakan GDI. Anda cukup membuat objek Grafis lalu memanggil metodenya dalam gaya berorientasi objek yang sudah dikenal — myGraphicsObject.DrawLine(parameters). Objek Grafis adalah inti dari GDI+ sama seperti konteks perangkat adalah inti dari GDI. Konteks perangkat dan objek Grafis memainkan peran yang sama, tetapi ada beberapa perbedaan mendasar antara model pemrograman berbasis handel yang digunakan dengan konteks perangkat (GDI) dan model berorientasi objek yang digunakan dengan objek Grafis (GDI+).

Objek Grafis , seperti konteks perangkat, dikaitkan dengan jendela tertentu di layar dan berisi atribut (misalnya, mode penghalusan dan petunjuk penyajian teks) yang menentukan bagaimana item akan digambar. Namun, objek Grafis tidak terikat dengan pena, kuas, jalur, gambar, atau font sebagai konteks perangkat. Misalnya, di GDI, sebelum Anda dapat menggunakan konteks perangkat untuk menggambar garis, Anda harus memanggil SelectObject untuk mengaitkan objek pena dengan konteks perangkat. Ini disebut sebagai memilih pena ke dalam konteks perangkat. Semua baris yang digambar dalam konteks perangkat akan menggunakan pena tersebut hingga Anda memilih pena yang berbeda. Dengan GDI+, Anda meneruskan objek Pena sebagai argumen ke metode DrawLine dari kelas Grafis . Anda dapat menggunakan objek Pena yang berbeda di setiap rangkaian panggilan DrawLine tanpa harus mengaitkan objek Pena tertentu dengan objek Grafis .

Dua Cara Untuk Menggambar Garis

Dua contoh berikut masing-masing menggambar garis merah lebar 3 dari lokasi (20, 10) ke lokasi (200.100). Contoh pertama memanggil GDI, dan yang kedua memanggil GDI+ melalui antarmuka kelas C++.

Menggambar garis dengan GDI

Untuk menggambar garis dengan GDI, Anda memerlukan dua objek: konteks perangkat dan pena. Anda mendapatkan handel ke konteks perangkat dengan memanggil BeginPaint, dan handel ke pena dengan memanggil CreatePen. Selanjutnya, Anda memanggil SelectObject untuk memilih pena ke dalam konteks perangkat. Anda mengatur posisi pena ke (20, 10) dengan memanggil MoveToEx lalu menggambar garis dari posisi pena tersebut ke (200, 100) dengan memanggil LineTo. Perhatikan bahwa MoveToEx dan LineTo menerima hdc sebagai argumen.

HDC          hdc;
PAINTSTRUCT  ps;
HPEN         hPen;
HPEN         hPenOld;
hdc = BeginPaint(hWnd, &ps);
   hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
   hPenOld = (HPEN)SelectObject(hdc, hPen);
   MoveToEx(hdc, 20, 10, NULL);
   LineTo(hdc, 200, 100);
   SelectObject(hdc, hPenOld);
   DeleteObject(hPen);
EndPaint(hWnd, &ps);

Menggambar garis dengan GDI+ dan antarmuka kelas C++

Untuk menggambar garis dengan GDI+ dan antarmuka kelas C++, Anda memerlukan objek Grafis dan objek Pena . Perhatikan bahwa Anda tidak meminta handel Windows untuk objek ini. Sebagai gantinya, Anda menggunakan konstruktor untuk membuat instans kelas Grafis (objek Grafis) dan instans kelas Pena (objek Pena ). Menggambar garis melibatkan pemanggilan metode Graphics::D rawLine dari kelas Grafis . Parameter pertama dari metode Graphics::D rawLine adalah penunjuk ke objek Pena Anda. Ini adalah skema yang lebih sederhana dan lebih fleksibel daripada memilih pena ke dalam konteks perangkat seperti yang ditunjukkan dalam contoh GDI sebelumnya.

HDC          hdc;
PAINTSTRUCT  ps;
Pen*         myPen;
Graphics*    myGraphics;
hdc = BeginPaint(hWnd, &ps);
   myPen = new Pen(Color(255, 255, 0, 0), 3);
   myGraphics = new Graphics(hdc);
   myGraphics->DrawLine(myPen, 20, 10, 200, 100);
   delete myGraphics;
   delete myPen;
EndPaint(hWnd, &ps);

Pena, Kuas, Jalur, Gambar, dan Font sebagai Parameter

Contoh sebelumnya menunjukkan bahwa objek Pena dapat dibuat dan dipertahankan secara terpisah dari objek Grafis , yang memasok metode gambar. Objek Brush, GraphicsPath, Image, dan Font juga dapat dibuat dan dipertahankan secara terpisah dari objek Graphics . Banyak metode gambar yang disediakan oleh kelas Grafis menerima objek Brush, GraphicsPath, Image, atau Font sebagai argumen. Misalnya, alamat objek Brush diteruskan sebagai argumen ke metode FillRectangle , dan alamat objek GraphicsPath diteruskan sebagai argumen ke metode Graphics::D rawPath . Demikian pula, alamat objek Gambar dan Font diteruskan ke metode DrawImage dan DrawString . Ini berbeda dengan GDI tempat Anda memilih kuas, jalur, gambar, atau font ke dalam konteks perangkat dan kemudian meneruskan handel ke konteks perangkat sebagai argumen ke fungsi gambar.

Metode Kelebihan Beban

Banyak metode GDI+ kelebihan beban; artinya, beberapa metode memiliki nama yang sama tetapi memiliki daftar parameter yang berbeda. Misalnya, metode DrawLine dari kelas Grafis hadir dalam formulir berikut:

Status DrawLine(IN const Pen* pen,
                IN REAL x1,
                IN REAL y1,
                IN REAL x2,
                IN REAL y2);
Status DrawLine(IN const Pen* pen,
                IN const PointF& pt1,
                IN const PointF& pt2);
Status DrawLine(IN const Pen* pen,
                IN INT x1,
                IN INT y1,
                IN INT x2,
                IN INT y2);
    
Status DrawLine(IN const Pen* pen,
                IN const Point& pt1,
                IN const Point& pt2);

Keempat variasi DrawLine di atas menerima penunjuk ke objek Pena , koordinat titik awal, dan koordinat titik akhir. Dua variasi pertama menerima koordinat sebagai angka floating point, dan dua variasi terakhir menerima koordinat sebagai bilangan bulat. Variasi pertama dan ketiga menerima koordinat sebagai daftar empat angka terpisah, sedangkan variasi kedua dan keempat menerima koordinat sebagai sepasang objek Titik (atau PointF).

Tidak Ada Lagi Posisi Saat Ini

Perhatikan bahwa dalam metode DrawLine yang diperlihatkan sebelumnya baik titik awal maupun titik akhir baris diterima sebagai argumen. Ini adalah keberangkatan dari skema GDI tempat Anda memanggil MoveToEx untuk mengatur posisi pena saat ini diikuti oleh LineTo untuk menggambar garis mulai dari (x1, y1) dan berakhir pada (x2, y2). GDI+ secara keseluruhan telah meninggalkan gagasan posisi saat ini.

Metode Terpisah untuk Gambar dan Isi

GDI+ lebih fleksibel daripada GDI dalam hal menggambar kerangka dan mengisi interior bentuk seperti persegi panjang. GDI memiliki fungsi Persegi panjang yang menggambar kerangka dan mengisi interior persegi panjang semuanya dalam satu langkah. Kerangka digambar dengan pena yang saat ini dipilih, dan interior diisi dengan kuas yang saat ini dipilih.

hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
SelectObject(hdc, hBrush);
SelectObject(hdc, hPen);
Rectangle(hdc, 100, 50, 200, 80);

GDI+ memiliki metode terpisah untuk menggambar kerangka dan mengisi interior persegi panjang. Metode DrawRectangle dari kelas Grafis memiliki alamat objek Pen sebagai salah satu parameternya, dan metode FillRectangle memiliki alamat objek Brush sebagai salah satu parameternya.

HatchBrush* myHatchBrush = new HatchBrush(
   HatchStyleCross,
   Color(255, 0, 255, 0),
   Color(255, 0, 0, 255));
Pen* myPen = new Pen(Color(255, 255, 0, 0), 3);
myGraphics.FillRectangle(myHatchBrush, 100, 50, 100, 30);
myGraphics.DrawRectangle(myPen, 100, 50, 100, 30);

Perhatikan bahwa metode FillRectangle dan DrawRectangle di GDI+ menerima argumen yang menentukan tepi kiri, atas, lebar, dan tinggi persegi panjang. Ini berbeda dengan fungsiPersegi Panjang GDI, yang mengambil argumen yang menentukan tepi kiri persegi, tepi kanan, atas, dan bawah. Perhatikan juga bahwa konstruktor untuk kelas Warna di GDI+ memiliki empat parameter. Tiga parameter terakhir adalah nilai merah, hijau, dan biru yang biasa; parameter pertama adalah nilai alfa, yang menentukan sejauh mana warna yang digambar dipadukan dengan warna latar belakang.

Membangun Wilayah

GDI menyediakan beberapa fungsi untuk membuat wilayah: CreateRectRgn, CreateEllpticRgn, CreateRoundRectRgn, CreatePolygonRgn, dan CreatePolyPolygonRgn. Anda mungkin mengharapkan kelas Wilayah di GDI+ memiliki konstruktor analog yang mengambil persegi panjang, elipsis, persegi panjang bulat, dan poligon sebagai argumen, tetapi itu tidak terjadi. Kelas Wilayah di GDI+ menyediakan konstruktor yang menerima referensi objek Rect dan konstruktor lain yang menerima alamat objek GraphicsPath. Jika Anda ingin membuat wilayah berdasarkan elips, persegi panjang bulat, atau poligon, Anda dapat dengan mudah melakukannya dengan membuat objek GraphicsPath (yang berisi elips, misalnya) lalu meneruskan alamat objek GraphicsPath tersebut ke konstruktor Wilayah .

GDI+ memudahkan untuk membentuk wilayah yang kompleks dengan menggabungkan bentuk dan jalur. Kelas Wilayah memiliki metode Union dan Intersect yang dapat Anda gunakan untuk menambah wilayah yang ada dengan jalur atau wilayah lain. Salah satu fitur bagus dari skema GDI+ adalah bahwa objek GraphicsPath tidak dihancurkan ketika diteruskan sebagai argumen ke konstruktor Wilayah . Di GDI, Anda dapat mengonversi jalur ke wilayah dengan fungsi PathToRegion , tetapi jalurnya dihancurkan dalam prosesnya. Selain itu, objek GraphicsPath tidak dihancurkan ketika alamatnya diteruskan sebagai argumen ke metode Union atau Intersect, sehingga Anda dapat menggunakan jalur tertentu sebagai blok penyusun untuk beberapa wilayah terpisah. Hal ini ditunjukkan di contoh berikut. Asumsikan bahwa onePath adalah penunjuk ke objek GraphicsPath (sederhana atau kompleks) yang telah diinisialisasi.

Region  region1(rect1);
Region  region2(rect2);
region1.Union(onePath);
region2.Intersect(onePath);