Multi Magic Square(마방진) 소스

C#/자료실 2008/06/16 01:15 Posted by <!--r'i"z&i\n+#]]x juree23
Odd, Even, SinglyEven Magic Square 구현한겁니다.

필요하신 분 받아가세요..

주민등록번호 유효성 체크

C#/자료실 2008/06/16 01:14 Posted by <!--r'i"z&i\n+#]]x juree23
걍 심심해서;;
필요하신 분 있으시면 가져 가세요~~ ^^

에디트플러스 입니다..

C#/자료실 2008/06/16 01:14 Posted by <!--r'i"z&i\n+#]]x juree23
체험판이지만 유용하게 쓰세여..
필요하신분들. 혹시 있을지 몰라서 이사이트에 없어서 올려봅니다.

FMOD모듈을 이용한 음악 재생기 입니다.

C#/자료실 2008/06/16 01:13 Posted by <!--r'i"z&i\n+#]]x juree23
아직 실력부족과 시간 부족으로 음악 열기랑 일시 정지 밖에 안되구요 ㅠ; 이런거 올려두 되려나;;
초랑 노래 진행도정도만 뜹니다.
글구 수정안해서 일시 정지후 재생 계속 누르면 ㅋㅋㅋ;; 버그 발견 ㅡ_ㅡ;;

fmod 은근히 최적화 잘되 있는거 같네요. mp3재생시에는 cpu점유율이 1% 미만이고
wma재생시는 2% 정도 먹네요 ㅎㅎ wince 용으로 쓰기에 적합한듯?;;

아 그리고 구버전 FMOD는 cs모듈이 없어서 만드는데 고생좀 했씁니다. ㅠㅠ;
구버전 쓰는 이유는 wince용으로 무언가를 만들려고 했는데 최신버전은 wince플랫폼을 빼버린듯해서..

투명창이 지원되는 메모장

C#/자료실 2008/06/16 01:13 Posted by <!--r'i"z&i\n+#]]x juree23
코딩 한 100줄 되려나 -_-+

C 매우 강력하군요...

C 문법도 모르면서 한번 어떤것인지 느껴보려고 살짝 만들어봤는데

조금만 익혔으면 한시간이면 될텐데..

무작정 msdn 뒤져가며 코딩한거라 소스들이 개판 5분전입니다.

여기저기 버그는 좀 있지만 살짝 공개 합니다.


vs.net 2005 라  .net framework 2.0 이 필요합니다.

간단한 메신저 예제 프로그램

C#/자료실 2008/06/16 01:12 Posted by <!--r'i"z&i\n+#]]x juree23
간단한 메신저 예제 프로그램을 올립니다.
필요하신분 참고 하세요..

스크롤바 스타일 변경 소스

C#/자료실 2008/06/16 01:11 Posted by <!--r'i"z&i\n+#]]x juree23
스크롤바 스타일 변경 소스입니다.

SMTP 메일전송 프로그램 소스

C#/자료실 2008/06/16 01:10 Posted by <!--r'i"z&i\n+#]]x juree23
SMTP 메일전송 프로그램 소스입니다..^^

'C# > 자료실' 카테고리의 다른 글

간단한 메신저 예제 프로그램  (0) 2008/06/16
스크롤바 스타일 변경 소스  (0) 2008/06/16
SMTP 메일전송 프로그램 소스  (0) 2008/06/16
오피스 문어 뷰어 프로그램 소스입니다.  (0) 2008/06/16
그림판 소스  (0) 2008/06/16
마우스 이벤트  (0) 2008/06/16

오피스 문어 뷰어 프로그램 소스입니다.

C#/자료실 2008/06/16 01:09 Posted by <!--r'i"z&i\n+#]]x juree23
오피스 문서(파워포인트,엑셀,DOC문서)를 볼수 있는 뷰어 프로그램의 소스입니다. 유용하게 쓰세염

'C# > 자료실' 카테고리의 다른 글

스크롤바 스타일 변경 소스  (0) 2008/06/16
SMTP 메일전송 프로그램 소스  (0) 2008/06/16
오피스 문어 뷰어 프로그램 소스입니다.  (0) 2008/06/16
그림판 소스  (0) 2008/06/16
마우스 이벤트  (0) 2008/06/16
메모장 소스입뉘당. 공부열쒸미하세요.  (0) 2008/06/16

그림판 소스

C#/자료실 2008/06/16 01:08 Posted by <!--r'i"z&i\n+#]]x juree23
신발님이 올려주신 자료입니다.

간단한 그림판 소스입니다.
이건 출처 기억나네요. ㅎㅎ
데브피아 c자료실에서 다운받은겁니다..... ..
헉 근데 누가 올리신 자료인지 까묵었네요. ㅡ,.ㅡ
문제가 되면 삭제를.....

마우스 이벤트

C#/자료실 2008/06/16 01:07 Posted by <!--r'i"z&i\n+#]]x juree23
C 를 좋아하는넘 님이 올려주신 자료입니다.
 c 언어 공부하다가 윈도우 프로그램으로 C 을 시작 하게 되었습니다.
그냥 적절한 교재가 없어서 MSDN 보고 만든 메세지 처리 부분에 대하여 만들어 봤습니다.
여러분들의 많은 도움 부탁드립니다

이것보다 마우스 이벤트 처리를 쉽게 할수는 없을까요?

메모장 소스입뉘당. 공부열쒸미하세요.

C#/자료실 2008/06/16 01:07 Posted by <!--r'i"z&i\n+#]]x juree23
메모장 소스 다시 올려 드립니당...
설치 및 배포 프로젝트 강좌 예제 화일입니다

윈폼과 컨트롤을 여러가지모양으로..

C#/자료실 2008/06/16 01:04 Posted by <!--r'i"z&i\n+#]]x juree23
윈폼과 컨트롤들을 여러가지 모양으로 제어한 예제입니다. tij 님이 가르쳐 주신 주소로 들어가서 보고 예제 만들어 봤습니다. 이것두 곧 강좌 올리겠습니다. 타이틀바도 없어지는군요...ㅋㅋ

메신져 소스 공개합니당..ㅡ0ㅡㅋㅋ

C#/자료실 2008/06/16 01:04 Posted by <!--r'i"z&i\n+#]]x juree23
메신져 입니당.
기본 채팅기능과 채팅방기능 1:1 채팅, 쪽지보내기, 회원가입, 손님으로 접속, IP 보기, 현제 접속자 현황, 현제 접속자 위치보기 등등 여러가지 기능이 있는 메신져 입니다. 아직 기능이 미흡하지만 C을 공부하시는 여러분들에게 조금이라도 도움이 될까 싶어서 이렇게 소스 공개합니당..  
불행히도 테이블 내역은 없어서 테이블은 소스 참고하셔서 직접 만드셔야 합니다..ㅜ.ㅜ.

