介绍
我已经对Windows API和Parts and States有一点乐趣,看看控件如何可以画在画布上.
有了很多的尝试和错误,我设法得出这个程序,将一个按钮画在画布上:
type TButtonState = (bsDefault,bsDisabled,bsHot,bsNormal,bsPressed); procedure DrawButton(ACanvas: TCanvas; X,Y,AWidth,AHeight: Integer; AFont: TFont; Caption: string; ButtonState: TButtonState); var Size: TSize; R: TRect; H: HTHEME; begin Size.cx := AWidth; Size.cy := AHeight; R := Rect(X,X + AWidth,Y + AHeight); if Winapi.uxTheme.UseThemes then begin H := OpenThemeData(0,'BUTTON'); if H <> 0 then try ACanvas.Brush.Style := bsClear; if AFont <> nil then begin ACanvas.Font.Assign(AFont); end; case ButtonState of bsDefault: begin GetThemePartSize(H,ACanvas.Handle,BP_PUSHBUTTON,PBS_DEFAULTED,nil,TS_DRAW,Size); DrawThemeBackground(H,R,nil); end; bsDisabled: begin GetThemePartSize(H,PBS_DISABLED,nil); //ACanvas.Font.Color := $00838383; //todo get actual disabled font color end; bsHot: begin GetThemePartSize(H,PBS_HOT,nil); end; bsNormal: begin GetThemePartSize(H,PBS_NORMAL,nil); end; bsPressed: begin GetThemePartSize(H,PBS_PRESSED,nil); end; end; // draw the button caption DrawText(ACanvas.Handle,PChar(Caption),Length(Caption),DT_CENTER or DT_VCENTER or DT_SINGLELINE); finally CloseThemeData(H); end end else begin // draw button in classic theme? end; end;
如果我这样调用那个程序:
procedure TForm1.FormPaint(Sender: TObject); begin DrawButton(Image1.Canvas,10,75,25,Form1.Font,'Normal',bsNormal); DrawButton(Image1.Canvas,40,'Default',bsDefault); DrawButton(Image1.Canvas,70,'Disabled',bsDisabled); DrawButton(Image1.Canvas,100,'Hot',bsHot); DrawButton(Image1.Canvas,130,'Pressed',bsPressed); end;
结果是我的预期是如此,像任何Windows按钮控件一样出现:
题
虽然我正在玩这个程序,但我很快意识到该按钮没有标题,我看不到添加字幕的方式,而不是自己绘制在按钮的顶部.您可以看到,“禁用”按钮仍然显示默认的字体颜色,禁用的控件通常具有不同的颜色,以帮助显示控件被禁用.标准Windows主题下禁用的字体颜色为$00838383(使用屏幕颜色选择器找到),但硬编码值绝对不是一个好主意,因为这些值通常对每个主题都是唯一的.
我的问题有几个部分,当使用Winows API绘制一个按钮时,我们必须自己手动绘制字幕?如果是这样,如何确保我正在绘制正确的字体名称,样式和大小等,以确保按钮与系统绘制的按钮相同?
奖金
当主题未启用时,应如何以经典Windows样式绘制按钮?
解决方法
你应该自己画出文字.您可以使用主题API来绘制文本.例如:
... bsDisabled: begin GetThemePartSize(H,nil); DrawThemeText(H,DT_CENTER or DT_VCENTER or DT_SINGLELINE,R); //ACanvas.Font.Color := $00838383; //todo get actual disabled font color end; ...
由于您可以使用适当的状态调用api,请将该调用包括在分支中,并删除对DrawText的调用.
您可以使用DrawFrameControl作为经典风格.例如:
DrawFrameControl(ACanvas.Handle,DFC_BUTTON,DFCS_BUTTONPUSH);