I have a flowLayoutPanel on my form. I have some controls there which can be dragged and dropped . What I need is to get the index of the control, which is located on mouse position, for example if mouse is on the first widget, I have to get 0. Please show me some way how can I do it.
Thanks
EDIT
Frogot to upload the photo ,sorry
You will need to iterate through the controls in the flowLayoutPanel.Controls collection to find which control is under the mouse. Then iterate through the list again to find how many controls are above/equal height and to the left of the control in question.
I don't think you can avoid the 2 iterations, as the ordering of the collection is not tied to physical position.
I realize this is a 5-year old question, but since this question and answer still pop up in Google, I feel compelled to provide a genuine answer.
The FlowLayoutPanel class provides a method called GetChildAtPoint which takes a client-relative location and returns the control at that position (if the position is the mouse location relative to the FlowLayoutPanel window, then that identifies the control under the cursor). Worse case, then, you only have one linear search iteration through the FlowLayoutPanel's children to match objects (if in fact, your objective is to get the actual index instead of finding the index to look up the control; if finding the control is what you actually want, you are already done).
In my particular application, I needed to track things easily in a drag-drop scenario where a control could only be dragged within a range of related controls. So I used the "Tag" property to populate the index into the control itself as I was populating the panel (actually I stored a reference to the base class of my child control wrappers, and maintained the index in a base-class Property that I could query after casting the Tag to the base class, but I digress. The reference allowed me to get all kinds of cool information about the window under the cursor for appropriate display and/or manipulation in addition to maintaining the parent index).
Related
I'm using WPF to implement an interface to manage groups in a competition. Each group is represented by a custom user control (let's call it GroupControl)
Basically, a GroupControl displays the name of the group (editable Combobox with a list a predefined names), a list of players within the group (Gridview with information such as player name, player number, etc.), and several other data (as Textblocks).
Now, the interface is divided into 2 areas:
Area 1 : where I display all the groups.
Area 2 : where I'm supposed to work on the groups.
So the idea is to be able to drag and drop (copy, not move) a group from Area 1 to Area 2; but also to be able to drag a group from Area 1 or Area 2 onto another group from Area 2 (to merge it somehow).
I have a first implementation following this tutorial:
https://msdn.microsoft.com/en-us/library/vstudio/ms742859%28v=vs.100%29.aspx#Implementing_Drag_And_Drop
It is a very simple solution, and worked very well until I realized the following issue: since every GroupControl intercepts Drag/Drop related events, it prevents me from interacting with the nested controls. For instance, I can't scroll my list of players by clicking and dragging the scrollbar because the MouseMove event is intercepted at the GroupControl level; same goes for the ComboBox which somehow won't display its items unless I remove the MouseMove event.
So, I've started digging found many great Drag and Drop implementations using more complex yet more efficient concepts, especially Adorners or Behaviors.
I read the following:
- http://www.zagstudio.com/blog/488#.VYqJFEZ4SdE
It seems to be working very well: I can drag/drop items from an area to another, I can even insert them at a specific position. BUT, I haven't found a way to use this solution to drag/drop a GroupControl onto another GroupControl.
Any help on this matter will be much appreciated. All I want to achieve is being able to interact with the nested controls within the GroupControl.
I have created a class that allows the user to drag panels on a forms. How can I ensure
that the user does not place two panels on top of each other? If they do, I would like to shift/or highlight one of the control while they are both overlapped.
I tried setting this in OnMouseDown event but that didn't quite work.
Also, the number of panels on the form vary depending on the number of pictures the form needs to show. Each panel has a picturebox inside the panel.
A much better approach is to use the Rectangle.Bounds.IntersectsWith method, which does the check for you and can produce cleaner code. I'm personally unaware of any performance issues or benefits, one way or the other, although I would venture a guess that simply looping over your controls and checking them with this would be faster than building lists and loops both.
Picturebox pic = new Picturebox();
foreach(Control picturebox in Form1){
if (pic.Bounds.IntersectsWith(picturebox.Bounds))
{
//We have a problem, Houston, because we just collided!
}
}
I hope this helps, even though you asked this question some time ago.
So I was able to solve this question with the help of sgud's suggestion.
The trick was to use Rectangle.Intersect method inside OnMouseUp event raised.
Here is the intuition I used behind it. (it might not be the neatest solution)
1) Create a list of all the controls inside my main panel.
2) Traverse through the controls and create a list of all the Rectangle Bounds for each control. you can get this by control.Bounds
3) Go through the list of Bounds and intersect it with the currently active element's bound.
If the returned rectangle has height and width the same as the active control then assign change the back color property.
I hope this helps to anyone else that have a similar problem
I try to explain my problem:
I got many customcontrols of same type on a panel.
At runtime I'm free to move any custumcontrol ( mousedown and mousemove events) in the form with mouse over any others customcontrols using bringtofront() to have it over all.
Now I need to know when the control I'm moving is over any other control and which control is under.
So far I've tryed to use drag-n-drop events but without success, there's some other way to do this or I've to re elaborate it with drag events?
thank you all for help
and sorry for my English.
EDIT:
The controls are cards game and my final goal is to use cards to create logical sequence following rules based on card value and/or color.
You can't solve the problem with drag-and-drop because you're not actually dropping one control onto the other control. You're merely moving them around in the form.
You need to become familiar with Z order, which is the front-to-back arrangement of objects in a virtual 3D space. To adjust the Z order, you can call the BringToFront and SendToBack methods of any object that derives from System.Windows.Forms.Control.
The Z order is also exposed by the parent (container) control's Controls collection. Using the GetChildIndex method, you can determine the position of any control within the Z order.
So now, all you need to do is figure out which control the control you're dragging is over. Do that by comparing the Location properties of the two controls. When you know that the locations of two controls overlap, check their respective Z order indices to see which one is on top.
I just wasted my entire evening on something which I thought would be very simple but it seems WPF and Google are letting me down completely.
I need a grid, 6x6 of which I fill every row and column with a custom control. I want to be able to navigate through this grid via the keyboard (I can get those events, no problem) but I cannot seem to find how I can always have the selected grid row/column in the center of my window.
I found some carousel alike implementations, but most of them only work in a single direction and I want two way navigation, yet none seem to support this nor can I extend them to do this.
I essentially want to create a PSP alike grid navigation.
One easy way is to do this:
Create a scrollable form.
Add a 6x6 grid of child controls.
In the GotFocus (or similar) event for all the controls, set the parent form scroll offset to an appropriate position to centre the child.
This is pretty straight-forward thing to implement, with a little bit of maths to work out how to centre the x,y position of a control by setting the scroll offsets (it can be tricky/confusing, but as long as you understand the coordinate systems used for scrolling, not too bad)
Or, another approach that avoids scrolling via the windows APIs and using custom controls:
Create a form
Override OnPaint to draw your grid of 6x6 "controls" as simple graphical shapes or bitmap images centred on the selected "control".
Handle keyboard (KeyDown/Up) and mouse handling (MouseDown/Up) events to make the 36 areas of the graphic respond to user inputs in the way you desire. You'll have to track the selected item and force the window to redraw its graphics to show the new state. Enable double buffering to stop it flickering.
The first approach gives you a lot of windows-based handling for free (tabbing between controls, remembering where the input focus is, and directing events to separate classes for each "control", for example). The second approach strips away all this "help" but gives you complete control over everything, which can often help avoid unintended behaviours (e.g. it won't move the input focus when the user presses Tab unless you specifically write the code to make it do that).
While I can easily accomplish in ASP.NET using AddAt(), I am trying to do the same thing in Windows Forms.
I have a panel, and while I can do a pnlMyPanel.Controls.Add(ctl) ... it always inserts it in the 0 position, when I would rather have it appended to the end, or pnlMyPanel.Controls.Count.
Am I overlooking a method or am I going to have to do something else?
It depends how your controls are being laid out.
I assume that all of the controls in the panel have their Dock property set. If so, call BringToFront, SendToBack, or SetChildIndex on the new control after adding it to the panel.
If not, set the Top and Left properties (or the Location property) of the new control.
AddAt functionality can be implemented by a combination of Add and SetChildIndex methods.
You can use
SetChildIndex Method
to reorder the index of the child control after adding the child control.
When SetChildIndex is called, the
Control referred to by the child
parameter is moved to the position
specified by newIndex and the other
Control references in the
Control..::.ControlCollection are
reordered to accommodate the move. The
control with an index value of zero is
at the top of the z-order, and higher
numbers are closer to the bottom.