탐색기 소스입니다.

C#/자료실 2008/06/16 01:03 Posted by <!--r'i"z&i\n+#]]x juree23
탐색기 소스입니다. 다 만들진 않았구요 파일 목록과 디렉토리 목록.. 선택된 목록을 보여주는 기능.. 기초기능만 넣었습니다. 여기서 자기가 기능을 추가하시면 됩니다.

윈2000 환경의 사용자에게 메세지 반복 보냄

C#/자료실 2008/06/16 01:02 Posted by <!--r'i"z&i\n+#]]x juree23
윈도우 2000 이상 환경의 사용자의 아이피를 적어주면 동일한 메세지를 지정된 횟수만큼 메세지 박스로 띄워줍니다.

아이피나 호스트의 정보를 추출하는 소스

C#/자료실 2008/06/16 01:02 Posted by <!--r'i"z&i\n+#]]x juree23
아이피나 호스트의 정보를 추출하는 소스

윈폼 강좌중에 프린터 컨트롤의 소스입니다.

C#/자료실 2008/06/16 01:01 Posted by <!--r'i"z&i\n+#]]x juree23
윈폼 강좌중에 프린터 컨트롤의 소스입니다.

투명 윈도우 소스 입니당..

C#/자료실 2008/06/16 01:00 Posted by <!--r'i"z&i\n+#]]x juree23
투명 윈도우 소스에영..ㅡ0ㅡ;;
허접하지만 모르는 분들을 위해소..

PDF를 BMP,PNG,TIFF,JPEG

C#/자료실 2008/06/16 01:00 Posted by <!--r'i"z&i\n+#]]x juree23
PDF를 BMP,PNG,TIFF,JPEG로 만드는 컴포넌트라고 하네요
프리입니다.

2D Polygon Collision Detection

C#/자료실 2008/06/16 00:59 Posted by <!--r'i"z&i\n+#]]x juree23
 

Sample Image

Introduction

This article describes how to detect the collision between two moving (2D) polygons. It's not the first tutorial on the topic, however, the tutorials on the net tend to be a bit too complex for a relatively simple problem. The source codes I could find also had too many abbreviations that I don't get, or were crippled with C optimizations. So here, I'll try to keep it as simple as possible. In any case, it should be possible to include the functions presented here to your C projects quite straightforwardly. The technique can be used to detect collisions between sprites as an alternative to pixel-perfect collisions which are usually too slow.

Background

To detect if two polygons are intersecting, we use the Separating Axis Theorem. The idea is to find a line that separates both polygons - if such a line exists, the polygons are not intersecting (Fig. 1). The implementation of this theorem is relatively simple, and could be summed up in this pseudo code:

  • For each edge of both polygons:
    • Find the axis perpendicular to the current edge.
    • Project both polygons on that axis.
    • If these projections don't overlap, the polygons don't intersect (exit the loop).

This can be easily extended to deal with moving polygons by adding one additional step. After having checked that the current projections do not overlap, project the relative velocity of the polygons on the axis. Extend the projection of the first polygon by adding to it the velocity projection (Fig. 2). This will give you the interval spanned by the polygon over the duration of the motion. From there, you can use the technique used for static polygons: if the projections of polygons A and B don't overlap, the polygons won't collide. (NB: However, remember that if the intervals do overlap, it doesn't necessarily mean that the polygons will collide. We need to do the test for all the edges before knowing that.)

Once we have found that the polygons are going to collide, we calculate the translation needed to push the polygons apart. The axis on which the projection overlapping is minimum will be the one on which the collision will take place. We will push the first polygon along this axis. Then, the amount of translation will simply be the amount of overlapping on this axis (Fig. 3).

That is it! Now, each time a collision occurs, the first polygon will nicely slide along the surface of the other polygon.

Figure 1: Projections of the polygons onto an axis.

Figure 2: Projections for moving polygons.

Figure 3: Find the minimum interval overlapping, then calculate the translation required to push the polygons apart.

Using the code

The PolygonCollision() function does all of the above, and returns a PolygonCollisionResult structure containing all the necessary information to handle the collision:

// Structure that stores the results of the PolygonCollision function
public struct PolygonCollisionResult {
    // Are the polygons going to intersect forward in time?
    public bool WillIntersect;
    // Are the polygons currently intersecting?
    public bool Intersect;
    // The translation to apply to the first polygon to push the polygons apart.
    public Vector MinimumTranslationVector;
}

Two helper functions are used by the PolygonCollision function. The first one is used to project a polygon onto an axis:

// Calculate the projection of a polygon on an axis
// and returns it as a [min, max] interval
public void ProjectPolygon(Vector axis, Polygon polygon, 
                           ref float min, ref float max) {
    // To project a point on an axis use the dot product
    float dotProduct = axis.DotProduct(polygon.Points[0]);
    min = dotProduct;
    max = dotProduct;
    for (int i = 0; i < polygon.Points.Count; i++) {
        dotProduct = polygon.Points[i].DotProduct(axis);
        if (d < min) {
            min = dotProduct;
        } else {
            if (dotProduct> max) {
                max = dotProduct;
            }
        }
    }
}

The second one returns the signed distance between two given projections:

// Calculate the distance between [minA, maxA] and [minB, maxB]
// The distance will be negative if the intervals overlap
public float IntervalDistance(float minA, float maxA, float minB, float maxB) {
    if (minA < minB) {
        return minB - maxA;
    } else {
        return minA - maxB;
    }
}

Finally, here is the main function:

Collapse
// Check if polygon A is going to collide with polygon B.
// The last parameter is the *relative* velocity 
// of the polygons (i.e. velocityA - velocityB)
public PolygonCollisionResult PolygonCollision(Polygon polygonA, 
                              Polygon polygonB, Vector velocity) {
    PolygonCollisionResult result = new PolygonCollisionResult();
    result.Intersect = true;
    result.WillIntersect = true;

    int edgeCountA = polygonA.Edges.Count;
    int edgeCountB = polygonB.Edges.Count;
    float minIntervalDistance = float.PositiveInfinity;
    Vector translationAxis = new Vector();
    Vector edge;

    // Loop through all the edges of both polygons
    for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) {
        if (edgeIndex < edgeCountA) {
            edge = polygonA.Edges[edgeIndex];
        } else {
            edge = polygonB.Edges[edgeIndex - edgeCountA];
        }

        // ===== 1. Find if the polygons are currently intersecting =====

        // Find the axis perpendicular to the current edge
        Vector axis = new Vector(-edge.Y, edge.X);
        axis.Normalize();

        // Find the projection of the polygon on the current axis
        float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
        ProjectPolygon(axis, polygonA, ref minA, ref maxA);
        ProjectPolygon(axis, polygonB, ref minB, ref maxB);

        // Check if the polygon projections are currentlty intersecting
        if (IntervalDistance(minA, maxA, minB, maxB) > 0)\
            result.Intersect = false;

        // ===== 2. Now find if the polygons *will* intersect =====

        // Project the velocity on the current axis
        float velocityProjection = axis.DotProduct(velocity);

        // Get the projection of polygon A during the movement
        if (velocityProjection < 0) {
            minA += velocityProjection;
        } else {
            maxA += velocityProjection;
        }

        // Do the same test as above for the new projection
        float intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
        if (intervalDistance > 0) result.WillIntersect = false;

        // If the polygons are not intersecting and won't intersect, exit the loop
        if (!result.Intersect && !result.WillIntersect) break;

        // Check if the current interval distance is the minimum one. If so store
        // the interval distance and the current distance.
        // This will be used to calculate the minimum translation vector
        intervalDistance = Math.Abs(intervalDistance);
        if (intervalDistance < minIntervalDistance) {
            minIntervalDistance = intervalDistance;
            translationAxis = axis;

            Vector d = polygonA.Center - polygonB.Center;
            if (d.DotProduct(translationAxis) < 0)
                translationAxis = -translationAxis;
        }
    }

    // The minimum translation vector
    // can be used to push the polygons appart.
    if (result.WillIntersect)
        result.MinimumTranslationVector = 
               translationAxis * minIntervalDistance;
    
    return result;
}

