EDIT:
So far all the answers have pointed out the code as originally written was hacky. I didn't write it, and don't understand fully how it all worked. However, in the general case, it did work. I have tried various tidy-ups, but they don't fix the basic problem, because of the strange behaviour of PointToScreen.
An alternative to explaining that behaviour, which I can see is difficult to explain without understanding the inner working of the rest of the form (and I don't at the moment), is to come up with an alternative way to implement the desired functionality, which is a small dialog appearing on top of a button when the button is pressed. The current implementation is a form which appears on top, and then tracks the original form to maintain its position. Is there a cleaner option?
Original Question:
I'm trying to position a form (form A) on top of a control (button B) on a form (form C) using PointToScreen:
Point buttonCorner = buttonB.Parent.PointToScreen(buttonB.Location);
where buttonB is a button in a FlowLayoutPanel on a form.
Most of the time it works, I get the position I expect. I use this code in a LocationChanged event on the form, so that form A tracks button B. This is working fine.
However, when another action causes the parent form to be resized, I find that the position of buttonCorner is offset, such that form A ends up off the screen (to the right). No part of my form is off the screen before this event.
The only theory I can come up with is that the LocationChanged event is firing while the FlowLayoutPanel is re-arranging, and it returns a bad position during that time. It seems a little far-fetched, but I don't have a better theory.
Suppose you have panelA and panelB. You have to register the LocationChanged of the panelB not of the form:
panelB.LocationChanged += (s,e) => {
Point buttonCorner = PanelControlFlow.PointToScreen(PanelControlFlow.Location);
//...
};
Anyway I can feel that your code has wrong approach, your 2 controls may not need to track each other unless you change their locations at runtime. You should provide more details so that we can find another better approach. Note that the FlowLayoutPanel will compact the controls automatically and positioning controls on it won't have any effect.
UPDATE:
For the reason why your PointToScreen returns some off-screen Point. I've tested this, when the form is minimized, its Location is -32000, -32000. All the PointToScreen will be added with this Location, that means if your control has Left calculated on your form is 300, then its Left calculated on the screen will be approximately -32000 + 300 = -31700. The same for Top. That's why your control's Location goes off screen. So you have to register the LocationChanged of the control you want to track to not the form. Why does the minimized window have Location of -32000,-32000? I think that's how a Window is hidden from screen.
Point buttonCorner = PanelControlFlow.PointToScreen(PanelControlFlow.Location);
That code is definitely wrong, the Location value is relative to the control's Parent. If you want to know where the panel's upper-left corner is located then you must use:
Point panelCorner = PanelControlFlow.PointToScreen(Point.Empty);
or for a button in the panel:
Point buttonCorner = someButtonInPanel.Parent.PointToScreen(someButtonInPanel.Location);
Then to get another button on top:
anotherButton.Location = anotherButton.Parent.PointToClient(buttonCorner);
Related
I am working on a mapped DVR/cctv UI.
I made it myself, so I did not use google's API. I just cut off big part of the map where I need it.
so, if I do have a really big map, then it won't fit in my pc's resolution, I haven't found a code to move the picture inside the pictureBox, but what I did is to move the pictureBox inside a panel. then it looked like a map, with boundaries. :)
now, I want to be able to save/attach this button to the picture.. so whenever and wherever I move the pictureBox, button gets along with it. even if goes outside the form, but when I drag it back, it appears to where it was let's say, attached just imagine the button like googlemap's marker. that's what I wanted to happen.
its like I am building my own offline google map..
if you have queries, feel free to ask. TIA
Simply add your button as a child of your picturebox:
button1.Parent = pictureBox1;
//or
pictureBox1.Controls.Add(button1);
Then you can use the Location property of your button to set it accordingly, that location is relative to your pictureBox, not your form.
If you want to keep the design location of your button, you can try this code:
Point loc = pictureBox1.PointToClient(button1.PointToScreen(Point.Empty));
button1.Parent = pictureBox1;
button1.Location = loc;
I have a problem with panel and weird area on it. I fill my panel with many PictureBoxes 32x32px, and a small area of this panel is filled with white area.
Here is how it looks like:
You can see that the first PictureBox has specified grass image, which is 32x32px, but the PictureBox below has only half of it's image. It's very strange.
I have also an onClick event specified for PictureBoxes to change it's background to other image. If I click on 'working' PictureBox it's background changes, but when I click on 'corrupted' one, it doesn't.
So basically, my question is - what could be the reason for such effect? Is it possible to find it out without analysing a code? I would like to avoid putting a code here, because it's very complicated and long.
EDIT
I used WinSpy++ and it is the result (red point is a place where i hover cursor)
so we can see that PictureBox is partly hidden behind this white area.
I don't know if the question is still active, but I'll try to respond anyway. It is more a comment on it, but since I'm not allowed to make comments yet I'll just answer.
I had encountered a similar issue when implementing some picutreBox drawing using onPaint event handler. The problem was that I called pictureBox.Invalidate() during onPaint and it caused displaying of the unwanted white color box. You might want to avoid using Invalidate() or Refresh() in your onPaint event if there is one.
If this is not the case it might also help to refresh the form or pictureBoxes that are corrupted. Try to call this.Refresh() after the form initialization, preferably in onLoad or onShown event handler.
If it still doesn't help then the problem is somewhere else, I'd guess there is a control hidden somewhere that causes that. But we'll need to see some code in order to suggest any other advice.
Hello,
Above is the program I am writing. On the right panel is basically two custom controls (the blue rectangle area) I created and just added them as controls to the background panel control when this winform program loads.
I used MS paint to draw out the pop up balloon that I want to see when my mouse enter this control's area. I want to do the following:
1. If mouse enter the control area, the yellow area balloon pop up and populate with the information of that specific control
2. If mouse move out of the control area, the pop up balloon disappear.
Can this be done with Winform application? I looked around and found out about Tooltip class but so far from researching I don't know if it does what I want to do.
I could be wrong but googling around gave me the impress that Tooltip offers very little in term of style. Ideally I want to make this pop up balloon into almost like a border-less pop up window where I can put image , font ect.....at will. Also Tooltip works if you hover over a button or specific field whereas I want the entire control area.
Can this be done? I appreciate if you can point me to any work around if there is one.
I wrote a comment, but I figure I'll expand it into a full answer. This is assuming you want a new control, which isn't a tooltip, for maximum customizability. I did something similar to this for work recently, to act as a non-modal info popup that disappears when clicked.
Creating a Custom Popup Form
What you want is essentially a floating popup that appears over your form, which means you'll want to define a new Form object, rather than a UserControl, as it won't actually be embedded within your other form.
Give it a multiline, non-editable textbox that you can fill with the information you want to populate, then simply call a new instance of the form on your Mouse_Enter event. Close it upon Mouse_Leave.
Adjusting The Style
You'll have to play with it a bit to get it to actually act like a popup and not just a window. I'd recommend setting it to a non-modal popup, and removing the border. You can write a function to automatically size it to its contents. I don't imagine you'll want the user manually resizing it.
Some other things to look into would be overriding the CreateParams property that comes with the basic Form object. You can force DropShadows and TopMost forms without making the form modal. Overriding ShowWithoutActivation to always return true will prevent the form from stealing focus when it pops up.
I'm not sure if you can pull off rounded edges like you have in your mockup. Perhaps you can pull it off with some wizardry in the OnPaint() function, but I couldn't tell you how to do it.
It might be a bit of a pain for fiddling around with, but you can get some good functionality and appearance out of it. If you think you can pull it off acceptably with the ToolTip class, go for it. It took me about a week to get my notifications where I wanted them (though I added several features that you probably don't need to worry about).
Examples
Some keywords to look up in related searches would be Toast Notification and Non-Modal Popup. This might be some use:
http://www.codeproject.com/Articles/442983/Android-Style-Toast-Notification-for-NET
Since you already have implemented custom user controls you might want to try it again. Make a control that is that style and color, changes it's size based on it's text. You can feed it information (such as the text to display) from your existing user control object. You can also have the mouse enter/leave code reside in your first user control.
If you're not sure how to make a rectangle with round corners you can either make it on the fly using a graphics object (which will turn into a bitmap on the screen) or make it how you want it to look in GIMP (or photoshop if you have it) then use that image as the background on your user control. Make the default background transparent (so your voids above the round corners are not grey). If you make a pre loaded image you'll need to be aware you will only be able to scale it equally in Y and X directions. unequal scaling will make it look distorted.
Can you use the Mouse_Enter event on the control?
I need to create a form with two panels:
1. Destination
2. Source
On the source panel there will be picture boxes. I need to be able to move it from source to point at destination panel with mouse.
I have a problem connected with different coordinates of the panels.
Please, help with advice or an idea what to do.
Moving those controls requires changing their Parent property. That's not easy to do, there is no good time to do this while the user is dragging with the mouse. You'll also get the effect of the panel clipping the control, you cannot display it on both with half of the control on one and the other half on the other panel. And yes, you have to change the Location property of the control when you change the parent or it will jump.
Punt the problem, don't use two panels. It only has to look like a panel, easily done by drawing one in the form's Paint method (or OnPaint override, better). Use e.Graphics.DrawRectangle or FillRectangle.
I feel quite limited by the default ContextMenuStrip, as it only can contain buttons, and no Controls.
I was wondering that for a long time, and I already tried it, using forms, but it never really worked out.
I already have I idea on how to set the whole thing up, with events and items. The only problem I have is the paint method.
When you open a ContextMenu (ContextMenuStrip) you can set its position on the mouse cursor, and it will be there, even if that means that it goes beyond the active form. (So I can't use the Controls Class as inheritance, as they can only draw themself as a part of a form.
Now I thought to use the Form Class as a base for my ContextMenu, but those where placed on the screen randomly.
So what I actually need is a class (or something similar) that can draw itself, without problems, and can be placed accurately on the screen.
Any hint would be nice, thanks.
Greg the Mad
Your first statement is false -- you can have a TextBox or a ComboBox in a ContextMenuStrip.
MSDN ToolStripComboBox
MSDN ToolStripTextBox
From the designer there is a small drop-down arrow when your mouse is in the "Type Here" box (sometimes hard to click) that will allow you to change the type.
If you are looking to allow for any type of control to be displayed in a top down fashion inside of a container to be positionable... you could always make a custom control using FlowLayoutPanel. With it's properties FlowDirection=TopDown and WrapContents=False to keep a vertical approach. This will handle your "menu" basics and your new control can expose whichever events you wish from each Control. You will have to handle the logic of showing the panel and positioning with it's Location property as well.
I forgot to address the issue with drawing outside of the parent form. Notice that ContextMenus are smart and when they reach a boundary of their parent they draw away from it. You should logically be able to draw in the correct direction (Up/Down or Left/Right) from any right mouse click. Per your attempt with a Form, set StartPosition=Manual then prior to calling Show() or ShowDialog() set it's Location property respective to the X and Y parameters provided in the event args of MouseClick.