 |
|
 |
is it possible to set a button to add new blocks ? and add snapping to borders ? for eg. divide work area into 3 columns and 3 rows (that will give us 9 cells) and one block can be only in one full cell ? and then add some other block that will have at the moment 8 cells to chose (available by drag and drop like You had presented) ? i just ask cause i don;t know how to achieve this, i don't expect You just to do this, but maybe You will have some guides for me, thanks in advance
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The MaxWindowTrackSize property indicates the maximum dimensions to which a user can drag resize a window. The value returned by MaxWindowTrackSize refers to the dimensions of the entire desktop. http://msdn.microsoft.com/en-us/library/system.windows.forms.systeminformation.maxwindowtracksize.aspx[^]
Outline will be limited in MaxWindowTrackSize. Here is the fixed code.
class Outline: Form { #region Attributes
private static Outline outline = null; private Point m_Delta = new Point(0, 0);
public Point Delta { get { return m_Delta; } set { m_Delta = value; } } #endregion
#region Constructor // Constructor private Outline() { // Set some properties to make this form a transparent black rectangle this.SuspendLayout(); this.ClientSize = new System.Drawing.Size(0, 0); this.StartPosition = FormStartPosition.Manual; this.BackColor = Color.Black; this.Opacity = 0.4; this.FormBorderStyle = FormBorderStyle.None; this.ShowInTaskbar = false; this.ControlBox = false; this.TopMost = true; this.ResumeLayout(false); } #endregion
#region Methods /// // Show static public void Show(Point location, Size size) { // Create a new object? if(outline == null) { outline = new Outline(); outline.Show(); // Just to get the size correct at first use (.NET bug?). Try to remove this line... } // Set the location and size, then show the form //outline.Location = location; outline.Location = new Point((location.X > 0 ? location.X : 0), (location.Y > 0 ? location.Y : 0)); outline.Delta = new Point((location.X < 0 ? location.X : 0), (location.Y < 0 ? location.Y : 0)); Size displaySize = new Size(outline.Delta.X + size.Width, outline.Delta.Y + size.Height); outline.Size = displaySize; outline.Show(); } // Hide new static public void Hide() { if(outline != null) { // Since we hide the original Hide() method we need to do this... (outline as Control).Hide(); } }
// Resize new static public void Resize(Size size) { if(outline != null) { Size displaySize = new Size(outline.Delta.X + size.Width, outline.Delta.Y + size.Height); (outline as Control).Size = displaySize; //(outline as Control).Size = size; } }
// Move new static public void Move(Point location) { if(outline != null) { //(outline as Control).Location = point;
Point originalDelta = outline.Delta; outline.Location = new Point((location.X > 0 ? location.X : 0), (location.Y > 0 ? location.Y : 0)); outline.Delta = new Point((location.X < 0 ? location.X : 0), (location.Y < 0 ? location.Y : 0));
Point shift = new Point(outline.Delta.X - originalDelta.X, outline.Delta.Y - originalDelta.Y);
Size displaySize = new Size((outline as Control).Size.Width + shift.X, (outline as Control).Size.Height + shift.Y); (outline as Control).Size = displaySize; } } #endregion
private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Outline)); this.SuspendLayout(); // // Outline // resources.ApplyResources(this, "$this"); this.Name = "Outline"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.ResumeLayout(false);
} }
Welcome to discussion. puzzlefun@hotmail.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I'm trying to enable the use of full positioning control (ala Frontpage) through a custom WinForm app that would alter a ASPX page... Can the same types of things be used here to alter a WebForm?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Sorry - I have not tested that - so I don't know if similar technique can be used... Please let me know how you solve it!
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi all!
There might be a need to improve the cursor part. At least if large objects are moved. Below is some suggestions of how to do this, but none is really easy. So help me out! I don’t update the code in the article until I have a good solution.
First a bug
In the event method userControl_MouseUp in MyUserControl.cs there should be a line that unregister the MouseMove event! So please add it if you are using this code.
// Handle mouse up; Perform a local move private void userControl_MouseUp(object sender, MouseEventArgs mouseEventArgs) { ... // Unregister the mouse move handler (sender as Control).MouseMove -= new MouseEventHandler(userControl_MouseMove); ... }
Second some ways to improve the cursor handling
(1) The smallest change is to really clean up. That is calling Dispose() before we create the next cursor. I found out that using bitmap.GetHicon() will give a resource that is not managed. See this thread. It is possible to add a win32 call to dispose it direct. This way it works with large objects - but it's still ugly and slow. And it’s no fun to add win32 calls. Add/change this in MyUserControl.cs
... using System.Runtime.InteropServices; ... [DllImport("user32.dll", EntryPoint="DestroyIcon")] static extern bool DestroyIcon(IntPtr hIcon); ... private Graphics cursorGraphics = null; private Bitmap bitmap = null; private Cursor cursor = null; private IntPtr intPtr = IntPtr.Zero; private Pen cursorPen = new Pen(Color.Black);
// Replace the default cursor when begin to move or drag this object private Cursor OutlineCursor() { // Clean up if(cursor != null) cursorGraphics.Dispose(); if(cursorGraphics != null) cursorGraphics.Dispose(); if(bitmap != null) bitmap.Dispose(); if(intPtr != IntPtr.Zero) DestroyIcon(intPtr); // Create a new cursor bitmap = new Bitmap(this.Width * 2, this.Height * 2); if(cursorGraphics != null) cursorGraphics.Dispose(); cursorGraphics = Graphics.FromImage(bitmap); cursorGraphics.DrawRectangle(cursorPen, this.Width - startPoint.X, this.Height - startPoint.Y, this.Width - 1, this.Height - 1); intPtr = bitmap.GetHicon(); cursor = new Cursor(intPtr); return cursor; }
(2) How to get rid of the "4 times as big as the object" cursor? Or how to set the HotSpot in the cursor. That seems impossible... The HotSpot is read only. The only way to set it is at design time (when creating a new cursor in VS2005). But at runtime it's not possible. I found this nice description of the .cur file format. My thought was to just create a bitmap with the same size as the object and add the header information to this bitmap to make it a cursor (or icon that is almost the same). Maybe SetPropertyItem() could be used. Or some other way to add this small info to the bitmap... This would be a nice piece of code to use in many other projects! Or we can use the old win32 call CreateCursor(…). See this nice article!
(3) Why not skip using a cursor and instead draw the outline direct onto the parent? Well yes, I almost managed that. But first, it's creating more ugly connections from child to parent, and second, it was hard to continually draw the outline if there was a background picture in the parent window – try it and you will see. Remove the OutlineCursor() method and add the code below to your MouseMove event method. You also need a Parent.Invalidate() in MouseUp.
// Handle mouse-move; If we are out of parent container then preform global drag private void userControl_MouseMove(object sender, MouseEventArgs mouseEventArgs) { // Get the current mouse coordinates as screen coordinates Point point = this.PointToScreen(new Point(mouseEventArgs.X, mouseEventArgs.Y)); // Have we left the parent container? if(IsCursorOutside(point) == true) { // Unregister this event (sender as Control).MouseMove -= new MouseEventHandler(userControl_MouseMove); // Clean up if(cursorGraphics != null) { cursorGraphics.Dispose(); cursorGraphics = null; Parent.Invalidate(); } // Do start the drag-drop action this.DoDragDrop(this, DragDropEffects.Move); } else { // Draw the outline of this object on the parent if(cursorGraphics == null) cursorGraphics = Parent.CreateGraphics(); cursorGraphics.Clear(Parent.BackColor); Point cursorPoint = Parent.PointToClient(this.PointToScreen(new Point(mouseEventArgs.X - startPoint.X, mouseEventArgs.Y - startPoint.Y))); cursorGraphics.DrawRectangle(cursorPen, cursorPoint.X, cursorPoint.Y, this.Width - 1, this.Height - 1); } }
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I can put one more possibility, however it works in completely other way: only with GDI objects, not controls, although maybe it is possible to extend this.
The problem is that drawing resizing/moving rectangles leaves their path. The idea is to save pixels which were under the rectangle (not it's interior - only bounds) and paint them when next reactangle has to be drawn.
I did it, however it needs "more ugly connections from child to parent", how you called it. This is small but most important part of the code
This one saves pixels under bound of rectangle to the array
int[][] GetData(Rectangle rect, Bitmap b) { int[][] ret = new int[4][];
int i; if (!(new Rectangle(new Point(0, 0), new Size(b.Size.Width-1, b.Size.Height-1)).Contains(rect)) || rect.Height < 0 || rect.Width < 0) return null; ret[0] = new int[rect.Width]; ret[1] = new int[rect.Height]; ret[2] = new int[rect.Width]; ret[3] = new int[rect.Height]; // NW to NE edge for (i = 0; i < rect.Width; i++) ret[0][i] = b.GetPixel(rect.X + i, rect.Y).ToArgb(); // NE to SE for (i = 0; i < rect.Height; i++) ret[1][i] = b.GetPixel(rect.X + rect.Width, rect.Y + i).ToArgb(); // SE to SW for (i = 0; i < rect.Width; i++) ret[2][i] = b.GetPixel(rect.X + rect.Width - i, rect.Y + rect.Height).ToArgb(); // SW to NW for (i = 0; i < rect.Height; i++) ret[3][i] = b.GetPixel(rect.X, rect.Y + rect.Height - i).ToArgb(); return ret; }
This one draws saved edges into bitmap:
void DrawRectangle(int[][] data, Point p, Bitmap b) { if (data == null) return; int width = GetWidth(data); int height = GetHeight(data); int i;
// NW to NE for (i = 0; i < width; i++) b.SetPixel(p.X + i, p.Y, Color.FromArgb(data[0][i])); // NE to SE for (i = 0; i < height; i++) b.SetPixel(p.X + width, p.Y + i, Color.FromArgb(data[1][i])); // SE to SW for (i = 0; i < width; i++) b.SetPixel(p.X + width - i, p.Y + height, Color.FromArgb(data[2][i])); // SW to NW for (i = 0; i < height; i++) b.SetPixel(p.X, p.Y + height - i, Color.FromArgb(data[3][i])); }
I used it when the parent was PictureBox, because calling it's Refresh redraws bitmap stored under Image property.
Maybe it is rather oriental stuff, but...
Ah! One thing about performance: Good message: No memory jumps, mem usage minimal even if an object is big. Bad message: High (100%) CPU usage - especially if an object is big. Things up to 100x100 pixels size perform rather good. CPU usage is the only hardware disadvantage - no memory problems.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for you help!
If I understand you correct the parent object needs to have a bitmap as background, and you use this bitmap to draw the outline on? If this is the case it feels a bit limited. Correct me if I'm wrong.
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yeach, it is extremely limited . Just another proposition. I am now working on sth like "DesignerPanel", which would be a container control in which all child controls implementing "IDesignObject" could be "designed". Now it works for all user-definied IDesignObjects (with custom paint procedures) and the Button. I have some problems with ListBox and I did'n tried other controls yet. If I get some result, I will inform ya. 
Greetings - gajato.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I have now changed to a better solution (I hope ) using a transparent form instead of the huge cursor. There is still some things to improve... there is some flicker when making the object smaller... And the challenge to package all this (and some more) into a nice reusable component...
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
By the way: This a code which is used by SharpDevelop (open-source IDE) to draw outline rectangle. As we can see, they reference "more directly" to Win GDI:
public static void DrawDragOutline(Region region) { if (region == null) return;
// Get hold of the DC for the desktop IntPtr hDC = User32.GetDC(IntPtr.Zero);
// Define the area we are allowed to draw into IntPtr hRegion = region.GetHrgn(Graphics.FromHdc(hDC)); Gdi32.SelectClipRgn(hDC, hRegion);
Win32.RECT rectBox = new Win32.RECT(); // Get the smallest rectangle that encloses region Gdi32.GetClipBox(hDC, ref rectBox);
IntPtr brushHandler = GetHalfToneBrush();
// Select brush into the device context IntPtr oldHandle = Gdi32.SelectObject(hDC, brushHandler);
// Blit to screen using provided pattern brush and invert with existing screen contents Gdi32.PatBlt(hDC, rectBox.left, rectBox.top, rectBox.right - rectBox.left, rectBox.bottom - rectBox.top, (uint)Win32.RasterOperations.PATINVERT);
// Put old handle back again Gdi32.SelectObject(hDC, oldHandle);
// Reset the clipping region Gdi32.SelectClipRgn(hDC, IntPtr.Zero);
Gdi32.DeleteObject(hRegion);
// Must remember to release the HDC resource! User32.ReleaseDC(IntPtr.Zero, hDC); }
They import GDI this way:
internal class Gdi32 { [DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern int CombineRgn(IntPtr dest, IntPtr src1, IntPtr src2, int flags);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern IntPtr CreateRectRgnIndirect(ref Win32.RECT rect);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern bool FillRgn(IntPtr hDC, IntPtr hrgn, IntPtr hBrush); [DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern int GetClipBox(IntPtr hDC, ref Win32.RECT rectBox);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern int SelectClipRgn(IntPtr hDC, IntPtr hRgn);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern IntPtr CreateBrushIndirect(ref LOGBRUSH brush);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern bool PatBlt(IntPtr hDC, int x, int y, int width, int height, uint flags);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern IntPtr DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern IntPtr CreateCompatibleDC(IntPtr hDC); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Nice, but not excellent.
In my opinion, creation of ultra-huge cursor at runtime just to draw rectangle around an object is not a good idea. Try to maximize the window and make the control big. Program crashes after few moving operations.
Each moving operation increases memory usage for plenty megabytes, if an object is big, then memory steps are even 20 megabytes. Mem is not freed just after object is dropped so mem usage quickly exceeds 100 megabytes. It is not a smart solution.
Maybe for small controls (e.g. toolbar items, as you mentioned), memory is freed quicker than it is allocated, but I find it dirty anyway.
Greetings - gajatko.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yes you are right! 
This is not good. The cursor part has to be redone. I just tried to add some dispose on the bitmap and cursor objects - but it did not seem to help. As a first improvement it would be nice to change the center position of my cursor - possible? (To avoid make it that big). Also, if this part is done smarter we could also use the outline cursor when resizing the object!
So, please all of you, help me improve this part!
private Graphics cursorGraphics = null; private Bitmap bitmap = null; private Cursor cursor = null; private Pen cursorPen = new Pen(Color.Black);
// Replace the default cursor when begin to move or drag this object private Cursor OutlineCursor() { if(cursor != null) cursor.Dispose(); if(cursorGraphics != null) cursorGraphics.Dispose(); if(bitmap != null) bitmap.Dispose(); bitmap = new Bitmap(this.Width * 2, this.Height * 2); cursorGraphics = Graphics.FromImage(bitmap); cursorGraphics.DrawRectangle(cursorPen, this.Width - startPoint.X, this.Height - startPoint.Y, this.Width - 1, this.Height - 1); IntPtr intPtr = bitmap.GetHicon(); cursor = new Cursor(intPtr); return cursor; }
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Very nice simplicity, cute code writing and complete documentation These cuase to i say it's realy excellent I'm working on a map designer project that has two main part, drag and drop from a toolbox and zoom control for my map,in first part i have not any problem, ofcourse reading this source help me to optimize my code, in second one i have some problems,in second part i want to zoom in my map and my added controls to map act like points of map, as needed, change location, scaling, zooming,... Have you ever work on a project like this, Or have you any idia?
Regards,
Reza Samadabadi
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks!
Do you have a picture as map in the background or does your map just consist of objects that the user drags to the form? I guess that for your user dragged object you will need to recalculate the coordinates to achieve scaling and zoom, then if you have a bitmap as background you will have to recalculate the coordinates according to the bitmap as it resizes along with the form - a bit harder maybe. Hope to find your project here when it ready!
Good luck!
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
You are right Mats I have a picture as a map in the background and in fact user drag objects on it, because of scaling and zooming of my map, i recalculate location,size,... for every object in my map, but you know that every solution is not good for every problem, i think it might be heavy or difficult for run on week computers or in a map with plenty of objects in it.
I guess it will finish on next week, and i will able to exactly test it on different PCs.
Thanks for your reply.
Reza
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Well it's up to you!
But I have used this technique in an application used to monitor/control IO:s in a robot system. The application is a toolbox with different graphical objects the user can drag to forms. One is the IO objects, one is a container box used to group other objects, and one is a note used as post-it on the form a s o. All objects can be dragged to other forms a s o. To be able to do some nice layout all this is needed… When done all objects are serialized to file and can easy be restored on next session.
So, in an application that consists of some toolbox that the user can drag to some design surface this can be useful!
Mats
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I can imagine using this for every application where great flexibility is demanded. With the starting point Mats gives to us, one might be able to include a form designer in an app.
Just imagine a CRM-Software, where users can design their own forms - with just the information they need!
Nice one, Mats!
Regards,
Mathias Wuehrmann
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|