如何用Delphi VCL的TPopupMenu实现自定义OwnerDraw样式及垂直分隔线?
当然可以通过TPopupMenu的OwnerDraw模式实现你想要的自定义菜单效果!看你已经完成了大部分UI逻辑,只需要补充图标与文本间的垂直分隔线绘制代码,同时还要注意内存泄漏的问题,我来帮你完善:
完善后的完整代码
procedure TForm1.pmiProjectCopyDrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; Selected: Boolean); var bt: TBitmap; menuItem: TMenuItem; shortcutText: string; begin bt := TBitmap.Create; try menuItem := TMenuItem(Sender); shortcutText := ShortCutToText(menuItem.ShortCut); with ACanvas do begin // 绘制菜单背景 Brush.Color := clWhite; FillRect(ARect); // 设置字体样式 Font.Size := 8; Font.Name := 'Noto Sans'; Font.Color := IfThen(Selected, $006C4E1F, $00757575); if menuItem.Caption = '-' then begin // 绘制水平分隔线 Pen.Color := $00E5DFD7; MoveTo(ARect.Left + 25, ARect.Top + 3); LineTo(ARect.Right - 10, ARect.Top + 3); end else begin // 绘制菜单图标 ImageList1.GetBitmap(menuItem.ImageIndex, bt); Draw(ARect.Left + 3, ARect.Top + 3, bt); // 绘制图标与文本间的垂直分隔线 Pen.Color := $00E5DFD7; // 和水平分隔线同色,保持风格统一 MoveTo(ARect.Left + 22, ARect.Top + 2); // 调整X坐标适配图标宽度 LineTo(ARect.Left + 22, ARect.Bottom - 2); // 上下留空白避免贴边 // 调整文本绘制区域,避开分隔线 ARect.Left := ARect.Left + 28; // 绘制菜单文本(垂直居中) DrawText(Handle, PChar(menuItem.Caption), Length(menuItem.Caption), ARect, DT_SINGLELINE or DT_VCENTER); // 绘制快捷键文本(右对齐+垂直居中) DrawText(Handle, PChar(shortcutText), Length(shortcutText), ARect, DT_SINGLELINE or DT_RIGHT or DT_VCENTER); end; end; finally bt.Free; // 必须释放Bitmap,避免内存泄漏! end; end;
关键修改点说明
- 修复内存泄漏:之前的代码没有释放创建的
TBitmap,现在用try...finally块确保资源被正确回收 - 添加垂直分隔线:在图标绘制完成后,用
MoveTo和LineTo绘制一条垂直直线,坐标可以根据你的图标大小调整(这里假设图标是16x16,所以X坐标设为ARect.Left + 22,留出一点间距) - 调整文本区域:把
ARect.Left向右偏移更多,避免文本和分隔线重叠 - 统一颜色风格:垂直分隔线用和水平分隔线相同的颜色
$00E5DFD7,保持UI一致性
额外提示
如果你的图标大小不是16x16,可以根据实际尺寸调整分隔线的X坐标,比如图标宽度是20,那么分隔线X坐标可以设为ARect.Left + 23,确保和图标之间有合适的留白,视觉效果会更舒服。
内容的提问来源于stack exchange,提问作者userhi




