Winapi 如何增加直线中点之间的间距?

Winapi 如何增加直线中点之间的间距?,winapi,gdi+,gdi,Winapi,Gdi+,Gdi,当使用标准笔(PS_点)并用它画一条线时,结果如下图所示(放大) 这条线对我来说有两个问题,第一个是,它为一个点设置了多个像素。第二个问题是,这些点太近了,我不想这样做(画一条非常柔和的线) 我可以使用SetPixel,但是,它的性能还有很多需要改进的地方 我的问题是:有没有一种合理快速的方法来画一条线,可以控制用来画一个点的像素数和点之间的间距 从本质上讲,这是一种比使用SetPixel更快的方法(如果它不那么慢的话,它可以用来解决问题) 一个代码片段,展示了它是如何在C、C++或Delphi

当使用标准笔(PS_点)并用它画一条线时,结果如下图所示(放大)

这条线对我来说有两个问题,第一个是,它为一个点设置了多个像素。第二个问题是,这些点太近了,我不想这样做(画一条非常柔和的线)

我可以使用SetPixel,但是,它的性能还有很多需要改进的地方

我的问题是:有没有一种合理快速的方法来画一条线,可以控制用来画一个点的像素数和点之间的间距

从本质上讲,这是一种比使用SetPixel更快的方法(如果它不那么慢的话,它可以用来解决问题)

<>一个代码片段,展示了它是如何在C、C++或Delphi中完成的。 谢谢你的帮助

编辑:我尝试了IInspectable使用ExtCreatePen的答案,结果非常接近。似乎获得像素/点而不是虚线的唯一方法是使用PS_ALTERNATE,但是,当使用PS_ALTERNATE时,无法指定间距

作为参考,如果我犯了一个我没有看到的错误,下面是我编写的测试程序。我想要的是1点(不是破折号)和2个空格的重复序列。我从测试程序获得的输出如下所示(放大):(顶行使用PS_ALTERNATE获得,底行使用指定1点,2个空格的数组,即2点和2个空格。)

测试程序:

{$APPTYPE        GUI}

{$LONGSTRINGS    OFF}
{$WRITEABLECONST ON}

program _ExtCreatePen;

uses Windows, Messages;

const
  AppName  = 'ExtCreatePen';

{$ifdef VER90} { Delphi 2.0 }
type
  ptrint  = longint;        // NativeInt  for newer versions
  ptruint = dword;          // NativeUint  "    "      "
{$endif}

{-----------------------------------------------------------------------------}

function WndProc (Wnd : HWND; Msg : UINT; wParam, lParam : ptrint)
         : ptrint; stdcall;
const
  PenPattern   : packed array[1..4] of DWORD = (1, 2, 1, 2); { 1 dot, 2 spaces}

  PenBrush     : TLOGBRUSH = (lbStyle:BS_SOLID; lbColor:0; lbHatch:0);
  PenWidth     : DWORD     = 1;

  { !! this doesn't seem to work as expected, expected 1 dot, 2 spaces !!     }

  PenStyle     : DWORD     = PS_COSMETIC or PS_USERSTYLE;
  StyleCount   : DWORD     = high(PenPattern);
  StylePattern : PDWORD    = @PenPattern[low(PenPattern)];

  { this gives 1 dot, 1 space.                                                }

  //PenStyle     : DWORD     = PS_COSMETIC or PS_ALTERNATE;
  //StyleCount   : DWORD     = 0;
  //StylePattern : PDWORD    = nil;

  Pen          : HPEN      = 0;

var
  ps          : TPAINTSTRUCT;
  ClientRect  : TRECT;

begin
  WndProc := 0;

  case Msg of
    WM_CREATE:
    begin
      PenBrush.lbColor := RGB(255, 0, 0);

      Pen := ExtCreatePen(PenStyle,
                          PenWidth,
                          PenBrush,
                          StyleCount,
                          StylePattern);
      exit;
    end;

    WM_PAINT:
    begin
      BeginPaint(Wnd, ps);
        GetClientRect(Wnd, ClientRect);

        SelectObject(ps.hdc, Pen);  { use the pen we created    }

        MoveToEx(ps.hdc, 0, ClientRect.Bottom div 2, nil);
        LineTo(ps.hdc, ClientRect.Right, ClientRect.Bottom div 2);
      EndPaint(Wnd, ps);

      exit;
    end;

    WM_CLOSE: PostMessage(Wnd, WM_DESTROY, 0, 0);

    WM_DESTROY:
       begin
         if Pen <> 0 then DeleteObject(Pen);

         PostQuitMessage(0);

         exit;
       end; { WM_DESTROY }
  end; { case msg }

  WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);
end;

{-----------------------------------------------------------------------------}

