42章 グラフィックス・デバイス・インターフェース(GDI)入門(その6)

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis"></meta>
<title>42章 グラフィックス・デバイス・インターフェース(GDI)入門(その6)
</title>
</head>

<body bgcolor="WHITE">
<font size="5">42章 グラフィックス・デバイス・インターフェース(GDI)入門(その6)
</font>
<hr>
<p align="CENTER">
<a href="chap42.lzh">ダウンロード</a>
<p>
 まず、余談から。なにか、この講座は失業期間の内に更新する事が多いです。仕事でプログラミングをしていると、どうも家に帰ってまでプログラミングをしたくないのかもしれません(笑)。今回も、失業期間中の更新です。<br>
 この講座を始めた頃のWindowsは95/98/NT4でしたが、何故か失業の多い私の書斎にもXPマシンが加わりました。しかし、OSの概観は変わっても、C言語とAPIを用いたプログラムは、なんら不安無くXPマシンでも動きました。<br>
 実務では、VBやBCBなどのRADツールを用いる事が普通です。しかし、この様な開発ツールはOSのバージョンアップの影響を受ける事があり、講座を始めた頃とは違った意味で、SDKレベルでのプログラミングの重要性が増してきている様に感じます。<br>
 また、現在、CPUの処理能力が増し、RADツールで大概のWindowsアプリケーションが組める時代です。しかし、ビデオキャプチャカードなどのSDKでは、サンプルプログラムが全てC言語で記述してある事があり、APIレベルでの知識は過去のものになっていない事を確信しました。
<hr>
 さて、余談はこれぐらいにして、今回は、描画オブジェクトの中でも使用頻度の多いと思われる<b>ペン</b>です。<b><i><u>ペンと言うのは、直線や曲線を描画するときに用いるオブジェクトです</u></i></b>。今回は、このオブジェクトの<b>作成の方法・使用方法・廃棄方法</b>を学びます。<br>
 筆者は、不精なのかサンプルプログラムを1から作る事はしません。今回は、37章のサンプルプログラムをベースにして作成しました。<br>
 では、早速、ソースコードから見てみましょう。
<p>
<table border="1" bgcolor="#F0F0F0">
<caption align="BOTTOM">リスト42-1
<tr><td>
<pre>
/* C言語で始めるWindowsプログラミング */
/* 42章のサンプルプログラム */
/* Programmed by Y.Kondo */
/* 注:TABサイズは4で見てください */
/* このファイルでは、メインウインドウのウインド*/
/*ウプロシージャが定義されている */

#define STRICT
#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include "wndproc.h"

/*===============================================================================*/

/* このファイル内でのみ用いられる関数のプロトタイプ宣言 */
static LRESULT Wm_CreateProc(HWND,CREATESTRUCT*);
static LRESULT Wm_DestroyProc(void);
static LRESULT Wm_PaintProc(HWND);

/* このファイル内でのみ用いられる変数宣言 */
HPEN P1,P2,P3,P4,P5,P6; /* 作成するペンのハンドル */

/* メインウインドウのウインドウプロシージャ */
LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
  switch(message)
   {
       case    WM_CREATE:              /*  ウインドウ初期化処理    */
           return  Wm_CreateProc(hwnd,(CREATESTRUCT*)lparam);
       case    WM_PAINT:               /*  再描画処理              */
           return  Wm_PaintProc(hwnd);
       case    WM_DESTROY:             /*  ウインドウの破壊後処理  */
           return  Wm_DestroyProc();
   }
   return  DefWindowProc(hwnd,message,wparam,lparam);
}

/*===============================================================================*/