The function can be used this way:

Vector polygonATranslation = new Vector();

PolygonCollisionResult r = PolygonCollision(polygonA, polygonB, velocity);

if (r.WillIntersect) {
  // Move the polygon by its velocity, then move
  // the polygons appart using the Minimum Translation Vector
  polygonATranslation = velocity + r.MinimumTranslationVector;
} else {
  // Just move the polygon by its velocity
  polygonATranslation = velocity;
}

polygonA.Offset(polygonATranslation);

'C# > 자료실' 카테고리의 다른 글

투명 윈도우 소스 입니당..  (0) 2008/06/16
PDF를 BMP,PNG,TIFF,JPEG  (2) 2008/06/16
2D Polygon Collision Detection  (0) 2008/06/16
The Aqualizer Strikes Back!  (0) 2008/06/16
ImageConverter - Converts images to a specific image format, changing sizes on the flow  (0) 2008/06/16
Aqua Gauge  (0) 2008/06/16

The Aqualizer Strikes Back!

C#/자료실 2008/06/16 00:59 Posted by <!--r'i"z&i\n+#]]x juree23

Introduction

Ah. Aqua buttons. They're everywhere. Except on your website. Don't be frustrated anymore. You've just found the helping hand you need: The Aqualizer! The Aqualizer, or Aqualize, is a fantastic, excellent and downright amazing command line utility to create “aqua”-buttons like this one:

If you want a button like this, download The Aqualizer and type at the command prompt:

C:\>aqualize "The\nAqualizer" button.bmp

Or maybe you want a red button?

C:\>aqualize -c:FF0000 "The\nAqualizer" button.bmp

A black one?

C:\>aqualize -c:000000 -t:FFFFFF "The\nAqualizer" button.bmp

A small one?

C:\>aqualize -s:small -a:0 "Hi!" button.bmp

I found a GIMP tutorial on the net for a aqua button I liked, and thought it would be cool if people, especially programmers, with no knowledge of GIMP or Photoshop could put a nice aqua button on their website. I wrote all the code I needed to follow the steps in the tutorial. The Aqualizer is based on Shadow, my program to add drop shadows to images (see my site).

Composing The Image

Let's take a look at the code in Main(). We're going to create an image with several layers, so we create a new LayeredImage object and call it image:

    // create image
    LayeredImage image = new LayeredImage(width, height);

The first layer we add is the background layer. We fill the layer with the background color.

    // background
    Layer bkgnd = image.Layers.Add();
    bkgnd.Clear(bkcolor);

If the user wants a drop shadow, we create a new layer, select a circle, fill that circle with black, apply a blur filter, move the layer a bit to the right and to the bottom, and set the opacity of the layer so that the shadow is not too dark. The blur filter in Shadow uses a Gauss curve to calculate the contribution of the color of a pixel to the “current” pixel. The blur filter in The Aqualizer uses a Sigmoid curve. A Sigmoid curve is defined by three parameters: alpha, beta and gamma. Alpha is the start point, beta is the inflexion point, and gamma is the end point. The value at alpha is zero and the value at gamma is 1. The advantage of a Sigmoid curve is that you know that the value at alpha is 0; when using a Gauss curve, you cannot be 100% sure that the value will be 0. If you want to know how a blur filter works, see the article on my site.

    if (dropshadow) {
        // shadow
        Layer shadow = image.Layers.Add();
        image.ActiveLayer = shadow;
        image.BackColor = Color.Black;
        image.Selection.SelectEllipse(
            margin,
            margin,
            buttonwidth,
            buttonwidth,
            SelectionMode.Replace);
        image.Fill();
        Blur.ApplyTo(shadow.Bitmap, blurx, blury);
        shadow.OffsetX = shadowoffsetx;
        shadow.OffsetY = shadowoffsety;
        shadow.Opacity = shadowopacity;
    }

Now, we're ready to paint the button. We begin by adding a layer for the border. We select a circle the size of the button and fill it with a radial gradient. Implementing the radial gradient code was easy: I just needed to calculate the distance from the current pixel to the center point, convert it to a value between 0 and 1, and mix the foreground and background color.

    // border
    Layer borderlayer = image.Layers.Add();
    image.Selection.SelectEllipse(
        margin,
        margin,
        buttonwidth,
        buttonwidth,
        SelectionMode.Replace);
    image.ActiveLayer = borderlayer;
    image.ForeColor = bordercolor;
    image.BackColor = Color.Black;
    image.Fill(
        borderfillx0,
        borderfilly0,
        borderfillx1,
        borderfilly1,
        FillType.Radial);

We fill the inner area of the button with the button color. When the method Fill() is called with no parameters, it will fill the current selection with the background color.

    // button color
    image.Selection.SelectEllipse(
        buttoncolorx,
        buttoncolory,
        buttoncolorwidth,
        buttoncolorwidth,
        SelectionMode.Replace);
    image.BackColor = buttoncolor;
    image.Fill();

We don't want our button to look flat. To achieve a nice effect, we will darken the top and left of the inner area a bit. To darken the left, we select a sickle shape by selecting the inner area and subtracting a circle from the current selection. The selection is feathered and filled with black. The method Feather() applies a blur filter to the selection mask. The same effect could be achieved by growing the selection and then applying a blur filter. To darken the top, we do the same: we select the inner area and subtract a circle about the same size, feather the selection, and fill it with black. We also add a mask to the shade layer because the feathering of the selection influences pixels outside the button, and we don't want that.

