(C++/CLI) 测试与父级相关的矩形中的鼠标位置
我一直在搞乱 Graphics 类在面板上画一些东西。到目前为止,我一直在使用 矩形结构。在面板上,通过单击按钮,它会在随机位置创建一个矩形,并将其添加到其他矩形的数组中(它们实际上是一个名为 UIElement 的类,其中包含 Rectangle 成员)。单击此面板时,它会对所有元素运行测试,以查看鼠标是否在其中任何元素内,如下所示:
void GUIDisplay::checkCollision()
{
Point cursorLoc = Cursor::Position;
for(int a = 0; a < MAX_CONTROLS; a++)
{
if(elementList[a] != nullptr)
{
if(elementList[a]->bounds.Contains(cursorLoc))
{
elementList[a]->Select();
//MessageBox::Show("Click!", "Event");
continue;
}
elementList[a]->Deselect();
}
}
m_pDisplay->Refresh();
}
问题是,当我单击矩形时,没有任何反应。
UIElement 类在以下代码中绘制其矩形。但是,我对其进行了一些修改,因为在 这个示例它使用 DrawReversibleFrame 进行实际绘图的方法,因为我正在使用 Graphics.FillRectangle 方法。当我更改它时,我注意到 DrawReversibleFrame 绘制在与 FillRectangle 不同的位置。我相信这是因为 DrawReversibleFrame 使用其相对于窗口的位置进行绘制,而 FillRectangle 则相对于其所在的任何 Paint 事件进行绘制(在面板的 Paint 方法中进行挖掘)。所以让我只展示代码:
void UIElement::render(Graphics^ g)
{
if(selected)
{
Pen^ line = gcnew Pen(Color::Black, 3);
//g->FillRectangle(gcnew SolidBrush(Color::Red), bounds);
ControlPaint::DrawReversibleFrame(bounds, SystemColors::Highlight, FrameStyle::Thick);
g->FillRectangle(gcnew SolidBrush(Color::Black), bounds);
//g->DrawLine(line, bounds.X, bounds.Y, bounds.Size.Width, bounds.Size.Height);
}
else
{
ControlPaint::DrawReversibleFrame(bounds, SystemColors::ControlDarkDark, FrameStyle::Thick);
//g->FillRectangle(gcnew SolidBrush(SystemColors::ControlDarkDark), bounds);
}
}
我在 DrawReverisbleFrame 和 FillRectangle 中添加这样我就能看到差异。这就是我单击由 DrawReversibleFrame 绘制的框架时的样子:
橙色框是我单击的位置,黑色是其渲染的位置。这表明矩形的 Contains() 方法是查找与窗口相关的矩形,而不是面板。这就是我需要修复的:)
我想知道是否会发生这种情况,因为碰撞是在面板 Paint 方法之外进行测试的。但我不知道如何在 Paint 方法中实现此碰撞测试。
更新:
好的,所以我刚刚发现DrawReversibleFrame和FillRectangle绘制的内容似乎总是相距一定的距离。我不太明白这一点,但其他人可能会。
I've been messing around with the Graphics class to draw some things on a panel. So far to draw, I've just been using the Rectangle Structure. On a panel, by clicking a button, it makes a rectangle in a random place and adds it to an array of other rectangles (They're actually a class called UIElement, which contains a Rectangle member). When this panel is clicked, it runs a test with all the elements to see if the mouse is inside any of them, like this:
void GUIDisplay::checkCollision()
{
Point cursorLoc = Cursor::Position;
for(int a = 0; a < MAX_CONTROLS; a++)
{
if(elementList[a] != nullptr)
{
if(elementList[a]->bounds.Contains(cursorLoc))
{
elementList[a]->Select();
//MessageBox::Show("Click!", "Event");
continue;
}
elementList[a]->Deselect();
}
}
m_pDisplay->Refresh();
}
The problem is, when I click the rectangle, nothing happens.
The UIElement class draws its rectangles in the following bit of code. However, I've modified it a bit, because in this example it uses the DrawReversibleFrame method to do the actually drawing, as I was using Graphics.FillRectangle method. When I changed it, I noticed DrawReversibleFrame drew in a different place than FillRectangle. I believe this is because DrawReversibleFrame draws with its positions relative to the window, while FillRectangle does it relative to whatever Paint event its in (Mines in a panel's Paint method.) So let me just show the code:
void UIElement::render(Graphics^ g)
{
if(selected)
{
Pen^ line = gcnew Pen(Color::Black, 3);
//g->FillRectangle(gcnew SolidBrush(Color::Red), bounds);
ControlPaint::DrawReversibleFrame(bounds, SystemColors::Highlight, FrameStyle::Thick);
g->FillRectangle(gcnew SolidBrush(Color::Black), bounds);
//g->DrawLine(line, bounds.X, bounds.Y, bounds.Size.Width, bounds.Size.Height);
}
else
{
ControlPaint::DrawReversibleFrame(bounds, SystemColors::ControlDarkDark, FrameStyle::Thick);
//g->FillRectangle(gcnew SolidBrush(SystemColors::ControlDarkDark), bounds);
}
}
I add in both DrawReverisbleFrame and FillRectangle so that way I could see the difference. This is what it looked like when I clicked the frame drawn by DrawReversibleFrame:
The orange frame is where I clicked, the black is where its rendering. This shows me that the Rectangle's Contains() method is look for the rectangle relevant to the window, and not the panel. That's what I need fixed :)
I'm wondering if this is happening because the collision is tested outside of the panels Paint method. But I don't see how I could implement this collision testing inside the Paint method.
UPDATE:
Ok, so I just discovered that it appears that what DrawReversibleFrame and FillRectangle draw are always a certain distance apart. I don't quite understand this, but someone else might.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Cursor::Position 和 < a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.controlpaint.drawreversibleframe.aspx" rel="nofollow">DrawReversableFrame 在屏幕坐标中操作。这是针对整个屏幕、显示器上的所有内容,而不仅仅是窗口。另一方面, FillRectangle 对窗口坐标进行操作,即窗口坐标中的位置你的窗户。
如果您以使用两个框进行绘图的示例为例,并且两个框之间的距离始终相同,然后在屏幕上移动窗口然后再次单击,您将看到两个框之间的差异发生了变化。这将是窗口左上角和屏幕左上角之间的差异。
这也是为什么当您检查单击的矩形时没有击中任何东西的原因。您正在根据窗口空间中的矩形坐标测试屏幕坐标中的光标位置。它有可能会击中其中一个矩形,但它可能不是您实际单击的矩形。
你必须始终知道你的变量在什么坐标系统中。这与 的初衷有关Joel Spolsky 在他的条目 Making Wrong 中谈到的匈牙利表示法代码看起来错误。
更新:
PointToScreen 和 PointToClient 应该用于在屏幕和窗口之间转换坐标坐标。
Both Cursor::Position and DrawReversableFrame operate in screen coordinates. That is for the entire screen, everything on your monitor, and not just your window. FillRectangle on the other hand operates on window coordinates, that is the position within your window.
If you take your example where you were drawing with both and the two boxes are always the same distance apart, and move your window on the screen then click again, you will see that the difference between the two boxes changes. It will be the difference between the top left corner of your window and the top left corner of the screen.
This is also why when you check to see what rectangle you clicked isn't hitting anything. You are testing the cursor position in screen coordinates against the rectangle coordinates in window space. It is possible that it would hit one of the rectangles, but it probably won't be the one you actually clicked on.
You have to always know what coordiante systems your variables are in. This is related to the original intention of Hungarian Notation which Joel Spolsky talks about in his entry Making Wrong Code Look Wrong.
Update:
PointToScreen and PointToClient should be used to convert coordinates between screen and window coordinates.