我正在使用DrawReversibleFrame根据名为SelectionTest的控件上的鼠标位置绘制一个反色的矩形。使用DrawReversibleFrame的基本代码取自此MSDN sample。
如果在选择区域期间重新绘制控件(在无效或刷新之后),矩形可能会消失或具有不同大小的多个副本。你可能会问我,你为什么要刷新控制?其实,我不是!也不会引发控件Paint事件。
我发现重绘只发生在两个其他控件之间绘制矩形时非常快速失效(例如:鼠标移动事件或定时器)。
为了重现这个话题,我创建了两个示例类:
SelectionTest ,处理DrawReversibleFrame。复选框This.Invalidate计时器,启用/禁用调用SelectionTest的Invalidate的计时器。如果激活它,则可以使用easyl重现不需要的DrawReversibleFrame行为。请注意,这个(Invalidade调用)只是重现错误的“欺骗”。在我的应用程序上,我没有调用Invalidate或要求以任何方式重绘控件。正如我所说,在我的应用程序中,不会引发Paint事件。
Form1 ,拥有两个面板之间的SelectionTest。它拥有两个主要的复选框,用于控制鼠标移动时的无效以及使计时器无效。如果两者都被选中,则不需要的行为会更加显着。
以下是不受欢迎行为的屏幕截图。请注意中心(较暗区域)控件右上角的选择:
问题:
SelectionTest.cs - 基于MSDN sample使用DrawReversibleFrame的控件。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace DrawReversibleFrameTest
{
public partial class SelectionTest : UserControl
{
Timer timer = new Timer();
public SelectionTest()
{
InitializeComponent();
this.MouseDown += SelectionTest_MouseDown;
this.MouseMove += SelectionTest_MouseMove;
this.MouseUp += SelectionTest_MouseUp;
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Enabled = ckbTimerEnabled.Checked;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Console.WriteLine("SelectionTest OnPaint");
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Console.WriteLine("SelectionTest OnPaintBackground");
}
void timer_Tick(object sender, EventArgs e)
{
this.Invalidate();
}
// The following three methods will draw a rectangle and allow
// the user to use the mouse to resize the rectangle. If the
// rectangle intersects a control's client rectangle, the
// control's color will change.
bool isDrag = false;
Rectangle theRectangle = new Rectangle(new Point(0, 0), new Size(0, 0));
Point startPoint;
private void SelectionTest_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Set the isDrag variable to true and get the starting point
// by using the PointToScreen method to convert form
// coordinates to screen coordinates.
if (e.Button == MouseButtons.Left)
{
isDrag = true;
}
Control control = (Control)sender;
// Calculate the startPoint by using the PointToScreen
// method.
startPoint = control.PointToScreen(new Point(e.X, e.Y));
}
private Point lastPosition = Point.Empty;
private void SelectionTest_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (lastPosition == e.Location)
return;
lastPosition = e.Location;
// If the mouse is being dragged,
// undraw and redraw the rectangle as the mouse moves.
if (isDrag)
// Hide the previous rectangle by calling the
// DrawReversibleFrame method with the same parameters.
{
ControlPaint.DrawReversibleFrame(theRectangle, this.BackColor, FrameStyle.Dashed);
// Calculate the endpoint and dimensions for the new
// rectangle, again using the PointToScreen method.
Point endPoint = ((Control)sender).PointToScreen(new Point(e.X, e.Y));
int width = endPoint.X - startPoint.X;
int height = endPoint.Y - startPoint.Y;
theRectangle = new Rectangle(startPoint.X, startPoint.Y, width, height);
// Draw the new rectangle by calling DrawReversibleFrame
// again.
ControlPaint.DrawReversibleFrame(theRectangle, this.BackColor, FrameStyle.Dashed);
}
}
private void SelectionTest_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
// If the MouseUp event occurs, the user is not dragging.
isDrag = false;
// Draw the rectangle to be evaluated. Set a dashed frame style
// using the FrameStyle enumeration.
ControlPaint.DrawReversibleFrame(theRectangle,
this.BackColor, FrameStyle.Dashed);
// Find out which controls intersect the rectangle and
// change their color. The method uses the RectangleToScreen
// method to convert the Control's client coordinates
// to screen coordinates.
Rectangle controlRectangle;
for (int i = 0; i < Controls.Count; i++)
{
controlRectangle = Controls[i].RectangleToScreen
(Controls[i].ClientRectangle);
if (controlRectangle.IntersectsWith(theRectangle))
{
Controls[i].BackColor = Color.BurlyWood;
}
}
// Reset the rectangle.
theRectangle = new Rectangle(0, 0, 0, 0);
}
private void ckbTimerEnabled_CheckedChanged(object sender, EventArgs e)
{
timer.Enabled = ckbTimerEnabled.Checked;
}
#region Designer
/// <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 Component 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.ckbTimerEnabled = new System.Windows.Forms.CheckBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// ckbTimerEnabled
//
this.ckbTimerEnabled.AutoSize = true;
this.ckbTimerEnabled.Location = new System.Drawing.Point(3, 114);
this.ckbTimerEnabled.Name = "ckbTimerEnabled";
this.ckbTimerEnabled.Size = new System.Drawing.Size(120, 17);
this.ckbTimerEnabled.TabIndex = 7;
this.ckbTimerEnabled.Text = "This.Invalidate timer";
this.ckbTimerEnabled.UseVisualStyleBackColor = true;
this.ckbTimerEnabled.CheckedChanged += new System.EventHandler(this.ckbTimerEnabled_CheckedChanged);
//
// comboBox1
//
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(29, 28);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(121, 21);
this.comboBox1.TabIndex = 6;
//
// button1
//
this.button1.Location = new System.Drawing.Point(29, 64);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 5;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(165, 36);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(35, 13);
this.label1.TabIndex = 4;
this.label1.Text = "label1";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(130, 74);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(35, 13);
this.label2.TabIndex = 8;
this.label2.Text = "label2";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(130, 98);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(35, 13);
this.label3.TabIndex = 9;
this.label3.Text = "label3";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(171, 74);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(35, 13);
this.label4.TabIndex = 10;
this.label4.Text = "label4";
//
// SelectionTest
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.ckbTimerEnabled);
this.Controls.Add(this.comboBox1);
this.Controls.Add(this.button1);
this.Controls.Add(this.label1);
this.Name = "SelectionTest";
this.Size = new System.Drawing.Size(226, 134);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckBox ckbTimerEnabled;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
#endregion
}
}
Form1.cs - 包含SelectionTest和两个侧面板
using System;
using System.Drawing;
using System.Windows.Forms;
namespace DrawReversibleFrameTest
{
public partial class Form1 : Form
{
Timer invalidateTimer = new Timer();
public Form1()
{
InitializeComponent();
invalidateTimer.Interval = 100;
invalidateTimer.Tick += invalidateTimer_Tick;
invalidateTimer.Enabled = ckbInvalidateTimer.Checked;
}
void invalidateTimer_Tick(object sender, EventArgs e)
{
this.panel1.Invalidate();
this.panel2.Invalidate();
}
private void selectionTest1_MouseMove(object sender, MouseEventArgs e)
{
if (this.ckbInvalidatePanelsOnMove.Checked)
{
this.panel1.Invalidate();
this.panel2.Invalidate();
//Console.WriteLine("Mouse move invalidate");
}
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
if (ckbPanel1DrawRectangle.Checked)
e.Graphics.FillRectangle(Brushes.Red, new Rectangle(new Point(2, 2), new Size(20, 60)));
}
private void Panel2_Paint(object sender, PaintEventArgs e)
{
if (ckbPanel2DrawRectangle.Checked)
e.Graphics.FillRectangle(Brushes.Red, new Rectangle(new Point(2, 2), new Size(20, 60)));
}
private void ckbInvalidateTimer_CheckedChanged(object sender, EventArgs e)
{
invalidateTimer.Enabled = ckbInvalidateTimer.Checked;
}
#region Designer
/// <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.panel1 = new System.Windows.Forms.Panel();
this.panel2 = new System.Windows.Forms.Panel();
this.ckbInvalidatePanelsOnMove = new System.Windows.Forms.CheckBox();
this.ckbInvalidateTimer = new System.Windows.Forms.CheckBox();
this.ckbPanel1Visible = new System.Windows.Forms.CheckBox();
this.ckbPanel2Visible = new System.Windows.Forms.CheckBox();
this.ckbPanel1DrawRectangle = new System.Windows.Forms.CheckBox();
this.ckbPanel2DrawRectangle = new System.Windows.Forms.CheckBox();
this.selectionTest1 = new DrawReversibleFrameTest.SelectionTest();
this.SuspendLayout();
//
// panel1
//
this.panel1.BackColor = System.Drawing.SystemColors.Highlight;
this.panel1.Location = new System.Drawing.Point(12, 12);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(49, 184);
this.panel1.TabIndex = 5;
this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.Panel1_Paint);
//
// panel2
//
this.panel2.BackColor = System.Drawing.SystemColors.Highlight;
this.panel2.Location = new System.Drawing.Point(350, 12);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(49, 130);
this.panel2.TabIndex = 6;
this.panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.Panel2_Paint);
//
// ckbInvalidatePanelsOnMove
//
this.ckbInvalidatePanelsOnMove.AutoSize = true;
this.ckbInvalidatePanelsOnMove.Location = new System.Drawing.Point(12, 256);
this.ckbInvalidatePanelsOnMove.Name = "ckbInvalidatePanelsOnMove";
this.ckbInvalidatePanelsOnMove.Size = new System.Drawing.Size(150, 17);
this.ckbInvalidatePanelsOnMove.TabIndex = 7;
this.ckbInvalidatePanelsOnMove.Text = "Invalidate panels on move";
this.ckbInvalidatePanelsOnMove.UseVisualStyleBackColor = true;
//
// ckbInvalidateTimer
//
this.ckbInvalidateTimer.AutoSize = true;
this.ckbInvalidateTimer.Location = new System.Drawing.Point(12, 279);
this.ckbInvalidateTimer.Name = "ckbInvalidateTimer";
this.ckbInvalidateTimer.Size = new System.Drawing.Size(97, 17);
this.ckbInvalidateTimer.TabIndex = 8;
this.ckbInvalidateTimer.Text = "Invalidate timer";
this.ckbInvalidateTimer.UseVisualStyleBackColor = true;
this.ckbInvalidateTimer.CheckedChanged += new System.EventHandler(this.ckbInvalidateTimer_CheckedChanged);
//
// ckbPanel1Visible
//
this.ckbPanel1Visible.AutoSize = true;
this.ckbPanel1Visible.Checked = true;
this.ckbPanel1Visible.CheckState = System.Windows.Forms.CheckState.Checked;
this.ckbPanel1Visible.Location = new System.Drawing.Point(168, 256);
this.ckbPanel1Visible.Name = "ckbPanel1Visible";
this.ckbPanel1Visible.Size = new System.Drawing.Size(94, 17);
this.ckbPanel1Visible.TabIndex = 9;
this.ckbPanel1Visible.Text = "Panel 1 visible";
this.ckbPanel1Visible.UseVisualStyleBackColor = true;
this.ckbPanel1Visible.CheckedChanged += new System.EventHandler(this.ckbPanel1Visible_CheckedChanged);
//
// ckbPanel2Visible
//
this.ckbPanel2Visible.AutoSize = true;
this.ckbPanel2Visible.Checked = true;
this.ckbPanel2Visible.CheckState = System.Windows.Forms.CheckState.Checked;
this.ckbPanel2Visible.Location = new System.Drawing.Point(168, 279);
this.ckbPanel2Visible.Name = "ckbPanel2Visible";
this.ckbPanel2Visible.Size = new System.Drawing.Size(94, 17);
this.ckbPanel2Visible.TabIndex = 10;
this.ckbPanel2Visible.Text = "Panel 2 visible";
this.ckbPanel2Visible.UseVisualStyleBackColor = true;
this.ckbPanel2Visible.CheckedChanged += new System.EventHandler(this.ckbPanel2Visible_CheckedChanged);
//
// ckbPanel1DrawRectangle
//
this.ckbPanel1DrawRectangle.AutoSize = true;
this.ckbPanel1DrawRectangle.Checked = true;
this.ckbPanel1DrawRectangle.CheckState = System.Windows.Forms.CheckState.Checked;
this.ckbPanel1DrawRectangle.Location = new System.Drawing.Point(268, 256);
this.ckbPanel1DrawRectangle.Name = "ckbPanel1DrawRectangle";
this.ckbPanel1DrawRectangle.Size = new System.Drawing.Size(135, 17);
this.ckbPanel1DrawRectangle.TabIndex = 11;
this.ckbPanel1DrawRectangle.Text = "Panel 1 draw rectangle";
this.ckbPanel1DrawRectangle.UseVisualStyleBackColor = true;
//
// ckbPanel2DrawRectangle
//
this.ckbPanel2DrawRectangle.AutoSize = true;
this.ckbPanel2DrawRectangle.Checked = true;
this.ckbPanel2DrawRectangle.CheckState = System.Windows.Forms.CheckState.Checked;
this.ckbPanel2DrawRectangle.Location = new System.Drawing.Point(268, 279);
this.ckbPanel2DrawRectangle.Name = "ckbPanel2DrawRectangle";
this.ckbPanel2DrawRectangle.Size = new System.Drawing.Size(135, 17);
this.ckbPanel2DrawRectangle.TabIndex = 12;
this.ckbPanel2DrawRectangle.Text = "Panel 2 draw rectangle";
this.ckbPanel2DrawRectangle.UseVisualStyleBackColor = true;
//
// selectionTest1
//
this.selectionTest1.BackColor = System.Drawing.SystemColors.ControlDark;
this.selectionTest1.Location = new System.Drawing.Point(67, 12);
this.selectionTest1.Name = "selectionTest1";
this.selectionTest1.Size = new System.Drawing.Size(277, 238);
this.selectionTest1.TabIndex = 0;
this.selectionTest1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.selectionTest1_MouseMove);
//
// Form7_DrawReversibleRectangleTest
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(449, 313);
this.Controls.Add(this.ckbPanel2DrawRectangle);
this.Controls.Add(this.ckbPanel1DrawRectangle);
this.Controls.Add(this.ckbPanel2Visible);
this.Controls.Add(this.ckbPanel1Visible);
this.Controls.Add(this.ckbInvalidateTimer);
this.Controls.Add(this.ckbInvalidatePanelsOnMove);
this.Controls.Add(this.panel2);
this.Controls.Add(this.panel1);
this.Controls.Add(this.selectionTest1);
this.Name = "Form7_DrawReversibleRectangleTest";
this.Text = "Form7_DrawReversibleRectangleTest";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private DrawReversibleFrameTest.SelectionTest selectionTest1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.CheckBox ckbInvalidatePanelsOnMove;
private System.Windows.Forms.CheckBox ckbInvalidateTimer;
private System.Windows.Forms.CheckBox ckbPanel1Visible;
private System.Windows.Forms.CheckBox ckbPanel2Visible;
private System.Windows.Forms.CheckBox ckbPanel1DrawRectangle;
private System.Windows.Forms.CheckBox ckbPanel2DrawRectangle;
#endregion
private void ckbPanel1Visible_CheckedChanged(object sender, EventArgs e)
{
this.panel1.Visible = ckbPanel1Visible.Checked;
}
private void ckbPanel2Visible_CheckedChanged(object sender, EventArgs e)
{
this.panel2.Visible = ckbPanel2Visible.Checked;
}
}
}
答案 0 :(得分:0)
您尝试做的伪逻辑是:
MouseDown:
MouseMove(带左按钮):
的MouseUp:
要排除故障:为DrawReversibleFrame()调用创建包装函数。绘制矩形后,将矩形边界打印到调试窗口。将鼠标拖过控件时,验证每个矩形是否被绘制两次。