当前位置: 首页 > article >正文

WinForms自定义控件入门:手把手教你用C# GDI+绘制可交互的按钮和面板

WinForms自定义控件实战用C# GDI打造高交互性UI组件在传统WinForms开发中标准控件往往难以满足现代应用对界面美观和交互体验的要求。想象一下当用户鼠标悬停时按钮能优雅地发光点击时呈现加载动画面板带有精致的阴影效果——这些都能通过GDI技术轻松实现。本文将带您从零开始构建具有专业质感的可交互UI组件。1. 构建自定义按钮的基础框架创建自定义控件首先需要继承Button基类。这个基础框架将作为我们所有高级功能的起点public class CustomButton : Button { private Color _hoverColor Color.FromArgb(50, 150, 250); private Color _normalColor Color.FromArgb(70, 70, 70); private int _cornerRadius 8; protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g e.Graphics; g.SmoothingMode SmoothingMode.AntiAlias; // 基础绘制逻辑将在这里实现 } }关键参数说明参数名类型默认值说明_hoverColorColorColor.FromArgb(50,150,250)鼠标悬停时的背景色_normalColorColorColor.FromArgb(70,70,70)正常状态下的背景色_cornerRadiusint8圆角半径(像素)2. 实现圆角矩形与动态效果2.1 绘制圆角矩形GDI没有直接绘制圆角矩形的方法我们需要自己实现private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius) { GraphicsPath path new GraphicsPath(); path.AddArc(rect.X, rect.Y, radius, radius, 180, 90); path.AddArc(rect.Right - radius, rect.Y, radius, radius, 270, 90); path.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90); path.AddArc(rect.X, rect.Bottom - radius, radius, radius, 90, 90); path.CloseFigure(); return path; }2.2 动态颜色过渡通过重写鼠标事件实现状态变化private bool _isHovering false; private bool _isPressed false; protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); _isHovering true; this.Invalidate(); // 触发重绘 } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); _isHovering false; this.Invalidate(); } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); _isPressed true; this.Invalidate(); } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); _isPressed false; this.Invalidate(); }3. 高级交互效果实现3.1 点击动画效果在按钮被点击时显示扇形加载动画private int _loadingAngle 0; private Timer _loadingTimer; private void StartLoadingAnimation() { _loadingTimer new Timer(); _loadingTimer.Interval 50; _loadingTimer.Tick (s, e) { _loadingAngle (_loadingAngle 10) % 360; this.Invalidate(); }; _loadingTimer.Start(); } protected override void OnClick(EventArgs e) { base.OnClick(e); StartLoadingAnimation(); Task.Delay(1000).ContinueWith(t { this.Invoke((MethodInvoker)delegate { _loadingTimer.Stop(); _loadingAngle 0; this.Invalidate(); }); }); }3.2 完整绘制逻辑整合所有效果到OnPaint方法protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g e.Graphics; g.SmoothingMode SmoothingMode.AntiAlias; // 确定当前状态颜色 Color bgColor _normalColor; if (_isHovering) bgColor _hoverColor; if (_isPressed) bgColor ControlPaint.Dark(_hoverColor, 0.2f); // 绘制背景 using (GraphicsPath path GetRoundedRectPath(ClientRectangle, _cornerRadius)) using (SolidBrush brush new SolidBrush(bgColor)) { g.FillPath(brush, path); } // 绘制加载动画 if (_loadingAngle 0) { using (Pen pen new Pen(Color.White, 3)) { g.DrawArc(pen, new Rectangle(Width-30, Height-30, 20, 20), 0, _loadingAngle); } } // 绘制文本 TextFormatFlags flags TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter; TextRenderer.DrawText(g, Text, Font, ClientRectangle, ForeColor, flags); }4. 创建自定义面板组件4.1 多边形面板基础继承Panel类并实现自定义绘制public class PolygonPanel : Panel { private int _sides 6; private Color _borderColor Color.Silver; private int _shadowDepth 5; protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g e.Graphics; g.SmoothingMode SmoothingMode.AntiAlias; // 绘制阴影效果 DrawShadow(g); // 绘制多边形背景 DrawPolygonBackground(g); } }4.2 阴影效果实现使用渐变画刷创建逼真阴影private void DrawShadow(Graphics g) { Rectangle shadowRect new Rectangle( _shadowDepth, _shadowDepth, Width - _shadowDepth, Height - _shadowDepth); using (GraphicsPath path CreatePolygonPath(shadowRect, _sides)) using (PathGradientBrush brush new PathGradientBrush(path)) { brush.CenterColor Color.FromArgb(50, Color.Black); brush.SurroundColors new Color[] { Color.Transparent }; g.FillPath(brush, path); } }4.3 多边形生成算法根据边数生成规则多边形路径private GraphicsPath CreatePolygonPath(Rectangle bounds, int sides) { GraphicsPath path new GraphicsPath(); float radius Math.Min(bounds.Width, bounds.Height) / 2; PointF center new PointF(bounds.X bounds.Width / 2, bounds.Y bounds.Height / 2); for (int i 0; i sides; i) { float angle i * 2 * (float)Math.PI / sides - (float)Math.PI / 2; PointF point new PointF( center.X radius * (float)Math.Cos(angle), center.Y radius * (float)Math.Sin(angle)); if (i 0) path.StartFigure(); else path.AddLine(path.GetLastPoint(), point); } path.CloseFigure(); return path; }5. 控件属性优化与设计时支持5.1 暴露可配置属性让控件在设计器中可配置[Category(Appearance)] [Description(圆角半径大小)] public int CornerRadius { get { return _cornerRadius; } set { _cornerRadius value; Invalidate(); } } [Category(Appearance)] [Description(鼠标悬停时的背景色)] public Color HoverColor { get { return _hoverColor; } set { _hoverColor value; Invalidate(); } }5.2 设计时渲染优化避免在设计模式执行动画protected override void OnPaint(PaintEventArgs e) { if (DesignMode) { // 简化设计时渲染 base.OnPaint(e); return; } // 完整的运行时渲染逻辑 }6. 性能优化技巧6.1 双缓冲技术减少绘制闪烁public CustomButton() { this.SetStyle( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); }6.2 资源释放确保GDI对象正确释放protected override void Dispose(bool disposing) { if (disposing) { if (_loadingTimer ! null) { _loadingTimer.Stop(); _loadingTimer.Dispose(); } } base.Dispose(disposing); }7. 实际应用示例7.1 在项目中使用自定义按钮private void InitializeCustomUI() { CustomButton btnSubmit new CustomButton(); btnSubmit.Text 提交; btnSubmit.HoverColor Color.FromArgb(80, 160, 255); btnSubmit.CornerRadius 12; btnSubmit.Size new Size(120, 40); btnSubmit.Location new Point(20, 20); this.Controls.Add(btnSubmit); }7.2 创建仪表盘面板private void CreateDashboardPanel() { PolygonPanel panel new PolygonPanel(); panel.Sides 8; panel.BorderColor Color.FromArgb(100, 100, 255); panel.Size new Size(200, 200); panel.Location new Point(150, 20); this.Controls.Add(panel); }

