当它应该向下时,它应该向右和向上移动时尝试绘制一个矩形

时间:2012-04-30 00:07:16

标签: c# winforms graphics drawing paint

我对DrawReversibleFrame()方法的使用导致绘制拖动操作的偏移和反转阴影。方法的名称(DrawReversibleFrame())似乎表明这可能是它应该工作的方式(绘制反转图像,而不是忠实地模仿你的动作)。但是,我想要相反(似乎没有简单的DrawFrame()方法)。

我尝试了两个在发布初始问题后显示的示例:How do I draw a rectangle based on the movement of the mouse?

这两个尝试可以在这里找到:

filled rubber band in Winforms Application

..在这里:

http://www.switchonthecode.com/tutorials/winforms-painting-on-top-of-child-controls

......但两人都不适合我。

首先,在我运行它们时,在两个示例的事件中调用base。*会导致StackOverflows(没有双关语)(通常我甚至不需要为StackOverflows做任何事情来炸毁我的应用程序)

我能够从DrawReversibleFrame()示例(上面的第二个链接)ALMOST工作中获取代码。但是,当我用鼠标向右和向下拖动(从左上到右下)时,绘制的矩形从右下角开始向上移动到左上角(但是我正在向相反的方向拖动 - 从左上角到右下角) - 移动的尺寸/数量似乎恰到好处。

此外,绘制操作开始的时间点也不在正确的位置 - 它在我的初始点左侧和上方开始。

注意:我正在使用PointToScreen(),因为拖动操作发生在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;

更新

在回应John的评论时,我在这里颠倒了数学:

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;
}

...但这只是为了取笑我,因为它使几乎工作,但是将PointToScreen()的调用更改为PointToClient()会使它变得更糟(进一步向左和顶部,有时候太大的矩形)。

这是现在的代码(矩形是完美的大小,但是从鼠标左侧和上方开始):

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));

另一个更新

注意:我正在动态创建的TableLayoutPanel上执行mousedown,它位于面板上,该面板位于表单上。

当我添加下面的代码时,值为25,然后是146.所以它似乎应该可以工作 - 它补偿了当TableLayoutPanel将Y值转换为146时有些事情。但它不是够了,还是...... ???

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;
        }
    }
}

再次更新

我终于能够在矩形下面发现TextBoxes并回答我的问题(我无法在StackOverflow上发布新问题,因为我超过了30天内的50个问题限制) :

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/9039ab0c-a587-476c-a952-9f35c6ccba42/

...但现在我还有另一个问题:

下面的代码确实找到了它下面的控件,因为它遍历面板上TextBoxes的所有,它确实发现了绘制的矩形下方的正确数量的控件(如果我拖动九个TextBox,找到九个。

但是,标记为找到的TextBox会不是正确的 - 它们不是我拖过的那些,而是位于TableLayoutPanel中的几行!

绘制的_FrameRect是从PointToScreen()转换而来的,textBox.Bounds是从RectangleToScreen()转换的,所以它们应该是同步的,但它们不是......(如果我没有这些转换相对位置的绝对位置,根本没有发现任何文本框。

// 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;
        }
    }
}

同样,找到了正确数量的控件,它们被“突出显示”(backColor属性已更改),但它们不是正确的。

最终更新

基于代码,我在这里上传了一只猫(或者一个frogleg):

http://www.c-sharpcorner.com/Forums/Thread/170813/

......我能够获得控件的伪高亮显示功能。这是相关的代码:

{{1}}

1 个答案:

答案 0 :(得分:1)

您需要使用您尝试使用的PointToScreen控件的TableLayoutPanel方法:

private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e) {
  if (e.Button != MouseButtons.Left)
    return;

  _IsSelecting = true;
  _StartPoint = tableLayoutPanel1.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 = tableLayoutPanel1.PointToScreen(e.Location);
  _FrameRect.Width = pt.X - _StartPoint.X;
  _FrameRect.Height = pt.Y - _StartPoint.Y;
  ControlPaint.DrawReversibleFrame(_FrameRect, Color.Black, FrameStyle.Dashed);
}