text: NOTE: These files have the names of:
  The challenge is to create a project from scratch, which focuses just as much on how to rotate an image as it does on doing it all in code. From 'scratch', 'home-made', applications are what is being looked for. Have you got what it takes?
  The concept to rotating images is simple. First, you find a place to put the corners of the picture, then you map the pixels and a rotated image is made.
  But wait, that sounds like a lot of work.
  Well, it is. Not just for you the programmer, but also for the program. To do this would take a tremendous amount of resources, and time (at the computers scale).
  There has GOT to be a better way.
  Luckily, there is. For this subject, the Graphics class is held in high esteem. Not just because it can do what we want and more, but also because one can be found residing in the PaintEventArgs of a form, critical to displaying images, diagrams, and other things at runtime. This 'WonderClass' is great and will seem to be the center of attention for our code.
  Graphics
  PaintEventArgs
  WonderClass
  But before we can get to the code...We need a respectable GUI!
  Create a new VB project (note this app is possible in the express editions of Visual Studio):
  Name it PocketWatchVB and click OK.
  PocketWatchVB
  When a blank form appears, change:FormBorderStyle to FixedSingle
  FormBorderStyle
  FixedSingle
  We do this so that the user can't resize the form, causing possible errors in the future.
  In order to give a smooth animation, set DoubleBuffered to True. This will make sure that you don't get any animation flashes, or bad quality.
  DoubleBuffered
  True
  Once again, be sure that the style is set to FixedSingle.
  FixedSingle.
  Before you do the next step, I would recommend that you have the files that are going to be used as the Background and watch hands. You can either download them below, make your own, or you can use the source code to retrieve the images (SRC.zip\Watch\Resources).
  If you are going to make your own images, the picture size that this article is made for is 256x256. They should all have a transparent background, and the hands should be created slightly smaller than the watch (but the image size must still be 256x256).
  Import the four Images you should have saved, by changing Form1's BackgroundImage and importing all four images.
  Form1
  BackgroundImage
  Import all four images into the .resx file.
  Choose (none).
  (none).
  None? The whole purpose of choosing none after we imported the pictures in Resources is so that we don't have to worry about outside paths in our code, the program is more portable, and it makes the code cleaner to reference to resources. So don't set any BackgroundImages this was just for the sake of importing resources.
  BackgroundImage
  Make the size of the form 370,370.
  This would put our images in the dead-center of the form. Just for looks.
  If your form looks like this, Good Job! The key point is the fact that this is a blank form. To help out the 'Homemade' aspect everything is done at runtime (actually it's much faster this way, and is better for overlaying pictures).
  In order to get the idea of what needs to be done before we start coding, let's use a table.
  It is easy to see that most of the code will be used to rotate and overlay the hands of the clock, while the first half of the procedures are spent on getting to that point.
  Before everything will work the way it should, some declarations are needed. These are the ones necessary to the success of this project.
  Import these in the Declarations Area:
  Imports System.Windows.Forms
  Imports System.Drawing
  Imports System.Drawing.Drawing2D
  Then declare the following as variables of their specific type. We will use these later:
  Dim clockHour As Double
  Dim clockmin As Integer
  Dim hourAng As Integer
  Dim minAng As Integer
  Dim secAng As Integer
  Dim secBMP As Image = (My.Resources.secondHand)
  Dim minBMP As Image = (My.Resources.minuteHand)
  Dim hourBMP As Image = (My.Resources.hourHand1)
  Dim watchBMP As Image = (My.Resources.PocketWatchProj)
  Declaring our BMPs before the code runs helps so that we can have everything run smoothly. On the other hand, we need to dispose of them before we close our form. To do this, add a Form1_FormClosed() event handler.
  Form1_FormClosed()
  Private Sub Form1_FormClosed(ByVal sender As Object, _
  ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
  secBMP.Dispose()
  minBMP.Dispose()
  hourBMP.Dispose()
  watchBMP.Dispose()
  End Sub
  OK, down to business. The main muscle of our code will live within the Form1_Paint() event handler. This is where we will literally 'paint' the form. Our painters will be Graphics classes that inherit PaintEventArgs in a way that lets us 'paint' the form. You can also paint controls, panels, and many other things, but the code might need to be tweaked.
  Form1_Paint()
  e.Graphics.DrawImage(WatchBMP, 0, 0)
  To begin, let us paint our pocketwatch onto the back of our form.Since this is within the Form1_paint() Event handler, e refers to the PaintEventArgs. This class allows us access into the Graphics painters that will paint the form. Here we are just telling the 'painters' to paint our picture(which is in Resources) at the point (0,0).
  Form1_paint()
  PaintEventArgs
  'make 12-hour instead of 24-hour
  clockHour = Now.TimeOfDay.Hours
  If clockHour > 12 Then
  clockHour -= 12
  ElseIf clockHour = 0 Then
  clockHour = 12
  End If
  'Set the angles for minute and hour
  hourAng = 30 * ClockHour
  minAng = 6 * Now.TimeOfDay.Minutes
  secAng = 6 * Now.Second
  Before we get our 'painters' to paint the clock's hands, we need to tell them where and how to paint. So this code converts the normal 24-hour time format into the common analog format of 12-hour. It then calculates the angles according to each corresponding formula, which isn't hard to figure out, just figure that there are 12 hours needed, divide 360 by 12, then tell your app to multiply accordingly, and so on.
  Dim sec As New Matrix()
  sec.Translate(1, 1)
  sec.RotateAt(secAng, New PointF(170, 170))
  e.Graphics.Transform = sec
  e.Graphics.DrawImage(secBMP, 0, 0)
  sec.Dispose()
  This snippet makes a Matrix, which before applying the changes to our 'painter', can be manipulated much more successfully than just the normal Graphics class. First, the matrix is positioned, rotated at the point necessary to ensure that the hands to the clock do not move off-center, or even off-screen. Then the changes are applied to our 'painter' using e.Graphics.Transform = sec. After this, the image is drawn onto the form, and the Matrix is disposed to empty resources correctly.
  e.Graphics.Transform = sec
  Because we have three hands on our clock, and all three work similarly, we find that our code tends to stay similar, but with some differences. This is one of those cases.
  Dim min As New Matrix()
  min.Translate(1, 1)
  min.RotateAt(minAng, New PointF(170, 170))
  e.Graphics.Transform = min
  e.Graphics.DrawImage(minBMP, 0, 0)
  min.Dispose()
  Note that the code is the same except for the Image, angle and name, etc. Not much explanation here. Just a repeat of the last snippet, a change here and there.
  Dim hour As New Matrix()
  hour.Translate(0, 0)
  hour.RotateAt(hourAng, New PointF(170, 170))
  e.Graphics.Transform = hour
  e.Graphics.DrawImage(hourBMP, 44, 44)
  hour.Dispose()
  Here is where it changes. We do everything the same except for where the image is plotted. For some reason, If you plot the image at the normal point, it causes it to be off-center, the best point for it is at (44,44).
  Now that our work-bearing procedures are made, we need a way to initiate them.
  Add the Timer tick handler to get this all going.
  Private Sub Timer1_Tick(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles Timer1.Tick
  Me.Refresh()
  End Sub
  OK, wait. Just refresh the form? Refreshing the form causes it to repaint itself. This calls our OnPaint handler which handles all of our duties. So, let's see if this works. Run the form, the clock should be blank for a split-second, then a picture is seen. More like a home-made picture. =)
  OnPaint
  If you did everything correct, your watch should look like this.
  Well, that was different. A simple sounding subject made hard with the challenge to do as much of it at runtime and/or from scratch. A matrix can be used to paint the form. Some lifeless images can be breathed into, and a normal form with NO controls at all can be made to look like a professional-made user control. For once, you can get something out of nothing. That's the beauty of programming.
  This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
  using System;
  using System.Collections.Generic;
  using System.Configuration;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Linq;
  using System.Text;
  using System.Windows.Forms;
  using System.IO;
  using System.Reflection;
  namespace PocketWatch
  {
  public partial class PocketWatch : Form
  {
  private int clockHour;
  private int clockMinute;
  private int clockSecond;
  private int hourAngle;
  private int minuteAngle;
  private int secondAngle;
  private Image watchFacePNG;
  private Image hourHandPNG;
  private Image minuteHandPNG;
  private Image secondHandPNG;
  private Timer clockTimer = new Timer();
  public PocketWatch()
  {
  InitializeComponent();
  clockTimer.Tick += new EventHandler(clockTimer_Tick);
  clockTimer.Interval = 1000;
  clockTimer.Enabled = true;
  try
  {
  Assembly assembly = Assembly.GetExecutingAssembly();
  Stream watchFaceStream = this.GetType().Assembly.GetManifestResourceStream("PocketWatch.Images.WatchFace.png");
  Stream hourHandStream = this.GetType().Assembly.GetManifestResourceStream("PocketWatch.Images.HourHand.png");
  Stream minuteHandStream = this.GetType().Assembly.GetManifestResourceStream("PocketWatch.Images.MinuteHand.png");
  Stream secondHandStream = this.GetType().Assembly.GetManifestResourceStream("PocketWatch.Images.SecondHand.png");
  watchFacePNG = new Bitmap(watchFaceStream);
  hourHandPNG = new Bitmap(hourHandStream);
  minuteHandPNG = new Bitmap(minuteHandStream);
  secondHandPNG = new Bitmap(secondHandStream);
  }
  catch (Exception ex)
  {
  MessageBox.Show("Error loading the background images: " + ex.Message);
  }
  }
  void clockTimer_Tick(object sender, EventArgs e)
  {
  this.Refresh();
  }
  private void PocketWatch_FormClosed(object sender, FormClosedEventArgs e)
  {
  watchFacePNG.Dispose();
  hourHandPNG.Dispose();
  minuteHandPNG.Dispose();
  secondHandPNG.Dispose();
  clockTimer.Dispose();
  }
  private void PocketWatch_Paint(object sender, PaintEventArgs e)
  {
  e.Graphics.DrawImage(watchFacePNG, 0, 0);
  DateTime now = DateTime.Now;
  clockHour = now.Hour;
  clockMinute = now.Minute;
  clockSecond = now.Second;
  if (clockHour > 12)
  {
  clockHour -= 12;
  }
  else if (clockHour == 0)
  {
  clockHour = 12;
  }
  hourAngle = 30 * clockHour;
  minuteAngle = 6 * clockMinute;
  secondAngle = 6 * clockSecond;
  Matrix sec = new Matrix();
  sec.Translate(1, 1);
  sec.RotateAt(secondAngle, new PointF(170, 170));
  e.Graphics.Transform = sec;
  e.Graphics.DrawImage(secondHandPNG, 0, 0);
  sec.Dispose();
  Matrix min = new Matrix();
  min.Translate(1,1);
  min.RotateAt(minuteAngle, new PointF(170, 170));
  e.Graphics.Transform = min;
  e.Graphics.DrawImage(minuteHandPNG, 0, 0);
  min.Dispose();
  Matrix hour = new Matrix();
  hour.Translate(0, 0);
  hour.RotateAt(hourAngle, new PointF(170, 170));
  e.Graphics.Transform = hour;
  e.Graphics.DrawImage(hourHandPNG, 44, 44);
  hour.Dispose();
  }
  }
  }
  Bitmap
  Image
  new
  Image
  new Bitmap()
  PocketWatch.Properties.Resources.WatchFace
  Bitmap();
  new Bitmap();
  watchFacePNG = (PocketWatch.Properties.Resources.WatchFace);
  hourHandPNG = (PocketWatch.Properties.Resources.hourHand);
  minuteHandPNG = (PocketWatch.Properties.Resources.minuteHand);
  secondHandPNG = (PocketWatch.Properties.Resources.secondHand);
  General News Suggestion Question Bug Answer Joke Rant Admin
  Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.