相关文章:

WinForms自定义控件入门:手把手教你用C# GDI+绘制可交互的按钮和面板

WinForms自定义控件实战:用C# GDI打造高交互性UI组件 在传统WinForms开发中,标准控件往往难以满足现代应用对界面美观和交互体验的要求。想象一下,当用户鼠标悬停时按钮能优雅地发光,点击时呈现加载动画,面板带有精致的…...

Windows Cleaner终极指南:三步彻底解决系统卡顿与C盘爆满问题

Windows Cleaner终极指南:三步彻底解决系统卡顿与C盘爆满问题 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 当你面对Windows系统越来越慢、C盘空间频…...

在 SAP S/4HANA 里把经典事务 BP 挂进 Fiori,并支持参数传递

先把名字叫对,很多项目里说的 Transaction launcher,落到 SAP 官方对象上,其实是 tile 加 target mapping 在 SAP 官方术语里,真正负责把导航意图解析到目标应用的,不是一个孤立的 Transaction launcher 对象,而是 SAP Fiori launchpad 里的 target mapping。target map…...

行为采集、召回、排序、缓存怎么配合?一次讲透

推荐系统在电商里怎么设计?一次讲清召回、排序、实时性与工程落地边界 大家好,我是一名有 4 年工作经验的 Java 后端开发。 推荐系统在电商里看起来很“算法”,但真正落到工程里,你会发现大量问题其实是系统设计问题。 这篇文章我…...

Windows 11 LTSC 24H2如何一键恢复微软商店?3分钟完整指南

Windows 11 LTSC 24H2如何一键恢复微软商店?3分钟完整指南 【免费下载链接】LTSC-Add-MicrosoftStore Add Windows Store to Windows 11 24H2 LTSC 项目地址: https://gitcode.com/gh_mirrors/ltscad/LTSC-Add-MicrosoftStore 你是否在使用Windows 11 LTSC 2…...

【板块轮动 | 算力行情】为什么AI算力正在成为A股下一个「新能源」——以及这次谁在提前下车

一、为什么算力行情在「复刻」新能源,但没有那么简单 2024年9月以后,如果你身边有炒A股的朋友,大概率听过两种声音。 一种说"算力就是下一个新能源,早信早上车";另一种说"这次不一样,别被…...