function InitAppClass: WordBool;
  { registers the application's window classes                                }
var
  cls : TWndClassEx;

begin
  cls.cbSize          := sizeof(TWndClassEx);           { must be initialized }

  if not GetClassInfoEx (hInstance, AppName, cls) then
  begin
    with cls do
    begin
      { cbSize has already been initialized as required above                 }

      style           := CS_BYTEALIGNCLIENT;
      lpfnWndProc     := @WndProc;                    { window class handler  }
      cbClsExtra      := 0;
      cbWndExtra      := 0;
      hInstance       := system.hInstance;
      hIcon           := LoadIcon (hInstance, IDI_APPLICATION);
      hCursor         := LoadCursor(0, IDC_ARROW);
      hbrBackground   := COLOR_WINDOW + 1;
      lpszMenuName    := nil;
      lpszClassName   := AppName;                     { Window Class name     }
      hIconSm         := 0;
    end; { with }

    InitAppClass := WordBool(RegisterClassEx(cls));
  end
  else InitAppClass := TRUE;
end;

{-----------------------------------------------------------------------------}

function WinMain : integer;
  { application entry point                                                   }
var
  Wnd : hWnd;
  Msg : TMsg;

begin
  if not InitAppClass then Halt (255);  { register application's class        }

  { Create the main application window                                        }

  Wnd := CreateWindowEx(WS_EX_CLIENTEDGE,
                        AppName,                { class name                  }
                        AppName,                { window caption text         }
                        ws_Overlapped       or  { window style                }
                        ws_SysMenu          or
                        ws_MinimizeBox      or
                        ws_ClipSiblings     or
                        ws_ClipChildren     or  { don't affect children       }
                        ws_visible,             { make showwindow unnecessary }
                        20,                     { x pos on screen             }
                        20,                     { y pos on screen             }
                        400,                    { window width                }
                        200,                    { window height               }
                        0,                      { parent window handle        }
                        0,                      { menu handle 0 = use class   }
                        hInstance,              { instance handle             }
                        nil);                   { parameter sent to WM_CREATE }

  if Wnd = 0 then Halt;                         { could not create the window }

  while GetMessage (Msg, 0, 0, 0) do            { wait for message            }
  begin
    TranslateMessage (Msg);                     { key conversions             }
    DispatchMessage  (Msg);                     { send to window procedure    }
  end;

  WinMain := Msg.wParam;                        { terminate with return code  }
end;

begin
  WinMain;
end.
{$APPTYPE GUI}
{$LONGSTRINGS OFF}
{$WRITEABLECONST ON}
程序ExtCreatePen;
使用窗口、消息;
常数
AppName='ExtCreatePen';
{$ifdef VER90}{Delphi 2.0}
类型
ptrint=longint;//新版本的NativeInt
ptrint=dword;//本地单位“
{$endif}
{-----------------------------------------------------------------------------}
函数WndProc(Wnd:HWND;Msg:UINT;wParam,lParam:ptrint)
:ptrint;stdcall;
常数
PenPattern:DWORD=(1,2,1,2);{1点,2个空格}的压缩数组[1..4]
PenBrush:TLOGBRUSH=(lbStyle:BS_SOLID;lbColor:0;lbHatch:0);
笔宽:DWORD=1;
{!!这似乎没有预期的效果,预期为1点,2个空格!!}
PenStyle:DWORD=PS_化妆品或PS_用户风格;
样式计数:DWORD=高(PenPattern);
StylePattern:PDWORD=@PenPattern[low(PenPattern)];
{这给了1个点,1个空格。}
//笔体:DWORD=PS_化妆品或PS_替代品;
//StyleCount:DWORD=0;
//StylePattern:PDWORD=nil;
Pen:HPEN=0;
变量
ps:TPAINTSTRUCT;
ClientRect:TRECT;
开始
WndProc:=0;
味精案例
WM_创建:
开始
PenBrush.lbColor:=RGB(255,0,0);
画笔:=ExtCreatePen(画笔样式,
笔宽,
画笔,
StyleCount,
风格模式);
出口
结束;
WM_油漆:
开始
开始油漆(Wnd,ps);
GetClientRect(Wnd,ClientRect);
选择Object(ps.hdc,Pen);{使用我们创建的笔}
MoveToEx(ps.hdc,0,ClientRect.底部分区2,无);
LineTo(ps.hdc、ClientRect.右侧、ClientRect.底部分区2);
端漆(Wnd,ps);
出口
结束;
WM_CLOSE:PostMessage(Wnd,WM_DESTROY,0,0);
WM_销毁:
开始
如果笔为0,则删除对象(笔);
PostQuitMessage(0);
出口
结束;{WM_DESTROY}
结束;{case msg}
WndProc:=DefWindowProc(Wnd、Msg、wParam、lParam);
结束;
{-----------------------------------------------------------------------------}
函数InitAppClass:WordBool;
{注册应用程序的窗口类}
变量
cls:TWndClassEx;
开始
cls.cbSize:=sizeof(TWndClassEx);{必须初始化}
如果不是GetClassInfo(hInstance、AppName、cls),则
开始
用cls做什么
开始
{cbSize已按上述要求初始化}
样式:=CS_BYTEALIGNCLIENT;
lpfnWndProc:=@WndProc;{窗口类处理程序}
cbClsExtra:=0;
cbWndExtra:=0;
hInstance:=system.hInstance;
hIcon:=加载图标(hInstance,IDI_应用程序);
hCursor:=加载光标(0,IDC_箭头);
hbrBackground:=彩色窗口+1;
lpszMenuName:=nil;
lpszClassName:=AppName;{窗口类名}
hIconSm:=0;
结束;{with}
InitAppClass:=WordBool(RegisterClassEx(cls));
结束
else InitAppClass:=TRUE;
结束;
{-----------------------------------------------------------------------------}
函数WinMain:integer;
{应用程序入口点}
变量
Wnd:hWnd;
Msg:TMsg;
开始
如果不是InitAppClass,则停止(255){注册应用程序的类}
{创建主应用程序窗口}
Wnd:=CreateWindowEx(WS_EX_CLIENTEDGE,
AppName,{class name}
AppName,{窗口标题文本}
ws_重叠或{窗口样式}
ws_SysMenu或
ws_最小电子邮箱或
ws_ClipSiblings或
ws_儿童或{不影响儿童}
ws_可见,{使showwindow不必要}
20,{x位置在屏幕上}
20,{y位置在屏幕上}
400,