Collapse
    // shade
    Layer shadelayer = image.Layers.Add();
    image.ActiveLayer = shadelayer;
    image.Selection.SelectEllipse(
        buttoncolorx - 2,
        buttoncolory - 2,
        buttoncolorwidth + 4,
        buttoncolorwidth + 4,
        SelectionMode.Replace);
    image.Selection.SelectEllipse(
        shadeleftx,
        shadelefty,
        shadeleftwidth,
        shadeleftheight,
        SelectionMode.Subtract);
    image.Selection.Feather(featherleft);
    image.BackColor = Color.Black;
    image.Fill();
    shadelayer.Opacity = shadeopacity;
    image.Selection.SelectEllipse(
        buttoncolorx - 2,
        buttoncolory - 2,
        buttoncolorwidth + 4,
        buttoncolorwidth + 4,
        SelectionMode.Replace);
    image.Selection.SelectEllipse(
        shadetopx,
        shadetopy,
        shadetopwidth,
        shadetopheight,
        SelectionMode.Subtract);
    image.Selection.Feather(feathertop);
    image.Fill();

    // shade mask -- set smoothing mode !!!
    FastBitmap mask = new FastBitmap(width, height, 
                            PixelFormat.Format24bppRgb);
    Graphics g = Graphics.FromImage(mask._bitmap);
    g.SmoothingMode = SmoothingMode.AntiAlias;
    SolidBrush blackbrush = new SolidBrush(Color.Black);
    SolidBrush whitebrush = new SolidBrush(Color.White);
    g.FillRectangle(
        blackbrush,
        0,
        0,
        width,
        height);
    g.FillEllipse(
        whitebrush,
        buttoncolorx,
        buttoncolory,
        buttoncolorwidth,
        buttoncolorwidth); 
    whitebrush.Dispose();
    blackbrush.Dispose();
    g.Dispose();
    shadelayer.Mask = mask;

Before we can put the text on the button, we have to create a Font object and preprocess the text a bit. If we encounter a '\n' in the text, we replace it by a Environment.NewLine string. If we encounter a double backslash ("\\"), we replace it with a single backslash.

Collapse
    // text
    Layer textlayer = image.Layers.Add();
    FontStyle fs = FontStyle.Regular;
    for (Int32 i = 0; i < fontstyle.Length; i++) {
        switch (fontstyle[i]) {
            case 'b':
                fs |= FontStyle.Bold;
                break;
            case 'i':
                fs |= FontStyle.Italic;
                break;
            case 'r':
                fs |= FontStyle.Regular;
                break;
            case 's':
                fs |= FontStyle.Strikeout;
                break;
            case 'u':
                fs |= FontStyle.Underline;
                break;
        }
    }
    Font f = new Font(fontface, fontsize, fs);
    StringFormat format = new StringFormat();
    format.Alignment = StringAlignment.Center;
    format.LineAlignment = StringAlignment.Center;
    format.Trimming = StringTrimming.None;
    SolidBrush brush = new SolidBrush(textcolor);
    StringBuilder sb = new StringBuilder(text.Length);
    for (Int32 i = 0; i < text.Length; i++) {
        if (text[i] == '\\') {
            if (i + 1 < text.Length) {
                if (text[i + 1] == 'n') {
                    sb.Append(Environment.NewLine);
                    i++;
                } else if (text[i + 1] == '\\') {
                    sb.Append('\\');
                    i++;
                } else {
                    sb.Append('\\');
                }
            } else {
                sb.Append('\\');
            }
        } else {
            sb.Append(text[i]);
        }
    }
    textlayer.DrawText(0, 0, width, height, 
              sb.ToString(), f, brush, format);
    brush.Dispose();
    f.Dispose();
    textlayer.Opacity = 1.0 - texttrans;

And now, ladies and gentlemen, the finishing touch: the highlighting. We select an ellipse and fill the selection with a linear gradient which changes gradually from white to transparent. After that, we flatten the image and we're done. Tadaa! A very nice aqua button!

    // highlight
    Layer highlightlayer = image.Layers.Add();
    image.ActiveLayer = highlightlayer;
    image.ForeColor = Color.White;
    image.BackColor = Color.Transparent;
    image.Selection.SelectEllipse(
        highlightx,
        highlighty,
        highlightwidth,
        highlightheight,
        SelectionMode.Replace);
    image.Fill(
        0,
        highlightfilly0,
        0,
        highlightfilly1,
        FillType.Linear);

    // result
    FastBitmap result = image.Flatten();
 

Sample Image - ImageConverter

Introduction

Every week I take dozens of pictures during the soccer games of Kevin, my 7 year old son. Most of these pictures are placed on a web site created for his team. And every week I find myself performing the ever recurring task of resizing the images (mostly 3072 x 2048) to something more friendly (e.g.: 768 x 512). Why? Just for those less fortunate that have no ADSL or so.

Of course, every repeating task is prone to be automated, and a first application was born to resize the pictures according to my wishes. To cope with different source and target paths, as well as different ways of resizing, the application needed a user interface. Working on the application and its (simple, yet effective) user interface, generalizing the use of the application is evident. The next step then is to share it with all of you and hope you find the application or some code snippet useful.

Using Image Converter

Just download the zipped executable, unzip it, and open it. After you have opened ImageConverter, you can open the image files that you want to convert by pressing the Open... button. The target path for the converted images is automatically set to the source path, if not set already. By pressing the Browse... button, you can select an alternative path for the converted images.

Before you start the conversion process, you can define the image format after conversion, you can define how the images should be named, and you can define the required image size.

For naming the target images, you can use the original name, and the corresponding extension for the target image format is added. If a file with the resulting name already exists, it will be overwritten. Another option is to use a prefix defined by you. Each target image file will get a unique name based on this prefix and a sequence number.

The target size can be a specified size, which means that the original image will be stretched. If you are just interested in obtaining images for which the largest of width or height is less than or equal to the specified maximum, the image will be scaled if either width or height is larger than the specified maximum. The third option is to scale each image by the specified percentage.

Using the code

The main code for the application is in FormImageConverter.cs whilst the code for the Thumbnail control I use is in Thumbnail.cs.

Selecting Images

The images to be converted are selected by invoking the ShowDialog method of a standard OpenFileDialog instance. The selected image files are processed by the DisplayThumbnails method, which disposes off any Thumbnail control still present. Then for each image file, a Thumbnail control is created and added to panelThumbnails.Controls. Note that if the file to be loaded is not a (valid) image file, an OutOfMemoryException is thrown and the Thumbnail control will not be created.

Conversion Process Thread

Because I want some progress information displayed during the conversion process, the conversion process takes place in another thread. The thread is created and started from the event handler for the Convert button.

