为什么 LineTo 成功时 FillRect 不绘制?
Why would FillRect not draw when LineTo succeeds?
我正在尝试 change the background color of a DateTimePicker,但我的问题与我正在尝试做的事情无关。
我正在捕捉 window 的 WM_PAINT
消息,让默认绘图实现发生(即 ComCtrl.dll 中的那个),然后在那之后出现并涂鸦顶一下。
最初我的代码很简单:
TDateTimePicker = class(Vcl.ComCtrls.TDateTimePicker)
protected
procedure WMPaint(var Message: TMessage); message WM_PAINT;
end;
procedure TDateTimePicker.WMPaint(var Message: TMessage);
begin
inherited;
end;
我什么都不做,控件正常绘制:
好戏开始了
现在我将进行一些实际绘图。这不是我 想要 的绘图,但它证明它有效。我会在控件的矩形上画一个十字:
procedure TDateTimePicker.WMPaint(var Message: TMessage);
var
dc: HDC;
rc: TRect;
p: HPEN;
begin
inherited;
//Get the device context to scribble on
dc := GetDC(Self.Handle);
if dc = 0 then
Exit;
try
rc := Self.GetClientRect;
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
finally
ReleaseDC(Self.Handle, dc);
end;
end;
这很简单:
- 获取我们将要绘制的
HDC
- 获取控件的客户端rect
- 创建实心红笔
- select笔入DC
- 画十字
- 恢复旧笔
- 删除我们的笔
而且有效!
当然可以。
现在填充整个矩形
我不想画十字,我想填充背景。首先,我将演示一种使用可怕的可怕方法来实现我的目标的方法:
I will stroke the width of the control with a very thick pen
这是一件可怕的事情,但它具有实际工作的优点:
procedure TDateTimePicker.WMPaint(var Message: TMessage);
var
dc: HDC;
rc: TRect;
p: HPEN;
begin
inherited;
dc := GetDC(Self.Handle);
if dc = 0 then
Exit;
try
rc := Self.GetClientRect;
//Fill a rectangle using a pen (cause FillRect doesn't work)
p := CreatePen(PS_SOLID, rc.Height, ColorToRGB(clRed));
p := SelectObject(dc, p);
Winapi.Windows.MoveToEx(dc, rc.Left, (rc.Bottom+rc.Top) div 2, nil); //middle of left edge
Winapi.Windows.LineTo(dc, rc.Right, (rc.Bottom+rc.Top) div 2); //middle of right edge
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
finally
ReleaseDC(Self.Handle, dc);
end;
end;
这很简单:
- 创建一个 23 像素高的笔
- 从左到右划过选取器的整个宽度
有效:
当然可以!
但我不想抹去一切
我不想删除日期时间选择器中的所有内容,只删除 "client" 区域。所以我调整了矩形:
- 从顶部、左侧和底部减去 2 个像素
- 从日期时间选择器下拉按钮的右边缘减去 34 像素
代码片段:
rc := Self.GetClientRect;
//rc := GetRectOfThePartIWant;
rc.Left := 2;
rc.Top := 2;
rc.Bottom := rc.Bottom-2;
rc.Right := rc.Right-34; //button width is 34 (use DateTime_GetDateTimePickerInfo.rcButton)
//Fill a rectangle using a pen (cause FillRect doesn't work)
//p := CreatePen(PS_SOLID, rc.Height, ColorToRGB(clRed));
br := Default(TLogBrush);
br.lbStyle := BS_SOLID;
br.lbColor := ColorToRGB([=13=]CCCCFF);
br.lbHatch := 0; //ignored for a BS_SOLID brush
p := ExtCreatePen(PS_SOLID or PS_GEOMETRIC or PS_ENDCAP_FLAT, rc.Height, br, 0, nil);
if p <> 0 then
begin
p := SelectObject(dc, p);
Winapi.Windows.MoveToEx(dc, rc.Left, (rc.Bottom+rc.Top) div 2, nil); //middle of left edge
Winapi.Windows.LineTo(dc, rc.Right, (rc.Bottom+rc.Top) div 2); //middle of right edge
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
end;
有效:
当然可以!
FillRect 有什么问题?
本来我只是简单地使用了FillRect
,只不过它坚持只画白色;而不是任何颜色:
procedure TDateTimePicker.WMPaint(var Message: TMessage);
var
dc: HDC;
rc: TRect;
br: TLogBrush;
b: HBRUSH;
le: Integer;
p: HPEN;
begin
inherited;
dc := GetDC(Self.Handle);
if dc = 0 then
Exit;
try
rc := Self.GetClientRect;
b := CreateSolidBrush(ColorToRGB(clRed));
if b <> 0 then
begin
b := SelectObject(dc, b); //select the brush into the DC
if b <> 0 then
begin
le := FillRect(dc, rc, b);
if le = 0 then
begin
//Draw failed
if IsDebuggerPresent then
DebugBreak;
end;
SelectObject(dc, b); //restore the old brush
end;
DeleteObject(b);
end;
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
finally
ReleaseDC(Self.Handle, dc);
end;
end;
它不起作用:
当然不行。它试图让我的生活变得困难。如果它有效,那么我就不会花 9 个小时了。
我只尝试填充矩形的上半部分;确保我的来源是正确的:
rc := Self.GetClientRect;
rc2 := rc;
rc2.Bottom := (rc2.Top + rc2.Bottom) div 2;
b := CreateSolidBrush(ColorToRGB(clRed));
if b <> 0 then
begin
b := SelectObject(dc, b); //select the brush into the DC
if b <> 0 then
begin
le := FillRect(dc, rc2, b);
if le = 0 then
begin
//Draw failed
if IsDebuggerPresent then
DebugBreak;
end;
SelectObject(dc, b); //restore the old brush
end;
DeleteObject(b);
end;
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
它不起作用:
当然不行
为什么不起作用?
为什么不起作用?
奖金聊天
您不能使用 Delphi 样式引擎,because the Styles Engine is not enabled when using Windows themes(仅在使用自定义主题时)。
b := CreateSolidBrush(ColorToRGB(clRed));
if b <> 0 then
begin
b := // *** original brush gets overwritten here ***
SelectObject(dc, b); //select the brush into the DC
if b <> 0 then
begin
le := FillRect(dc, rc, b);
您不需要 select 刷入设备上下文,因为您将其作为参数传递。然后 selecting 它,将返回值分配回 brush 变量,然后 FillRect
使用错误的 brush 参数(这就是为什么它应该不起作用的原因)。
我正在尝试 change the background color of a DateTimePicker,但我的问题与我正在尝试做的事情无关。
我正在捕捉 window 的 WM_PAINT
消息,让默认绘图实现发生(即 ComCtrl.dll 中的那个),然后在那之后出现并涂鸦顶一下。
最初我的代码很简单:
TDateTimePicker = class(Vcl.ComCtrls.TDateTimePicker)
protected
procedure WMPaint(var Message: TMessage); message WM_PAINT;
end;
procedure TDateTimePicker.WMPaint(var Message: TMessage);
begin
inherited;
end;
我什么都不做,控件正常绘制:
好戏开始了
现在我将进行一些实际绘图。这不是我 想要 的绘图,但它证明它有效。我会在控件的矩形上画一个十字:
procedure TDateTimePicker.WMPaint(var Message: TMessage);
var
dc: HDC;
rc: TRect;
p: HPEN;
begin
inherited;
//Get the device context to scribble on
dc := GetDC(Self.Handle);
if dc = 0 then
Exit;
try
rc := Self.GetClientRect;
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
finally
ReleaseDC(Self.Handle, dc);
end;
end;
这很简单:
- 获取我们将要绘制的
HDC
- 获取控件的客户端rect
- 创建实心红笔
- select笔入DC
- 画十字
- 恢复旧笔
- 删除我们的笔
而且有效!
当然可以。
现在填充整个矩形
我不想画十字,我想填充背景。首先,我将演示一种使用可怕的可怕方法来实现我的目标的方法:
I will stroke the width of the control with a very thick pen
这是一件可怕的事情,但它具有实际工作的优点:
procedure TDateTimePicker.WMPaint(var Message: TMessage);
var
dc: HDC;
rc: TRect;
p: HPEN;
begin
inherited;
dc := GetDC(Self.Handle);
if dc = 0 then
Exit;
try
rc := Self.GetClientRect;
//Fill a rectangle using a pen (cause FillRect doesn't work)
p := CreatePen(PS_SOLID, rc.Height, ColorToRGB(clRed));
p := SelectObject(dc, p);
Winapi.Windows.MoveToEx(dc, rc.Left, (rc.Bottom+rc.Top) div 2, nil); //middle of left edge
Winapi.Windows.LineTo(dc, rc.Right, (rc.Bottom+rc.Top) div 2); //middle of right edge
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
finally
ReleaseDC(Self.Handle, dc);
end;
end;
这很简单:
- 创建一个 23 像素高的笔
- 从左到右划过选取器的整个宽度
有效:
当然可以!
但我不想抹去一切
我不想删除日期时间选择器中的所有内容,只删除 "client" 区域。所以我调整了矩形:
- 从顶部、左侧和底部减去 2 个像素
- 从日期时间选择器下拉按钮的右边缘减去 34 像素
代码片段:
rc := Self.GetClientRect;
//rc := GetRectOfThePartIWant;
rc.Left := 2;
rc.Top := 2;
rc.Bottom := rc.Bottom-2;
rc.Right := rc.Right-34; //button width is 34 (use DateTime_GetDateTimePickerInfo.rcButton)
//Fill a rectangle using a pen (cause FillRect doesn't work)
//p := CreatePen(PS_SOLID, rc.Height, ColorToRGB(clRed));
br := Default(TLogBrush);
br.lbStyle := BS_SOLID;
br.lbColor := ColorToRGB([=13=]CCCCFF);
br.lbHatch := 0; //ignored for a BS_SOLID brush
p := ExtCreatePen(PS_SOLID or PS_GEOMETRIC or PS_ENDCAP_FLAT, rc.Height, br, 0, nil);
if p <> 0 then
begin
p := SelectObject(dc, p);
Winapi.Windows.MoveToEx(dc, rc.Left, (rc.Bottom+rc.Top) div 2, nil); //middle of left edge
Winapi.Windows.LineTo(dc, rc.Right, (rc.Bottom+rc.Top) div 2); //middle of right edge
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
end;
有效:
当然可以!
FillRect 有什么问题?
本来我只是简单地使用了FillRect
,只不过它坚持只画白色;而不是任何颜色:
procedure TDateTimePicker.WMPaint(var Message: TMessage);
var
dc: HDC;
rc: TRect;
br: TLogBrush;
b: HBRUSH;
le: Integer;
p: HPEN;
begin
inherited;
dc := GetDC(Self.Handle);
if dc = 0 then
Exit;
try
rc := Self.GetClientRect;
b := CreateSolidBrush(ColorToRGB(clRed));
if b <> 0 then
begin
b := SelectObject(dc, b); //select the brush into the DC
if b <> 0 then
begin
le := FillRect(dc, rc, b);
if le = 0 then
begin
//Draw failed
if IsDebuggerPresent then
DebugBreak;
end;
SelectObject(dc, b); //restore the old brush
end;
DeleteObject(b);
end;
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
finally
ReleaseDC(Self.Handle, dc);
end;
end;
它不起作用:
当然不行。它试图让我的生活变得困难。如果它有效,那么我就不会花 9 个小时了。
我只尝试填充矩形的上半部分;确保我的来源是正确的:
rc := Self.GetClientRect;
rc2 := rc;
rc2.Bottom := (rc2.Top + rc2.Bottom) div 2;
b := CreateSolidBrush(ColorToRGB(clRed));
if b <> 0 then
begin
b := SelectObject(dc, b); //select the brush into the DC
if b <> 0 then
begin
le := FillRect(dc, rc2, b);
if le = 0 then
begin
//Draw failed
if IsDebuggerPresent then
DebugBreak;
end;
SelectObject(dc, b); //restore the old brush
end;
DeleteObject(b);
end;
//Create a pen to draw a criss-cross
p := CreatePen(PS_SOLID, 0, ColorToRGB(clLime));
p := SelectObject(dc, p); //select the pen into the dc
Winapi.Windows.MoveToEx(dc, rc.Left, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Right, rc.Bottom);
Winapi.Windows.MoveToEx(dc, rc.Right, rc.Top, nil);
Winapi.Windows.LineTo(dc, rc.Left, rc.Bottom);
P := SelectObject(dc, p); //restore old pen
DeleteObject(p); //delete our pen
它不起作用:
当然不行
为什么不起作用?
为什么不起作用?
奖金聊天
您不能使用 Delphi 样式引擎,because the Styles Engine is not enabled when using Windows themes(仅在使用自定义主题时)。
b := CreateSolidBrush(ColorToRGB(clRed));
if b <> 0 then
begin
b := // *** original brush gets overwritten here ***
SelectObject(dc, b); //select the brush into the DC
if b <> 0 then
begin
le := FillRect(dc, rc, b);
您不需要 select 刷入设备上下文,因为您将其作为参数传递。然后 selecting 它,将返回值分配回 brush 变量,然后 FillRect
使用错误的 brush 参数(这就是为什么它应该不起作用的原因)。