Windows Forms中使用PaintEvent导致绘制伪影问题排查
图片特定区域高亮功能的异常绘制伪影问题
我正在实现图片特定区域高亮功能,逻辑为将图片除目标区域外的部分变暗,目标区域的位置和尺寸通过参数传入。已完成概念验证(POC),功能可运行,但出现无法消除的异常绘制伪影(图片左侧非预期异常区域)。
设计器代码
partial class cComponentWindow { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.btnOkay = new System.Windows.Forms.Button(); this.StaticLabel = new System.Windows.Forms.Label(); this.DynamicLabel = new System.Windows.Forms.Label(); this.PCBPictureBox = new System.Windows.Forms.PictureBox(); ((System.ComponentModel.ISupportInitialize)(this.PCBPictureBox)).BeginInit(); this.SuspendLayout(); // // btnOkay // this.btnOkay.Location = new System.Drawing.Point(12, 480); this.btnOkay.Name = "btnOkay"; this.btnOkay.Size = new System.Drawing.Size(820, 23); this.btnOkay.TabIndex = 1; this.btnOkay.Text = "Okay"; this.btnOkay.UseVisualStyleBackColor = true; this.btnOkay.Click += new System.EventHandler(this.btnOkay_Click); // // StaticLabel // this.StaticLabel.AutoSize = true; this.StaticLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.StaticLabel.Location = new System.Drawing.Point(8, 2); this.StaticLabel.Name = "StaticLabel"; this.StaticLabel.Size = new System.Drawing.Size(130, 20); this.StaticLabel.TabIndex = 3; this.StaticLabel.Text = "Some Static Text"; // // DynamicLabel // this.DynamicLabel.AutoSize = true; this.DynamicLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.DynamicLabel.Location = new System.Drawing.Point(12, 25); this.DynamicLabel.Name = "DynamicLabel"; this.DynamicLabel.Size = new System.Drawing.Size(104, 20); this.DynamicLabel.TabIndex = 2; this.DynamicLabel.Text = "Dynamic Text"; // // PCBPictureBox // this.PCBPictureBox.InitialImage = null; this.PCBPictureBox.Location = new System.Drawing.Point(25, 25); this.PCBPictureBox.Name = "PCBPictureBox"; this.PCBPictureBox.Size = new System.Drawing.Size(790, 450); this.PCBPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.PCBPictureBox.TabIndex = 4; this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form_Paint); this.PCBPictureBox.TabStop = false; // // cComponentWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(844, 511); this.Controls.Add(this.DynamicLabel); this.Controls.Add(this.StaticLabel); this.Controls.Add(this.btnOkay); this.Controls.Add(this.PCBPictureBox); this.Name = "cComponentWindow"; this.Text = "Title"; this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form_Paint); // I also tried commenting this auto generated one out. That didn't change anything. ((System.ComponentModel.ISupportInitialize)(this.PCBPictureBox)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Button btnOkay; private System.Windows.Forms.PictureBox PCBPictureBox; private System.Windows.Forms.Label StaticLabel; private System.Windows.Forms.Label DynamicLabel; }
业务逻辑代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; public partial class cComponentWindow : Form { // Variables: private UInt16 SizeX; private UInt16 SizeY; private UInt16 OffsetX; private UInt16 OffsetY; private bool[,] Matrix; private PaintEventArgs e; private Pen DarkPen = new Pen(Color.FromArgb(127, 0, 0, 0)); // Methodes: public cComponentWindow(UInt16 OffsetX, UInt16 OffsetY, UInt16 SizeX, UInt16 SizeY, String CHK, Image Picture) { InitializeComponent(); this.OffsetX = OffsetX; this.OffsetY = OffsetY; this.SizeX = SizeX; this.SizeY = SizeY; this.DynamicLabel.Text = CHK; this.PCBPictureBox.Image = Picture; this.Matrix = new bool[this.SizeX, this.SizeY]; } private void btnOkay_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.OK; Close(); } private void Form_Paint(object sender, PaintEventArgs e) { this.e = e; this.Draw(); } public void Highlight(UInt16 OffsetX, UInt16 OffsetY, UInt16 SizeX, UInt16 SizeY) { for (UInt16 x = 0; x < SizeX; x++) { for (UInt16 y = 0; y < SizeY; y++) { this.Matrix[OffsetX + x, OffsetY + y] = true; } } } private void Draw() // OG time: 2m20s after some optimisations 0.5s (-99.6%) { //e.Graphics.FillRectangle(new SolidBrush(Color.Green), 0, 27, 790, 395 + 27); // Go through the entire matrix. for (UInt16 y = 0; y < this.SizeY; y++) { UInt16 StartBlock = 0; bool PreviousValue = false; for (UInt16 x = 0; x < this.SizeX; x++) { bool CurrentValue = Matrix[x, y]; if (CurrentValue && !PreviousValue) { // Draw the line to a highlight. e.Graphics.DrawLine(DarkPen, this.OffsetX + StartBlock, this.OffsetY + y, this.OffsetX + x - 1, this.OffsetY + y); } if (!CurrentValue && this.SizeX - 1 == x) { // Draw the line to the edge of the screen. e.Graphics.DrawLine(DarkPen, this.OffsetX + StartBlock, this.OffsetY + y, this.OffsetX + x, this.OffsetY + y); } if (PreviousValue && !CurrentValue) { // Mark the start of the line. StartBlock = x; } PreviousValue = CurrentValue; } } } }
调用代码
// x Offset relative to top left of the picturebox, y Offset relative to top left of the picturebox, width of the photo <= picturebox width, height of the photo <= picturebox height. cComponentWindow Window = new cComponentWindow(0, 27, 790, 395, "Text to be dynamically displayed", global::G458.Properties.Resources.Test_Picture); // x Offset relative to top left of the darken area, y Offset relative to top left of the darken area, width of the highlight <= darken area width, height of the highlight <= darken area height. Window.Highlight(10, 10, 250, 150); Window.Highlight(500, 300, 100, 50); Window.ShowDialog();
已尝试的排查方法
- 调整变暗区域的位置/尺寸:伪影形状改变但仍存在
- 将PaintEvent绑定到窗口而非PictureBox:结果完全相同
- 仅保留PictureBox的PaintEvent,注释窗口的PaintEvent:结果无变化
我不清楚如何修复该问题,希望得到解决方案或建议。
编辑:后续在添加功能和调整代码的过程中,问题意外解决,但不确定具体修复原因。
内容的提问来源于stack exchange,提问作者OADINC
相关产品推荐
相关产品推荐