private void buttonConvert_Click(object sender, System.EventArgs e)
{
    this.Cursor = Cursors.WaitCursor;
    _convertThread = new Thread(new ThreadStart(ConvertImageFiles));
    _convertThread.Start();
}

The ConvertImageFiles method takes care of determining the extension and image format for the target image, as well as the name for the image file. Using this information and knowing the size for the target image, the original image as represented by the Thumbnail control can be converted.

Collapse
private void ConvertImageFiles()
{
    this.Cursor = Cursors.WaitCursor;
    _converting = true;
    this.EnableControls();
    try
    {
        ...
        // determine the target size
        System.Drawing.Size targetSize = this.DetermineTargetSize(thumbnail.Image);
        System.Drawing.Image targetImage = null; 

        try
        {
            // the new image is created and written based on
            // the original, the target size and the desired image format
            targetImage = new Bitmap(thumbnail.Image, targetSize);
            targetImage.Save(targetFileName, targetImageFormat); 
            // invoke the delegate for updating progress information
            this.Invoke(_imageInfoDelegate, 
                 new object[] { thumbnail, targetFileName, targetSize });
            targetImage.Dispose();
        }
        catch (System.Threading.ThreadAbortException e)
        {
            throw e;
        }
        catch {}
        ...
    }
    catch {}
    finally
    {
        this.Cursor = Cursors.Default;
        _converting = false;
        this.EnableControls();
    }
}

To prevent the user from changing the settings during the conversion process, the controls on the main form are disabled at the start, and the Close button becomes a Cancel button. Pressing the Cancel button causes the thread to be aborted by calling _convertThread.Abort method, which causes a System.Threading.ThreadAbortException to be thrown. The exception is caught and re-thrown until the outer try-catch is reached, and the controls can be enabled again.

To update the progress information during the conversion process, a delegate is executed using the Invoke method on the main form. The progress information uses the thumbnail, the target file name, and the target size. These objects are put in an object array, which holds the arguments for the DisplayImageInfo method to be called.

// the delegate
private delegate void ImageInfoDelegate(Thumbnail thumbnail, 
              string targetFile, System.Drawing.Size toSize);

private ImageInfoDelegate _imageInfoDelegate = null;

_imageInfoDelegate = new ImageInfoDelegate(DisplayImageInfo);

// invoke the delegate for updating progress information
this.Invoke(_imageInfoDelegate, new object[] { thumbnail, 
                                 targetFileName, targetSize });

Enabling/Disabling Controls

As noted, the various controls on the main form are disabled during the conversion process and the Close button changed into a Cancel button. Also, if no images have been selected or no target path defined, the Convert button is disabled. This is implemented in the EnableControls method, which has to be called every time the conditions queried in the method have changed.

private void EnableControls()
{
    this.buttonConvert.Enabled = 
        !_converting &&
        this.panelThumbnails.Controls.Count > 0 &&
        this.labelTargetPathValue.Text.Trim() != "";
    this.buttonBrowseTargetPath.Enabled = !_converting;
    this.buttonOpen.Enabled = !_converting;
    this.groupBoxOnConvert.Enabled = !_converting;
    this.groupBoxTargetSize.Enabled = !_converting;
    this.comboBoxTargetFormat.Enabled = !_converting;
    this.buttonClose.Text = _converting ? "Cancel" : "Close";
}

Thumbnail Control

The Thumbnail control is a UserControl on which a Panel is placed that contains a PictureBox and two Labels. The PictureBox holds the thumbnail image, the file name Label, and the original image size Label. The border around the control is obtained by setting the control's DockPadding to 2 for all sides. The thin line between the PictureBox and the file name Label is the BackColor of the underlying Panel 'shining' through. This is accomplished by setting both Labels to dock on the bottom and by giving the PictureBox the size of the remaining space with the height set to just one pixel less.

Thumbnail Control

The main task of the Thumbnail control is to show a thumbnail for each loaded image file and to present easy access to the corresponding image and its file path. The file path is supplied to the constructor, and the file is loaded using the FromFile method.

public Thumbnail(string filePath)
{
    InitializeComponent();
    _filePath = filePath;
    try
    {
        _image = System.Drawing.Image.FromFile(_filePath);
    }
    catch (System.OutOfMemoryException e)
    {
        // file does not represent a valid image
        throw e;
    }

    ...

Loading a file that does not represent a (recognizable) image causes an OutOfMemoryException, so the exception is caught and thrown again to inform the code constructing the thumbnail.

If it is loadable, the size for the thumbnail image is calculated and the visual feedback is set.

    ...

    int max = Math.Min(this.pictureBox.Width, this.pictureBox.Height);
    int width = _image.Width;
    int height = _image.Height;
    // determine the size for the thumbnail image
    if (_image.Width > max || _image.Height > max)
    {
        if (_image.Width > _image.Height)
        {
            width = max;
            height = (int) (_image.Height * max / _image.Width);
        }
        else
        {
            width = (int) (_image.Width * max / _image.Height);
            height = max;
        }
    }
    // set feedback information
    this.pictureBox.Image = new Bitmap(_image, width, height);
    this.labelFileName.Text = Path.GetFileName(_filePath);
    this.labelImageSize.Text = string.Format("{0} x {1}", 
                       _image.Size.Width, _image.Size.Height);
}

Aqua Gauge

C#/자료실 2008/06/16 00:57 Posted by <!--r'i"z&i\n+#]]x juree23
Screenshot - AquaGauge.gif

Introduction

I have chosen to develop this .NET user control to explore the easy yet powerful .NET GDI+. This simple gauge control developed using .NET 2.0 can cater to the entire range of monitoring purposes. Let's see how to develop such a glossy control using GDI+.

Overridden UserControl Methods

Normally, If we create user controls that have been fully drawn by the user, we should override the OnPaint and OnPaintBackground methods. Additionally, the control styles are to be set as appropriate. The following common styles can be set using this.SetStyle(ControlStyles.XXXXX, true/false);.

SupportsTransparentBackColor This will enable your control to support a transparent backcolor if set to true.
ControlStyles.ResizeRedraw Allows repainting when the control is resized.
ControlStyles.AllPaintingInWmPaint If true, the control ignores the window message WM_ERASEBKGND to reduce flicker.
This style should only be applied if the UserPaint bit is set to true.
ControlStyles.UserPaint If true, the control paints itself rather than the operating system doing so.
ControlStyles.OptimizedDoubleBuffer If true, the control is first drawn to a buffer rather than directly to the screen, which can reduce flicker. If you set this property to true, you should also set the AllPaintingInWmPaint to true.

The OnPaint and OnPaintBackground methods will be called whenever the control needs to be repainted. For example, when the control is resized or the form is minimized and maximized, the OnPaint method will be called.

OnPaintBackground vs. OnPaint

