问题
I'm trying to set the back color of each TextBox that is within the rectangle defined between a MouseDown and MouseUp event, where the MouseUp event takes place to the right of and below the MouseDown event.
I capture the Points this way:
static readonly Color PSEUDO_HIGHLIGHT_COLOR = Color.Gainsboro;
private Point selectionStart;
private Point selectionEnd;
. . .
private void flowLayoutPanelGreatGooglyMoogly_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
selectionStart = PointToClient(MousePosition);
}
}
private void flowLayoutPanelGreatGooglyMoogly_MouseUp(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
selectionEnd = PointToClient(MousePosition);
HighlightAllTextBoxValsBetweenPoints();
}
}
...and here's the code that should set the BackColor of the TextBoxes "beneath" the virtual rectangle described by the Points:
private void HighlightAllTextBoxValsBetweenPoints() {
TextBox tb;
foreach (Control ctrl in flowLayoutPanelGreatGooglyMoogly.Controls) {
if (ctrl is TextBox) {
tb = (TextBox)ctrl;
if ((tb.Location.X >= selectionStart.X) &&
(tb.Location.Y >= selectionStart.Y) &&
(tb.Location.X <= selectionEnd.X) &&
(tb.Location.Y >= selectionEnd.Y)) {
tb.BackColor = PSEUDO_HIGHLIGHT_COLOR;
}
}
}
}
...but, although the code is being executed, none of the TextBoxes are ever seen as being within those constraints.
It's as if I'm dragging over a map of the good ol' USA, but the troll under the bridge is telling me that Kansas is really in Canada.
My logic is probably mixed-up or backwards (failing to compare the X and Y coordinates correctly), or I'm failing to convert the Points from relative to absolute or vice versa.
UPDATE:
The answer was almost perfect (and how was John to know that my FlowLayoutPanel was situated where it was); to get it to work, I just had to add this above his code:
// Have to subtract the Top (Y) value of the Panel
int DeltaFromFormTopToPanelTop = flowLayoutPanelGreatGooglyMoogly.Location.Y;
selectionStart.Y = selectionStart.Y - DeltaFromFormTopToPanelTop;
selectionEnd.Y = selectionEnd.Y - DeltaFromFormTopToPanelTop;
UPDATE to the UPDATE
To prevent the coloring/prompting when a user has only selected one control, I had to add this code, too:
if (e.Button == MouseButtons.Left) {
selectionEnd = PointToClient(MousePosition);
if (MouseHasNotMovedFar()) {
return;
}
HighlightAllTextBoxValsBetweenPoints();
PromptForAndAssignInputValue();
}
private bool MouseHasNotMovedFar() {
// The "X" or horizontal, is TextBoxWidth*2 + LabelWidth*1
// The "Y" or vertical, is TextBoxHeight*2
// If the user has moved the mouse less than these between
// MouseDown and MouseUp, they probably have not dragged to
// select multiple TextBoxes.
const int ACCEPTABLE_X_DELTA = 74;
const int ACCEPTABLE_Y_DELTA = 40;
return (selectionEnd.X - selectionStart.X) <= ACCEPTABLE_X_DELTA &&
(selectionEnd.Y - selectionStart.Y) <= ACCEPTABLE_Y_DELTA;
}
回答1:
There's a few issues.
First - textbox coordinates are relative to the flowLayoutPanel. Therefore your PointToClient must be the same:
selectionStart = flowLayoutPanelGreatGooglyMoogly.PointToClient(MousePosition);
Second - you had a logic bug; the last comparison was reversed. (tb.Location.Y >= selectionEnd.Y)) {
A suggestion to simplify the process and allow dragging in any direction would be to use Rectangles:
private void HighlightAllTextBoxValsBetweenPoints()
{
var selectionBounds = new Rectangle(
selectionStart.X,
selectionStart.Y,
selectionEnd.X - selectionStart.X,
selectionEnd.Y - selectionStart.Y);
foreach (Control ctrl in flowLayoutPanel1.Controls)
{
var tb = ctrl as TextBox;
if (tb == null)
continue;
if (tb.Bounds.IntersectsWith(selectionBounds))
tb.BackColor = PSEUDO_HIGHLIGHT_COLOR;
}
}
来源:https://stackoverflow.com/questions/10342291/there-seems-to-be-a-mismatch-between-the-location-of-my-controls-and-the-locatio