使用C#繪制一個标尺,其實是在學習Gdi繪圖的一些知識,也在試驗出好多人平時總問的一個問題,一個毫米等于多少像素,同時自己也了解了在圖形中尺寸是怎麼計算的。

1.尺寸的确定
在使用标尺測試控件的寬度時,一個像素是指起始點開始後一個像素點才為一個像素,我總是認為一個像素就是螢幕上的一個格子。
2.如何使用重繪時不閃爍
在網上找到許多人的文章,代碼如下,收藏之:
private void InitControl()
{
InitializeComponent();
//減少閃爍
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
}
3.Onpaint的參數中ClipRectangle為需重繪矩形區域,不要誤認為是ClientRectangle。 4.毫米與像素的換算,其實是依賴于顯示裝置的和分辨率以及DPI的,需要使用API确定這些值後,經過換算就可以得到。
public static double MillimetersToPixelsWidth(IntPtr hDc, double length)
{
//以毫米為機關的顯示器寬度
int width = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZSIZE); // 4
//像素數量
int pixels = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZRES); //8
return (((double)pixels / (double)width) * (double)length);
}
public static double PixelsToMillimetersWidth(IntPtr hDc, double length)
{
int width = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZSIZE);
int pixels = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZRES);
return (double)width / (double)pixels * (double)length;
}
這裡收藏一下GetDeviceCaps方法的調用,其聲明為如下:
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int Index);
調用時hdc為裝置句柄,要以使用這種方式擷取:
var hDc = Util.NativeMethods.GetDC(this.Handle);
其中的亦為API函數,需要聲明引用。
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
最後源代碼檔案:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace DrawLine
{
public partial class PixRular : Control
{
public PixRular()
{
InitControl();
}
private void InitControl()
{
InitializeComponent();
//減少閃爍
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
}
public PixRular(IContainer container)
{
container.Add(this);
InitControl();
}
protected override void OnSizeChanged(EventArgs e)
{
this.Invalidate();
base.OnSizeChanged(e);
}
/// <summary>
/// 注意,e.ClipRectangle為需要重繪的矩形區域(失效區域),并不是ClientRectangle,
/// 如果不能确定重繪區域内的内容,則按ClientRectangle全部重繪一遍
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
var clientRect = this.ClientRectangle;
//backgroup
var br = new SolidBrush(Color.LightGoldenrodYellow);
e.Graphics.FillRectangle(br, clientRect);
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(clientRect.Location, new Size(clientRect.Width - 1, clientRect.Height - 1)));
//draw rular
var pen = Pens.Black;
var width = clientRect.Width;
var height = clientRect.Height;
var unitHeight = 10;
var halfUnitHeght = 5;
var packUnitHeight = 15;
var hDc = Util.NativeMethods.GetDC(this.Handle);
for (int i = 0; i < width; i++)
{
if (i % 50 == 0)
{
e.Graphics.DrawLine(pen, i, 0, i, packUnitHeight);
e.Graphics.DrawString(i.ToString(), this.Font, Brushes.Black, i, packUnitHeight + 1);
e.Graphics.DrawString(Util.PixelsToMillimetersWidth(hDc,(double)i).ToString("f1") + "mm", this.Font, Brushes.Black, i, packUnitHeight + 15);
}
else
{
if (i % 10 == 0)
{
e.Graphics.DrawLine(pen, i, 0, i, unitHeight);
}
else if (i % 5 == 0)
{
e.Graphics.DrawLine(pen, i, 0, i, halfUnitHeght);
}
}
}
base.OnPaint(e);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using DrawLine.Enums;
using System.Drawing.Drawing2D;
namespace DrawLine
{
class Util
{
public static double MillimetersToPixelsWidth(IntPtr hDc, double length)
{
int width = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZSIZE);
int pixels = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZRES);
return (((double)pixels / (double)width) * (double)length);
}
public static double PixelsToMillimetersWidth(IntPtr hDc, double length)
{
int width = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZSIZE);
int pixels = NativeMethods.GetDeviceCaps(hDc, NativeMethods.CapIndex.HORZRES);
return (double)width / (double)pixels * (double)length;
}
public class NativeMethods
{
[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int Index);
public class CapIndex
{
public static readonly int DRIVERVERSION = 0;
public static readonly int TECHNOLOGY = 2;
public static readonly int HORZSIZE = 4;
public static readonly int VERTSIZE = 6;
public static readonly int HORZRES = 8;
public static readonly int VERTRES = 10;
public static readonly int BITSPIXEL = 12;
public static readonly int PLANES = 14;
public static readonly int NUMBRUSHES = 16;
public static readonly int NUMPENS = 18;
public static readonly int NUMMARKERS = 20;
public static readonly int NUMFONTS = 22;
public static readonly int NUMCOLORS = 24;
public static readonly int PDEVICESIZE = 26;
public static readonly int CURVECAPS = 28;
public static readonly int LINECAPS = 30;
public static readonly int POLYGONALCAPS = 32;
public static readonly int TEXTCAPS = 34;
public static readonly int CLIPCAPS = 36;
public static readonly int RASTERCAPS = 38;
public static readonly int ASPECTX = 40;
public static readonly int ASPECTY = 42;
public static readonly int ASPECTXY = 44;
public static readonly int SHADEBLENDCAPS = 45;
public static readonly int LOGPIXELSX = 88;
public static readonly int LOGPIXELSY = 90;
public static readonly int SIZEPALETTE = 104;
public static readonly int NUMRESERVED = 106;
public static readonly int COLORRES = 108;
public static readonly int PHYSICALWIDTH = 110;
public static readonly int PHYSICALHEIGHT = 111;
public static readonly int PHYSICALOFFSETX = 112;
public static readonly int PHYSICALOFFSETY = 113;
public static readonly int SCALINGFACTORX = 114;
public static readonly int SCALINGFACTORY = 115;
public static readonly int VREFRESH = 116;
public static readonly int DESKTOPVERTRES = 117;
public static readonly int DESKTOPHORZRES = 118;
public static readonly int BLTALIGNMENT = 119;
}
}
}
}