OnPaintBackground paints the background (and thereby the shape) of the Window and is guaranteed to be fast. In contrast, OnPaint paints the details and might be slower because individual paint requests are combined into one Paint event that covers all areas that have to be redrawn. You might want to invoke the OnPaintBackground if, for instance, you want to draw a gradient-colored background for your control.

While OnPaintBackground has an event-like nomenclature and takes the same argument as the OnPaint method, OnPaintBackground is not a true event method. There is no PaintBackground event and OnPaintBackground does not invoke event delegates. When overriding the OnPaintBackground method, a derived class is not required to invoke the OnPaintBackground method of its base class.

Drawing the Guage Dial

First, let's see how to draw the dial. The dial requires a Scale, Threshold Indicator, some text and the current value to be displayed.

Drawing the scale requires calculating the positions for the rules that are to be drawn at the circumference. Let's say we need to draw a scale starting from 0 to 10 from angle 90 degrees to 270 degrees on the dial. In this case, the difference in the degrees (270-90 = 180) must be divided into 10 parts. To find the position for each part to be drawn, we need the following formula:

x = centerX + radius * cos(180/partNo)
y = centerY + radius * sin(180/partNo)

Note: when using Math.Cos or Math.Sin we should give angles in radians.

Circle Formula

After finding the position, we can draw any type of scale mark on the circumference. I have chosen to draw a line as a scale mark. Since the dial area is not going to be changed often, it can be drawn in OnPaintBackground overridden method.

Drawing the Pointer

The pointer may need to be repainted often. So, it is better to draw it in the OnPaint method. Finding the pointer position is the same as the logic for drawing the scale. The pointer can be drawn using graphicsObj.FillPolygon() method and it can be transformed to any angle that will represent the current value. Otherwise, the pointer can be redrawn for every change made for the current value.

Drawing the Glossiness

Drawing the glossiness is very simple. All you have to do is, after painting all the dial and pointer, fill two ellipses with gradient coloring. The LinearGradientBrush class provides the ability to draw gradient fills. Masking the gradient layer over the dial gives the glossiness as shown in the below figure.

Glosiness

Using the AquaGauge Control

This AquaGauge control can be used as any other user control provided by Windows. The following are the control-specific properties that can be used to configure this gauge to suit your requirements.

Property Name Type Description
DialColor Color Gets or Sets the background color for the gauge.
DialText String Gets or Sets the Text displayed on the gauge dial.
EnableTransparentBackground bool Enables or Disables Transparent Background color. Note: Enabling this will reduce the performance and may make the control flicker.
Glossiness float Gets or Sets the strength of the Glossiness.
MaxValue float Gets or Sets the maximum value shown on the gauge scale.
MinValue float Gets or Sets the minimum value shown on the gauge scale.
NoOfDivisions int Gets or Sets the number of divisions on the gauge scale.
NoOfSubDivisions int Gets or Sets the number of subdivisions displayed on the scale for each division.
RecommendedValue float Gets or Sets the recommended value on the scale. This will be used as a pivot point for drawing the threshold area.
ThresholdPercent float Gets or Sets the Threshold area percentage on the scale.
Value float Gets or Sets the value to which the pointer will point.

Points of Interest

Whenever we draw images with lots of manipulations, it is recommended to draw it on an image object and then paint. For example, drawing the gauge dial requires lots of CPU-consuming operations. So, we can draw the dial onto an image and then draw using graphicsObj.DrawImage(). Whenever changes are made on the dial properties, we can recreate the image object. It would improve the performance.

Generate Thumbnail Images from PDF Documents

C#/자료실 2008/06/16 00:56 Posted by <!--r'i"z&i\n+#]]x juree23
 

Thumbnail images

Introduction

This article presents VB.NET code to create thumbnail images from a directory of Adobe Acrobat PDF documents.

Often when looking for documents it is much easier to find what you want visually, for example seeing the cover of a document.

The application was written for a website that I was developing that needed to display links to PDF documents. Instead of just showing a little PDF icon next to each document we wanted to display the front page of the actual document.

As shown below, this gives the listings better aesthetics and also enables the users to find documents quicker if they recognise it.

PDF Icons
VS
Custom Icons

Note: please ignore the strange text, lorem ipsum is simply dummy text for this example

Hopefully people will agree that having the actual front cover displayed next to the hyperlink works better than the generic PDF icon.

Background

The web site was a Content Management System (CMS) so new PDF documents were uploaded to the site by the users. We then had this application scheduled as a batch service to run every 5 minutes and check for new files.

In the backend system the documents have metadata stored in a SQL Server 2000 database. We would then write a flag to say the thumbnail had been created and when we generated the HTML content for the page request in ASP/ASP.NET we would return the appropriate IMG tag and source as appropriate.

Using the Acrobat SDK also meant we could programmically read the PDF metadata and retrieve the number of pages in the document, which could then be displayed as well. Although the end users could have entered that information it meant less work for them and a better overall impression of the web site. Another advantage was that many users relied on the number of pages to determine how large the document was rather than the more technical Kb/Mb value.

Approach

To generate the thumbnail image for each document I used the Adobe Acrobat 5.0 SDK and the Microsoft .NET 1.1 Framework.

Note: do not confuse the thumbnails that are part of a PDF document with the .png files this application generates.

The Acrobat SDK combined with the full version of Adobe Acrobat (sadly the free reader does not expose the COM interfaces) exposes a COM library of objects that can be used to manipulate and access PDF information.

So using these COM objects via COM Interop, we can load the PDF document, get the first page and render that page to the clipboard. Then using the .NET Framework we can copy this to a bitmap, scale and combine that image and then save the result as a .gif or .png file.

Original rendered PDF page scaled down

At first I just saved the scaled down image, but then decided to “fancy” up the thumbnail with a drop-shadow and folded corner. To achieve this effect I created a transparent .gif, called pdftemplate_portrait.gif, using Macromedia Fireworks MX where the main body of the page template was transparent.

By making the bottom-left pixel transparent too we can easily set the transparent colour for a bitmap in .NET.

I keep the top-right of the image white where the corner folds over, that means I can just combine the images by drawing the transparent template directly over the PDF image to achieve the final look.

Compositing the template and rendered image together

Pre-requisites

The full version of Adobe Acrobat (the free reader does not expose the COM interfaces) which exposes a COM library of objects to manipulate and access PDF information.

The Adobe Acrobat 5.0 SDK which is a free download from the Adobe Solutions Network website (note: the site requires registration). The latest SDK for Acrobat 6.0 requires paid membership, so we will use the previous SDK version.

Link on Adobe website for the Acrobat 5.0 SDK

To quickly see if you have the full version of Adobe Acrobat installed, use regedit.exe and look under HKEY_CLASSES_ROOT for entry entry called AcroExch.PDDoc.

Check for AcroExch.PDDoc

You'll also need the .NET 1.1 Framework and some PDF files to test the solution.