static LRESULT Wm_CreateProc(HWND hwnd,CREATESTRUCT *cs)
{
  
   <b>LOGPEN</b>  lp={
                   PS_SOLID,       /*  実線    `*/
                   {5,0},          /*  太さ5  */
                   RGB(255,255,0)  /*  黄色    */  
               };
   P1=<b>CreatePen(PS_SOLID,1,RGB(255,0,0))</b>;          /*  太さが1で赤の実線                              */
   P2=<b>CreatePen(PS_DASH,1,RGB(0,255,0))</b>;           /*  太さが1で緑のダッシュ線                        */
   P3=<b>CreatePen(PS_DASHDOTDOT,1,RGB(0,0,255))</b>;     /*  太さが1でダッシュドットドット線                */
   P4=<b>CreatePenIndirect(&lp;)</b>;                      /*  構造体LOGPENを用いて間接的にペンの型を指定する  */
   P5=<b>CreatePen(PS_INSIDEFRAME,10,RGB(255,0,0))</b>;   /*  矩形をはみ出さないで囲う実線。太さは10で赤色  */
   P6=<b>CreatePen(PS_SOLID,10,RGB(255,0,0))</b>;         /*  P5との対比  */
   return  0;
}

static LRESULT Wm_PaintProc(HWND hwnd)
{
  PAINTSTRUCT ps;
   HDC         PaintDC;

  if(GetUpdateRect(hwnd,NULL,TRUE))
   {
       PaintDC=BeginPaint(hwnd,&ps;);   /*  ウインドウ描画用のデバイスコンテキスト取得  */
       /*  描画を行う  (ここから)    */
       <b>SelectObject(PaintDC,P1)</b>;   MoveToEx(PaintDC,10,10,NULL);   LineTo(PaintDC,300,10);
       <b>SelectObject(PaintDC,P2)</b>;   MoveToEx(PaintDC,10,30,NULL);   LineTo(PaintDC,300,30);
       <b>SelectObject(PaintDC,P3)</b>;   MoveToEx(PaintDC,10,50,NULL);   LineTo(PaintDC,300,50);
       <b>SelectObject(PaintDC,P4)</b>;   MoveToEx(PaintDC,10,70,NULL);   LineTo(PaintDC,300,70);

      /*  描画オブジェクトの種類が違うとペンに影響を与えない*/
       SelectObject(PaintDC,GetStockObject(DKGRAY_BRUSH));

      /*  矩形を2つのペンで描画  */      
       <b>SelectObject(PaintDC,P5)</b>;
       Rectangle(PaintDC,10,90,145,160);
       <b>SelectObject(PaintDC,P6)</b>;
       Rectangle(PaintDC,155,90,290,160);
       /*  作成した描画オブジェクトを開放する  */
       <b>SelectObject(PaintDC,GetStockObject(BLACK_BRUSH))</b>;
       /*  描画を行う  (ここまで)    */
       EndPaint(hwnd,&ps;);             /*  ウインドウ描画用のデバイスコンテキスト開放  */
   }
   return  0;
}

static LRESULT Wm_DestroyProc(void)
{
  /*  ペンを破棄する  */
   <b>DeleteObject(P1)</b>;
   <b>DeleteObject(P2)</b>;
   <b>DeleteObject(P3)</b>;
   <b>DeleteObject(P4)</b>;
   <b>DeleteObject(P5)</b>;
   <b>DeleteObject(P6)</b>;
   PostQuitMessage(0);
   return  0;
}
</pre>
</table>
<p>
 ペンの作成方法には代表的な物が2つあります。1つは、<b><i><u>CreatePen関数</u></i></b>。もう1つは、<b><i><u>CreatePenIndirect関数</u></i></b>です。C++と異なり、どこでも変数宣言できないC言語では、CreatePen関数が使い易いでしょう。勿論、実行ファイルをコンパクトな物にしたければ、CreatePenIndirect関数を選択した方が良いかもしれません。
<p>
・<b>CreatePen関数</b>
<p>
 第1引数は、線のタイプを決定するパラメータです。MSDNのマニュアルによると以下のように説明されています。
<table border="1">
<tr>
  <td>
       PS_SOLID
   </td>
   <td>
       Pen is solid.
   </td>
</tr>
<tr>
  <td>
       PS_DASH
   </td>
   <td>
       Pen is dashed. This style is valid only when the pen width is one or less in device units. 
   </td>
</tr>
<tr>
  <td>
       PS_DOT
   </td>
   <td>
       Pen is dotted. This style is valid only when the pen width is one or less in device units. 
   </td>
</tr>
<tr>
  <td>
       PS_DASHDOT
   </td>
   <td>
       Pen has alternating dashes and dots. This style is valid only when the pen width is one or less in device units.    </td>