从比亚迪宋L到北京魔方:拆解国内已上市CMS车型,聊聊用户体验与真实痛点

从比亚迪宋L到北京魔方:拆解国内已上市CMS车型的真实用户体验 当北京魔方成为国内首款搭载CMS电子后视镜的量产车型时,汽车科技论坛里炸开了锅。一位ID为"极客老司机"的用户上传了夜间暴雨中行驶的视频——传统后视镜几乎失效的场景下&#xf…...

量子强化学习在TSP问题中的参数优化与应用

1. 量子强化学习在TSP问题中的应用概述量子强化学习(Quantum Reinforcement Learning, QRL)作为量子计算与强化学习的交叉领域,为解决组合优化问题提供了全新的技术路径。在旅行商问题(Traveling Salesman Problem, TSP&#xff0…...

8大网盘文件直链获取神器LinkSwift:如何实现全平台无限制高速下载?

8大网盘文件直链获取神器LinkSwift:如何实现全平台无限制高速下载? 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘…...

保姆级教程:在Vue3+Vite项目中集成LivePlayer H5播放器(含跨域、多分屏避坑指南)

Vue3Vite项目实战:LivePlayer H5播放器深度集成与性能优化指南 引言 在当今视频内容爆炸式增长的时代,前端开发者面临着一个关键挑战:如何在现代Web应用中高效集成功能强大且稳定的视频播放解决方案。LivePlayer H5播放器凭借其多协议支持、低…...

实战踩坑记录:从生成SM2私钥到吉大正元下载双证书的全流程解析

SM2双证书申请全流程实战指南:从密钥生成到吉大正元系统对接 第一次在吉大正元系统上申请SM2双证书时,我盯着屏幕上那个格式错误的P10文件提示,意识到国密证书的申请流程远比想象中复杂。这不是简单的RSA证书申请流程换套算法就能解决的问题—…...

VMware Tools安装后别急着庆祝!共享文件夹设置、分辨率调整与性能优化的完整配置清单

VMware Tools安装后必做的10项深度配置:从能用变好用的进阶指南 当你看到"Enjoy, –the VMware team"的提示时,VMware Tools的安装只是完成了第一步。真正提升虚拟机体验的关键,在于后续这一系列深度配置。本文将带你解锁共享文件夹…...

从选料到布线:一个硬件工程师的DDR4实战笔记(以MT40A512M16JY-083E为例)

从选料到布线:一个硬件工程师的DDR4实战笔记(以MT40A512M16JY-083E为例) 去年负责一款智能家居主控板设计时,遇到了一个看似简单的需求:为基于瑞芯微RK3588的平台配置16GB DDR4内存。这个看似标准的任务,却…...

ONNXRuntime GPU版本与CUDA环境匹配实战指南

1. 为什么需要关注ONNXRuntime与CUDA版本匹配? 第一次在服务器上部署ONNXRuntime-GPU版本时,我遇到了一个让人抓狂的问题:模型推理速度比CPU还慢。经过半天排查才发现,原来安装的ONNXRuntime版本与CUDA环境不兼容。这种版本不匹配…...

基于安卓的水产养殖水质监测系统毕设

博主介绍:✌ 专注于Java,python,✌关注✌私信我✌具体的问题,我会尽力帮助你。一、研究目的本研究旨在设计并实现一种基于安卓平台的智能化水产养殖水质监测系统以解决传统水产养殖中水质管理存在的实时性不足、数据采集效率低下及人工干预成本高等问题。…...

Uniapp+Vue3+Ts 实战:巧用双script标签破解globalData共享与生命周期执行难题

1. 当Uniapp遇上Vue3Ts&#xff1a;globalData共享的困境 最近在帮团队升级Uniapp项目到Vue3TypeScript时&#xff0c;遇到了一个典型问题&#xff1a;App.vue中原本通过export default导出的globalData全局变量&#xff0c;在改用<script setup>语法糖后突然失效了。其他…...

大众点评爬虫终极指南:3步搞定餐饮数据采集与动态字体破解

大众点评爬虫终极指南&#xff1a;3步搞定餐饮数据采集与动态字体破解 【免费下载链接】dianping_spider 大众点评爬虫&#xff08;全站可爬&#xff0c;解决动态字体加密&#xff0c;非OCR&#xff09;。持续更新 项目地址: https://gitcode.com/gh_mirrors/di/dianping_spi…...

ACE-Guard限制器终极指南:彻底解决腾讯游戏卡顿问题

ACE-Guard限制器终极指南&#xff1a;彻底解决腾讯游戏卡顿问题 【免费下载链接】sguard_limit 限制ACE-Guard Client EXE占用系统资源&#xff0c;支持各种腾讯游戏 项目地址: https://gitcode.com/gh_mirrors/sg/sguard_limit 还在为腾讯游戏卡顿烦恼吗&#xff1f;你…...

如何用Umi-OCR实现扫描PDF的完美转换:免费离线OCR终极指南

如何用Umi-OCR实现扫描PDF的完美转换&#xff1a;免费离线OCR终极指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片&#xff0c;PDF文档识别&#xff0c;排除水印/页眉页脚&#xff0c;扫描/生成二维码。内置多国…...

如何快速突破网盘限速:LinkSwift网盘直链下载助手完整指南

如何快速突破网盘限速&#xff1a;LinkSwift网盘直链下载助手完整指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …...

别再只用@keydown.enter了!盘点Vue表单交互中回车键监听的5个实用场景与避坑点

Vue表单交互中回车键的高级应用&#xff1a;5个实战场景与深度优化 在Web应用开发中&#xff0c;表单交互占据了用户操作的重要部分。虽然大多数开发者都熟悉基础的keydown.enter用法&#xff0c;但回车键在不同场景下的精细控制往往能显著提升用户体验。本文将深入探讨五个典型…...

思源宋体TTF:为什么这款免费字体能彻底改变你的中文排版体验

思源宋体TTF&#xff1a;为什么这款免费字体能彻底改变你的中文排版体验 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还记得那些年为中文字体版权发愁的日子吗&#xff1f;当我第一…...

Windows和Office激活难题?KMS_VL_ALL_AIO一站式智能解决方案详解

Windows和Office激活难题&#xff1f;KMS_VL_ALL_AIO一站式智能解决方案详解 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 面对Windows系统或Office办公软件的激活过期警告&#xff0c;你是否…...

从零到一:基于YOLOv8与PySide6构建桌面端目标检测应用

1. 环境准备与工具安装 目标检测应用的开发离不开合适的工具链支持。我们先从最基础的环境搭建开始&#xff0c;这里我推荐使用Python 3.8版本&#xff0c;因为这个版本在兼容性和稳定性方面表现都很不错。安装过程很简单&#xff0c;直接从Python官网下载对应操作系统的安装包…...

AssetRipper高效数据存储架构:深入解析Unity资产提取工具的核心设计

AssetRipper高效数据存储架构&#xff1a;深入解析Unity资产提取工具的核心设计 【免费下载链接】AssetRipper GUI Application to work with engine assets, asset bundles, and serialized files 项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper Asset…...

DLSS Swapper深度解析:如何通过注册表管理实现游戏性能调优

DLSS Swapper深度解析&#xff1a;如何通过注册表管理实现游戏性能调优 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 当你在游戏中启用DLSS技术时&#xff0c;是否曾好奇过它到底在后台做了些什么&#xff1f;为什么…...

Vue+SpringBoot项目实战:如何把Kettle引擎‘搬’到浏览器里运行?

VueSpringBoot全栈实战&#xff1a;浏览器端Kettle引擎的架构设计与实现 技术选型背后的思考 当我们决定将Kettle这样的传统桌面应用引擎迁移到浏览器环境时&#xff0c;技术栈的选择直接决定了项目的可维护性和扩展性。VueSpringBoot的组合在这个场景下展现出独特的优势&…...

为什么92%的C项目不敢升级?2026规范成本陷阱识别图谱(含GCC 14.2/Clang 18.1兼容性速查表)

第一章&#xff1a;现代 C 语言内存安全编码规范 2026 概览C 语言因其零开销抽象与硬件贴近性&#xff0c;仍在操作系统、嵌入式系统及高性能基础设施中占据核心地位。然而&#xff0c;传统 C 编程中普遍存在的缓冲区溢出、悬空指针、未初始化内存访问等缺陷&#xff0c;已成为…...

iOS AVFoundation实战:视频播完别急着返回,这3种播放结束处理方案你选哪个?

iOS视频播放结束体验设计&#xff1a;从技术实现到用户心理的深度解析 当用户沉浸在视频内容中&#xff0c;最后一个画面淡出时&#xff0c;那一刻的交互体验往往决定了他们是否会继续留在你的应用里。作为产品设计者&#xff0c;我们面临的不仅是一个技术问题&#xff0c;更是…...

MCP网关吞吐瓶颈总在凌晨2点爆发?C++内存池+无锁RingBuffer+NUMA感知调度三重优化方案(附GitHub Star 4.7k的benchmark对比)

第一章&#xff1a;MCP网关吞吐瓶颈的凌晨2点现象学解析 凌晨2点&#xff0c;生产环境MCP&#xff08;Microservice Control Plane&#xff09;网关突现吞吐量断崖式下跌——P99延迟飙升至3.2秒&#xff0c;错误率从0.01%跃升至17%&#xff0c;而CPU与内存监控曲线却呈现诡异的…...