The code was written in VB.NET using the .NET 1.1 Framework and Visual Studio.NET 2003 on Windows XP, but there is no reason it wouldn't work on Windows NT/2000 or .NET 1.0.

Using the code

The code is quite simple with a try/catch over the main body. It is purposely in one large block so it's easy to see what it happening and to step through and examine with the debugger.

Initially we create an instance of AcroExch.PDDoc using late-binding. The referenced Adobe Acrobat 5.0 Type Library (Acrobat.tlb from C:\Program Files\Adobe\Acrobat 5.0 SDK\InterAppCommunicationSupport\Headers) does not expose a COM class you can create using early-binding. By referencing the type library we can get the Intellisense and strong-typing of the other Acrobat objects.

Pass the filename of the PDF documents to be opened to the PDDoc object, which can then be accessed to get metadata on the document; GetNumPages() and GetInfo() for custom document properties.

' Create the document (Can only create the AcroExch.PDDoc object using
' late-binding)
pdfDoc = CreateObject("AcroExch.PDDoc")

' Open the document
ret = pdfDoc.Open(inputFile)

If ret = False Then
    Throw New FileNotFoundException
End If

' Get the number of pages
pageCount = pdfDoc.GetNumPages()

Set a reference to the first page of the document as pdfPage, which is of type Acrobat.CAcroPDPage. From this we can get a rectangle object of the actual page dimensions. One strange point to notice here is that the Adobe Acrobat SDK documentation seems incorrect, as the PDFRect that is returned from the GetSize() method has IDispatch properties x, y but the PDFRect we need to supply to CopyToClipboard must have left, right, top, bottom.

Finally we render the PDF page to the clipboard at full size. We could have Acrobat scale the image down for us by a percentage, but we can get better visual results using the .NET scaling algorithms of the Bitmap class.

It would have been more efficient to render directly to an off-screen bitmap, and also not have overwritten what ever was previously on the clipboard, but I found the clipboard method the most stable way to get a rendered bitmap of the page using Acrobat.

Although it looks like the pdfPage object has a DrawEx method that can take an H<CODE>DC I couldn't get the method to work in a consistently successful way. Calling DrawEx in the paint event of a Windows Forms application did work but it still wouldn't write to an off-screen bitmap directly. Therefore the clipboard method is used and if the process runs on a batch server it won't cause too much worry.

Note: the Draw method is deprecated, as it only works on Win16 systems where hWnd was unique to Windows and not to each process as on NT.

' Get the first page
pdfPage = pdfDoc.AcquirePage(0)

' Get the size of the page
' This is really strange bug/documentation problem
' The PDFRect you get back from GetSize has properties
' x and y, but the PDFRect you have to supply CopyToClipboard
' has left, right, top, bottom
pdfRectTemp = pdfPage.GetSize

' Create PDFRect to hold dimensions of the page
pdfRect = CreateObject("AcroExch.Rect")

pdfRect.Left = 0
pdfRect.right = pdfRectTemp.x
pdfRect.Top = 0
pdfRect.bottom = pdfRectTemp.y

' Render to clipboard, scaled by 100 percent (ie. original size)
' Even though we want a smaller image, better for us to scale in .NET
' than Acrobat as it would greek out small text
' see http://www.adobe.com/support/techdocs/1dd72.htm

Call pdfPage.CopyToClipboard(pdfRect, 0, 0, 100)

Dim clipboardData As IDataObject = Clipboard.GetDataObject()

Grab the rendered page bitmap from the clipboard and based on the pdfRectTemp object determine if it's a portait or landscape document. Set the correct file to load as the template, and if it is landscape, switch the width and height.

Dim pdfBitmap As Bitmap = clipboardData.GetData(DataFormats.Bitmap)

' Size of generated thumbnail in pixels
Dim thumbnailWidth As Integer = 38
Dim thumbnailHeight As Integer = 52
Dim templateFile As String

' Switch between portrait and landscape
If (pdfRectTemp.x < pdfRectTemp.y) Then
   templateFile = templatePortraitFile
Else
   templateFile = templateLandscapeFile
   ' Swap width and height (little trick not using third temp variable)
   thumbnailWidth = thumbnailWidth Xor thumbnailHeight
   thumbnailHeight = thumbnailWidth Xor thumbnailHeight
   thumbnailWidth = thumbnailWidth Xor thumbnailHeight
End If

Load the template file as as Bitmap and as an Image. We use both because the Bitmap class supports MakeTransparent and the image can easily be passed to the Graphics.DrawImage() method. It is slightly inefficent but speed isn't the primarly objective for this application.

Render the pdfImage using the GetThumbnailImage() method of the .NET Framework Bitmap class, this provides a very smooth scaled version of the image.

Next create a blank bitmap with room for the template border. Set the templateBitmap to use the bottom-left pixel of the image as the transparency colour using calling MakeTransparent(). See an article on Chris Sells website for more on transparencies in .NET.

Using the new blank bitmap, draw the rendered pdf page image to it and then the template with transparency directly over the top. Because it is transparent the main area of the page template will still appear through.

Finally, save the composited image back as a .png or .gif file, although .png does look better.

Collapse
' Load the template graphic
Dim templateBitmap As Bitmap = New Bitmap(templateFile)
Dim templateImage As Image = Image.FromFile(templateFile)

' Render to small image using the bitmap class
Dim pdfImage As Image = pdfBitmap.GetThumbnailImage(thumbnailWidth, _
  thumbnailHeight, _
  Nothing, Nothing)

' Create new blank bitmap (+ 7 for template border)
Dim thumbnailBitmap As Bitmap = New Bitmap(thumbnailWidth + 7, _
  thumbnailHeight + 7, _
  Imaging.PixelFormat.Format32bppArgb)

' To overlayout the template with the image, we need to set the transparency
' http://www.sellsbrothers.com/writing/default.aspx?
' content=dotnetimagerecoloring.htm
templateBitmap.MakeTransparent()

Dim thumbnailGraphics As Graphics = Graphics.FromImage(thumbnailBitmap)

' Draw rendered pdf image to new blank bitmap
thumbnailGraphics.DrawImage(pdfImage, 2, 2, thumbnailWidth, thumbnailHeight)

' Draw template outline over the bitmap (pdf with show through the
' transparent area)
thumbnailGraphics.DrawImage(templateImage, 0, 0)

' Save as .png file
thumbnailBitmap.Save(outputFile, Imaging.ImageFormat.Png)

Write some feedback to the console as we work through each of the files.

Then actively release the reference code to the COM objects as Acrobat it isn't the best suited application to opening and closing multiple PDF documents without falling over. Luckily the code doesn't cause Acrobat to display any UI that might cause the process to hang waiting for user interaction.

Console.WriteLine("Generated thumbnail... {0}", outputFile)

thumbnailGraphics.Dispose()

