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;
Related
Say I had a control like a Picture Box on my Windows Form and I wanted the user to be able to drag it around the panel like a canvas freely to any position they want. What would be the best way to do this?
Afterwards, I want to be able to retrieve the location of the image on the panel. Obviously I'd need the MouseDown event, and my first idea would be to set the location of the control equal to the cursors location, but this glitchy and not smooth.
This post might help as well HERE...
and to display the output, simply add a label or textbox and display the coordinates- something like:
textbox1.Text = pictureBox1.Location.ToString();
or take the coordinates by:
pictureBox.Location (which is a point) -or-
pictureBox.Location.X // pictureBox.Location.Y (which are integers)
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);
I have problem with showing a diagram which is too big to see on one panel.
I have to scrollbars which should change the point of view on the diagram, but when i want to scroll the picture, the shapes are moving on the different position, everything getting crushed.
it looks like this here link
when i show it,and like this here link when i try to look on the bottom of the graph
it looks like application drawing the shapes every time when i scroll the panel, and when i go on the bottom of picture the point on the top left corner still is (0,0) not (0,500)
I have algorithm, which giving value of location on the panel and nr id of object to the array, then i have the loop which drawing it, getting info from dictionary about the object and his position from array.
How this problem can be solved ?
Thx for any advice's
Edited
I dont want to draw it again i want to draw one big graph, something like this(link in the comment), but i know that user can make for example 50 objects(shapes) and that kind of big graph cant be seen on the small panel so we have to have a chance to scroll and see the bottom of grapf, left side or this side which he want.
I'll try to give more details about application.
When you lunch it, you see the control panel(form1), where you adding events/functions/xor/or every of this option have their own shape on the graph.
So user adds for example event with text, pressing the button add which creates the object and adding it to the collection. He can adds events/functions,xor/or as many as he wants.
Ok, when he adds everything what he wanted, and now he would like to see graph so he pressing the button "generate the diagram", now the application is showing the next windwow with panel and scrollbars. You can see the window in links.
In the second form after this line
private void panel1_Paint(object sender, PaintEventArgs e){
I have algorithm which is putting the coordinate values to table, then forech loop is taking from dictionary ( collection):
text which should be shown on diagram in the middle of shape,
value which determine a type of shape on the panel.
from arrays loop taking the coordinate values.
This how its work, I can also put a code in here when its needed.
The standard mistake is forgetting to offset your drawing by the scroll position. Use the panel's AutoScrollPosition property, like this:
void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
e.Graphics.DrawLine(Pens.Black, 0, 0, 300, 2000);
}
The Panel control is in general pretty cranky about painting, it was designed to be a container control. You typically also want it double-buffered and to force a repaint when it is being resized. Setting the DoubleBuffered and ResizeRedraw properties requires deriving your own control from Panel.
It looks like application drawing the shapes every time when i scroll the panel
Why don't you erase the drawing area and draw the shapes again?
Maybe you can post a code snippet?
The scenario is that i want the user to create a shape in a small panel that opens (the added shape can later be placed on the canvas), but for a better reference, i want the user to be able to move the semi-transparent panel somewhere on the canvas and then draw with the accurate reference.
Please tell me:
Which panel type to use
How to make it moving by clicking the mouse on the move button (not the whole panel as dragging will be used for drawing lines) and move it around.
How to make it semi transparent.
How to make it appear and disappear (this should be pretty simple)
How to somehow limit its movement inside the canvas so it cannot move on the ribbon
And I really really hope there will be something built-in in WPF that i'll be able to use, and i will not have to do it the hard way i.e. create a rectangle, and do customized hit testing on it to allow the user to draw on top of that rectangle, make that rectangle transparent, and add graphics items for the buttons and controls on that rectangle "panel".
I am asking this because i have never seen such feature in any Windows application and i have no idea what to use for this purpose and how to implement it. The closest thing to what i want is in Adobe Acrobat Pro, which is the small preview of the page that appears when i double click with the middle mouse button. It doesn't move, nor it is transparent or can be drawn upon, but scale and shape wise i want something similar.
You should be able to place a second Canvas inside of your main canvas, and place whatever UserControl you'd like with your "view" inside of it.
You'll have to handle the mouse click/drag for moving it around yourself, but otherwise, it should be very straightforward.
Ok, I have googled, but maybe I put my search in weirdly. :/
I have a VB.NET WinForms application. I have the anchor properties set for all the controls so that it will resize all the controls to look decent when the form is maximized. (Haven't gotten around to manual resizing yet however).
Anyway, the problem:
I go to set the same properties for a button (testing with a single button for now) on the main GUI form/picture. When I go to run the program via F5, it looks decent. But when I maximize the form, the entire button covers up more than it should.
I've taken screenshots of the form so you can see a visual of what I'm talking about. :/
Before: http://zack.scudstorm.com/before.png
After: http://zack.scudstorm.com/after.png
What other propert(y|ies) do I need to set for the buttons to show up correctly? :/ (The buttons go over the boxes that say, for example, "1-1", "2-3", etc.
Thanks,
-Zack
Seems like you have anchored top-left and bottom-right when what you want is just top-left.
Edit: If it's just an image that does not change when the winform changes, then don't anchor your buttons at all. Just put them where they go. If you are scaling the image, then I would either detect the clicks on the image and do the scaling math or do the scaling math and set my buttons in code in the Form.OnResize event.
As it appears that your goal is just to be able to handle clicks on the "computers"...
One option that can be useful for this sort of task is to create an "overlay" bitmap (not displayed, but which is the exact same size as your source bitmap) which uses different colors to represent all the clickable regions. (e.g. (R=0,G=0,B=0) for computer 0, (0,0,1) for computer 1, etc)
You could even generate this bitmap somewhat automatically without too much trouble (If you have a mode where you can click the top left and then bottom right corners of the image to define a new region)
When the mouse is clicked, you can check the pixel at the scaled coordinates of the mouse position in the overlay and determine what their click corresponds to. This can be a lot easier than creating loads of controls, and makes it a lot easier to have clickable regions that aren't rectangular.