1

我对该DrawReversibleFrame()方法的使用导致绘制了我的拖动操作的偏移和反转阴影。方法的名称DrawReversibleFrame()(但是,我想要相反的(而且似乎没有简单的DrawFrame()方法)。

我尝试了两个示例,这些示例是在我发布初始问题后指出的:如何根据鼠标的移动绘制矩形?

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

Winforms 应用程序中的填充橡皮筋

..和这里:

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 个问题的限制):

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

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

代码(下面)现在确实找到了它下面的控件,因为它循环遍历面板上的所有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;
        }
    }
}
4

1 回答 1

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);
}
于 2012-05-01T15:54:18.100 回答