天天看點

C#使用GDI繪制格尺

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

C#使用GDI繪制格尺

1.尺寸的确定

在使用标尺測試控件的寬度時,一個像素是指起始點開始後一個像素點才為一個像素,我總是認為一個像素就是螢幕上的一個格子。

C#使用GDI繪制格尺

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;


            }

        }
    }
}