</tr>
<tr>
  <td>
       PS_DASHDOTDOT
   </td>
   <td>
       Pen has alternating dashes and double dots. This style is valid only when the pen width is one or less in device units.
   </td>
</tr>
<tr>
  <td>
       PS_NULL
   </td>
   <td>
       Pen is invisible.
   </td>
</tr>
<tr>
  <td>
       PS_INSIDEFRAME
   </td>
   <td>
       Pen is solid. When this pen is used in any graphics device interface (GDI) drawing function that takes a bounding rectangle, the dimensions of the figure are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to geometric pens. 
   </td>
</tr>
</table>
<p>
 しかし、<b>第2引数で指定する幅で、線の物理幅が1デバイスピクセルより大きくなる場合は、全て実線になります</b>。
 第2引数は、<b>論理的</b>な線の幅を指定します。論理的なと言うのは、36章で少し書いたように、GDIには、今までのスクリーン座標とクライアント座標以外に独自の座標を持ちます。デフォルトは、<b>MM_TEXT</b>と呼ばれる座標系で、論理単位は、1デバイスピクセル単位に写像されます。そして、x座標の正方向は右、y座標の正方向は下になります。<br>
 従って、GDIの座標系を変更しない場合、第2引数を2以上にした場合、第1引数の値に関わらず、実線になります。<br>
 第3引数は、線の色で<b><i><u>RGBマクロ</u></i></b>で指定します。RGBマクロの引数は左から順に赤、緑、青で、0から255の値で表現します。全て0の時は黒。全て255の時は白です。
<p>
・<b>CreatePenIndirect関数</b>
<p>
 引数は1つで、<b>LOGPEN構造体</b>変数へのポインタです。
<p align="CENTER">
<table border="1" bgcolor="#F0F0F0">
<tr><td>
<pre>
typedef struct tagLOGPEN { // lgpn
  UINT     lopnStyle; 
   POINT    lopnWidth; 
   COLORREF lopnColor; 
} LOGPEN;
</pre>
</td></tr>
</table>
<p>
の様に定義されています。<br>
また、<b>POINT構造体</b>は、
<p align="CENTER">
<table border="1" bgcolor="#F0F0F0">
<tr><td>
<pre>
typedef struct tagPOINT { // pt
  LONG x; 
   LONG y; 
} POINT;
</pre>
</td></tr>
</table>
<p>
の様に定義されていますが、yは無視されます。つまり、xの値が線の論理的な幅になるのです。
<p>
・<b>SelectObject関数</b>
<p>
 これは、37章で説明しました。しかし、補足しておくべき事があります。これは、この関数は、リージョン以外で用いた場合、変更された同じ分野のオブジェクトのハンドルを返すと言う事です。つまり、ペンを変更すれば、前のペンのハンドルが返されるのです。
<p>
・<b>DeleteObject関数</b>
<p>
 作成したオブジェクトを破棄する関数です。引数は、廃棄するオブジェクトのハンドルです。<br>
 <b><i><u>選択されているオブジェクトは廃棄出来ません</u></i></b>。従って、いずれかの方法で作成したオブジェクトが選択されていない状態にする必要があります。この時、便利なのが、Windowsが本来持っているストックオブジェクトです。今回は、黒色のストックペンにSelectObject関数で置き換える事で、作成した全てのペンを選択されていない状態にして、破棄しています。<br>
<hr>
<p>
 長い間、更新していないにも関わらず、アクセス数は減るどころか、増える一方です。余談でも申しましたように、特殊なボードのSDKなどのサンプルプログラムは、C言語とAPIで記述されている事が多々あります。RADツールだけでなく、Windowsの動作原理を理解したプログラミングを心がけたいものです。
<p>
 次回は、塗りつぶすブラシを作ってみましょう。では、お楽しみに。
<p align="RIGHT">
2003年10月23日<br>
<hr>
<p align="RIGHT">
<a href="/web/20150829012816/http://web.kyoto-inet.or.jp:80/people/ysskondo/index.html">目次</a><br>
<hr>
<p align="RIGHT">
著作権者:近藤妥
</body>
</html>

  • 最終更新:2018-03-11 05:34:44

このWIKIを編集するにはパスワード入力が必要です

認証パスワード