pdfDoc.Close()
Marshal.ReleaseComObject(pdfPage)
Marshal.ReleaseComObject(pdfRect)
Marshal.ReleaseComObject(pdfDoc)

Creating Glow Button

C#/자료실 2008/06/16 00:55 Posted by <!--r'i"z&i\n+#]]x juree23

Screenshot - Demo.jpg

Introduction

This is my very first article to any open source site. Since I've gotten a lot useful article from this site, I'll be glad if I can to contribute to this great site.

This article will explain how to make a button that has a glow feature.

Background (optional)

When I installed Windows Vista, I was amazed by it's appearance. It had a very nice user interface and so many eye candy controls. That make me think about making something just like that. I've created some fancy controls that look like Vista components since that day. Also, I've always thought about making an article or tutorial to share my knowledge. Finally, while creating this glow button control, I've decided to make an article for it too.

So why Glow Button? I've been interested in this control since I played with Vista Windows, especially with its Minimize, Maximize and Close Buttons. They have some fancy glow affects. And thanks to .NET Framework 2.0, it's easier to create them.

Using the code

Basically, to create the glow effect, you have to make a "Layer" that will create the glow with GDI+. Unfortunately, .NET Framework 2.0 doesn't allow a control that can make other controls mid-transparent. Or rather, when you place a control above another control, you can't see the control below, even you set full transparency at the upper control. The trick for this button is to request from another button that surrounds it to make a glow layer for that control.

Since we want to ask other glow controls to make glow effects, we need a layer status for the control:

Public Enum LayerStatus
    None = 0
    Self = 1
    TopLeft = 2
    Top = 3
    TopRight = 4
    Left = 5
    Right = 6
    BottomLeft = 7
    Bottom = 8
    BottomRight = 9
End Enum

Now we have a status for the control to make layer as requested. If we must ask another surrounding button to make glow effect, how can we do that if the button is at the edge, side, top, bottom etc? For this problem, we need a special container for our control, so the control at edge or side can ask this container to make the glow effect. Let's name it "Grid".

Screenshot - Grid.jpg

Another feature that we will add is the ability to change themes dynamically. For this, we will use a colortable class called GlassColorTable and some defined colors for our control. Let's name it ColorSet. Also remember that a button has four default states, which is: Normal, Highlighted (Mouse Over), Pressed and Disabled. For the moment, I'm not including Disabled state, due to to the fact that I don't have enough time to experiment with it. I'll include it when I update my article.

Collapse
Public Interface IGlassColor
    Enum States
        Normal = 0
        Highlighted = 1
        Pressed = 2
        Disabled = 3
    End Enum

    Sub NormalState()
    Sub HighlightState()
    Sub PressedState()
    Sub DisabledState()
End Interface

Public Class ColorSet
    'Normal State
    Public BackgroundHigh As Color
    '.
    '.
    '.
    Public TextColor As Color

    'Highlight State
    Public BackgroundHighFocus As Color
    '.
    '.
    '.
    Public TextColorFocus As Color

    'Glow Set
    Public GlowCenter As Color
End Class

Public Class GlassColorTable
    Implements IGlassColor

    Protected _BackgroundHigh As Color
    Protected _BackgroundLow As Color
    Protected _ShineHigh As Color
    Protected _ShineLow As Color
    Protected _BorderLeft As Color
    Protected _BorderRight As Color
    Protected _BorderTop As Color
    Protected _BorderBottom As Color
    Protected _TextColor As Color
    Protected _GlowCenter As Color

    Private _State As IGlassColor.States
    Private _cSet As ColorSet

    Public Overridable ReadOnly Property BackgroundLow() As Color
        Get
            Return _BackgroundHigh
        End Get
    End Property
    
    '.
    '.
    '.
End Class

To change themes dynamically, we must create a property.

<Browsable(False)> _
Public Property Renderer() As ColorSet
    Get
        Return _ColorTable.Renderer
    End Get
    Set(ByVal value As ColorSet)
        _ColorTable.Renderer = value
        _ColorTable.State = IGlassColor.States.Normal
        Me.Refresh()
    End Set
End Property

Since we now have the ability to change themes for the button, we must let the button know which color we want to be layered from another control.

Screenshot - Themed.jpg

<Browsable(False)> _
Public Property LayerColor() As Color
    Get
        Return _ColorTable.GlowCenter
    End Get
    Set(ByVal value As Color)
        _LayerColor = value
    End Set
End Property

So, the most important part is done. It's time to use them for our application. Since we must ask help from another control to make the glow effect, we must set up in each control events which are "mouse enter" and "mouse leave" events.

Private Sub GlowButton1_MouseEnter(ByVal sender As Object, 
    ByVal e As System.EventArgs) Handles GlowButton1.MouseEnter
    GlowButton2.Layer = GlowingButton.GlowButton.LayerStatus.Left
    GlowButton4.Layer = GlowingButton.GlowButton.LayerStatus.Top
    GlowButton5.Layer = GlowingButton.GlowButton.LayerStatus.TopLeft

    GlowButton2.LayerColor = GlowButton1.LayerColor
    GlowButton4.LayerColor = GlowButton1.LayerColor
    GlowButton5.LayerColor = GlowButton1.LayerColor

    Grid1.GlowColor = GlowButton1.LayerColor
    Grid1.GlowStartPoint = New Point(GlowButton1.Location.X - 7, 
        GlowButton1.Location.Y - 7)
    Grid1.GlowStyle = GlowingButton.Grid.GlowStyles.TopLeft
End Sub

Private Sub GlowButton1_MouseLeave(ByVal sender As Object, 
    ByVal e As System.EventArgs) Handles GlowButton1.MouseLeave
    GlowButton2.Layer = GlowingButton.GlowButton.LayerStatus.None
    GlowButton4.Layer = GlowingButton.GlowButton.LayerStatus.None
    GlowButton5.Layer = GlowingButton.GlowButton.LayerStatus.None

    Grid1.GlowStyle = GlowingButton.Grid.GlowStyles.None
End Sub

To change themes dynamically, use the Renderer property.

For Each g As GlowingButton.GlowButton In Grid1.Controls
    g.Renderer = New GlowingButton.DiamondRed
Next

Points of Interest

Since we need to ask other controls to apply effects, we have to setup every control we have in the application. It will take time to setup everything, especially when we work with many buttons. To solve this problem, I suggest you make a class that inherits Grid control, place all glow buttons in the grid, and perform the required setup automatically with AddHandler methods. When I have more spare time, I'll explain in separate articles about this.

Additional notes about the demo: did some of you notice my other reason for creating this control? Yes, it's a Sudoku puzzle! My original motive with this control was for creating a Sudoku Puzzle Solver that can apply customized regions (that's why it needed themes or colorsets). The solver itself is still a long way to go because I've include it with many useful features.

That's all.