我对该DrawReversibleFrame()
方法的使用导致绘制了我的拖动操作的偏移和反转阴影。方法的名称DrawReversibleFrame()
(但是,我想要相反的(而且似乎没有简单的DrawFrame()
方法)。
我尝试了两个示例,这些示例是在我发布初始问题后指出的:如何根据鼠标的移动绘制矩形?
这两个尝试可以在这里找到:
..和这里:
http://www.switchonthecode.com/tutorials/winforms-painting-on-top-of-child-controls
...但没有一个对我有用。
首先,在这两个示例的事件中对 base.* 的调用在我运行它们时会导致 StackOverflows(没有双关语)(通常我什至不需要为 StackOverflows 做任何事情来炸毁我的应用程序)。
我能够从DrawReversibleFrame()
示例(上面的第二个链接)改编的代码几乎可以正常工作。但是,当我用鼠标向右和向下(从左上角到右下角)拖动时,绘制的矩形从右下角开始向上到左上角(但我正在以相反的方式拖动 - 从左上角到右下角)——不过,移动的大小/数量似乎完全正确。
此外,绘制操作开始的点也不完全在正确的位置——它开始于我的初始点的左侧和上方。
注意:我正在使用PointToScreen()
,因为拖动操作发生在 a 上TableLayoutPanel
,它已放置在表单的顶部。如果我不使用它,我根本看不到任何绘图。
我的代码是:
public partial class Form1 : Form
{
private bool _IsSelecting = false;
private Point _StartPoint = Point.Empty;
private Rectangle _FrameRect = Rectangle.Empty; //1
public Form1()
{
InitializeComponent();
// DoubleBuffered = true; //makes no apparent difference either way
}
private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
_IsSelecting = true;
_StartPoint = PointToScreen(e.Location);
_FrameRect = new Rectangle(_StartPoint, Size.Empty);
}
private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (!_IsSelecting)
return;
ControlPaint.DrawReversibleFrame(_FrameRect, Color.Black, FrameStyle.Dashed);
Point pt = PointToScreen(e.Location);
_FrameRect.Width = _StartPoint.X - pt.X;
_FrameRect.Height = _StartPoint.Y - pt.Y;
ControlPaint.DrawReversibleFrame(_FrameRect, Color.Black, FrameStyle.Dashed);
}
private void tableLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
{
if (!_IsSelecting)
return;
ControlPaint.DrawReversibleFrame(_FrameRect,
Color.Black, FrameStyle.Dashed);
_IsSelecting = false;
_FrameRect = Rectangle.Empty;
_StartPoint = Point.Empty;
}
}
更新
为了回应约翰的评论,我在这里颠倒了数学:
_FrameRect.Width = pt.X - _StartPoint.X;
_FrameRect.Height = pt.Y - _StartPoint.Y;
...但这只会取笑我,因为它使它几乎可以工作,但是将对 PointToScreen() 的调用更改为 PointToClient() 会使情况变得更糟(更靠近左侧和顶部,有时矩形太大)。
这是现在的代码(矩形是完美的大小,但从鼠标的左侧和上方开始):
private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
_IsSelecting = true;
_StartPoint = PointToScreen(e.Location);
//_StartPoint = PointToClient(e.Location); //<- this makes it way worse - the rectangle is way too big, and starts even further up and to the left
_FrameRect = new Rectangle(_StartPoint, Size.Empty);
}
private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (!_IsSelecting)
return;
ControlPaint.DrawReversibleFrame(_FrameRect, Color.Black, FrameStyle.Dashed);
Point pt = PointToScreen(e.Location);
//Point pt = PointToClient(e.Location); //worse
_FrameRect.Width = pt.X - _StartPoint.X;
_FrameRect.Height = pt.Y - _StartPoint.Y;
ControlPaint.DrawReversibleFrame(_FrameRect, Color.Black, FrameStyle.Dashed);
}
private void tableLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
{
if (!_IsSelecting)
return;
ControlPaint.DrawReversibleFrame(_FrameRect,
Color.Black, FrameStyle.Dashed);
_IsSelecting = false;
_FrameRect = Rectangle.Empty;
_StartPoint = Point.Empty;
}
另一个更新
注意:我在动态创建的 TableLayoutPanel 上执行 mousedown,它位于表单上的面板上。
当我添加下面的代码时,值是 25,然后是 146。所以它似乎应该工作 - 当它将 Y 值转换为 146 时,它补偿了 TableLayoutPanel 上方有东西的事实。但这还不够,或者...???
log.Debug(String.Format("Mouse Down Location.Y = {0}", e.Location.Y));
_StartPoint = PointToScreen(e.Location);
log.Debug(String.Format("Mouse Down PointToScreen Location.Y = {0}", _StartPoint.Y));
另一个更新
我终于能够在这里找到矩形下方的文本框以及我的问题的答案(我无法在 StackOverflow 上发布新问题,因为我已经超过了 30 天内 50 个问题的限制):
...但现在我有另一个问题:
代码(下面)现在确实找到了它下面的控件,因为它循环遍历面板上的所有TextBox,并且它确实发现了绘制的矩形下面的正确数量的控件(如果我拖动超过 9 个 TextBox,它会找到 9 个)。
但是,标记为找到的文本框不是正确的——它们不是我拖过的文本框,而是位于 TableLayoutPanel 中的几行下方!
绘制的 _FrameRect 是从 PointToScreen() 转换而来的,而 textBox.Bounds 是从 RectangleToScreen() 转换而来的,所以它们应该是同步的,但不知何故,它们不是……(如果我没有这些绝对位置到相对位置,根本没有发现任何文本框)。
private void HighlightAllTextBoxValsBetweenPoints() {
foreach (Control ctrl in tableLayoutPanelGreatgooglyMoogly.Controls) {
var tb = ctrl as TextBox;
if (tb == null)
continue;
if (RectangleToScreen(tb.Bounds).IntersectsWith(_FrameRect)) {
//MessageBox.Show(String.Format("{0}", tb.Name));
tb.BackColor = PSEUDO_HIGHLIGHT_COLOR;
}
}
}
同样,找到了正确数量的控件,并且它们被“突出显示”(backColor 属性已更改),但它们不是正确的。
最后更新
根据在此处上传的一只猫(或青蛙腿,我猜)的代码:
http://www.c-sharpcorner.com/Forums/Thread/170813/
...我能够使控件的伪突出显示正常工作。这是相关的代码:
// Declare a rectangle and a point:
Rectangle describedRect;
Point startingPoint;
private bool _IsSelecting = false; // <- already had this
// In the MouseDown event:
_IsSelecting = true;
startingPoint = e.Location;
// In the MouseMove event:
if (!_IsSelecting)
return;
describedRect = Rectangle.FromLTRB(startingPoint.X, startingPoint.Y, e.X, e.Y);
// In the MouseUp event:
if (!_IsSelecting)
return;
HighlightAllTextBoxValsBetweenPoints();
_IsSelecting = false;
private void HighlightAllTextBoxValsBetweenPoints() {
foreach (Control ctrl in tableLayoutPanelGreatGooglyMoogly.Controls) {
var tb = ctrl as TextBox;
if (tb == null)
continue;
if (describedRect.IntersectsWith(tb.Bounds)) {
tb.BackColor = PSEUDO_HIGHLIGHT_COLOR;
}
}
}