I am trying to create a graphic in the middle of my layout, which can be restricted in a Linearlayout. Example => Print App This is my application and the graphic has to be in the white area written "Diagram".
The graphic only needs lines and bezier curves.
in fact I do not know if it has a specific object where I can draw.
with lines (x1, y1, x2, y2).
public class MyView : View
{
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
Paint green = new Paint {
AntiAlias = true,
Color = Color.Rgb(0x99, 0xcc, 0),
};
green.SetStyle(Paint.Style.FillAndStroke);
Paint red = new Paint {
AntiAlias = true,
Color = Color.Rgb(0xff, 0x44, 0x44)
};
red.SetStyle(Paint.Style.FillAndStroke);
float middle = canvas.Width * 0.25f;
canvas.DrawPaint(red);
canvas.DrawRect(0, 0, middle, canvas.Height, green);
}
}
How do I draw this in a specific place in my layout?
How do I draw this in a specific place in my layout?
After you've complete your draw view MyView, you can place it in your layout in xml for example like this:
<YOURNAMESPACE.MyView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/myview" />
In this case, it can be used like normal UI components in the layout, means you can use Margin, Gravity and such layout parameters to certain the location where it should be placed.
If you want to implement it in the code behind, you can use LayoutParams. Specific layout code depends on which parent view are you using.
Basically it means, you can draw the view use Paint in the subclass of View and place it like a UI components in your layout.
Related
My question has three parts:
I Can draw shapes like line, Circle, Rectangle and .. on WPF Canvas. I want to use InkCanvas features like erasing and moving strokes.
Is it possible to convert this shape to a collection of stylus
points and add this collection to InkCanvas?
If it's possible how can I do that?
Is there a better approach to this situation?
Guide me please.
first of all, the answer is Yes. you can convert paths to stroke collection and then add them to the InkCanvas.
For the second part of your question, the answer should be something like this:
Point mypoint;
Point tg;
var pointCollection = new List<Point>();
for (var i = 0; i < 500; i++)
{
SomePath.Data.GetFlattenedGeometryPath()
.GetPointAtFractionLength(i / 500f, out mypoint, out tg);
pointCollection.Add(p);
}
For stylus point and stylus point collection:
StylusPointCollection StPoints = new StylusPointCollection();
add stylus points during converting path to collection of points by:
StPoints.Add(new StylusPoint(p.X, P.Y));
And after this step calling Stroke method to create a collection of strokes from your stylus collection:
Stroke st = null;
st = new Stroke(StPoints);
Update
Yes! there is a better ways for adding shapes to inkCanvas.
You can define this stylus points shape directly and add them using MouseDown, MouseMove.. for example for drawing a Rectangle:
pts.Add(new StylusPoint(mouseLeftDownPoint.X, mouseLeftDownPoint.Y));
pts.Add(new StylusPoint(mouseLeftDownPoint.X, currentPoint.Y));
pts.Add(new StylusPoint(currentPoint.X, currentPoint.Y));
pts.Add(new StylusPoint(currentPoint.X, mouseLeftDownPoint.Y));
pts.Add(new StylusPoint(mouseLeftDownPoint.X, mouseLeftDownPoint.Y));
Or Override DrawCore method of Stroke Class and define a new stroke type.
Custom Rendering Ink (MSDN)
I have a subclassed parent UIView object which should add another subclassed UIView. This is the UIView I want to add and where the Draw method is not called:
public class Circle : UIView
{
private UIColor color;
public Circle ()
{
this.color = UIColor.Black;
this.BackgroundColor = UIColor.Clear;
}
public Circle (UIColor color)
{
this.color = color;
this.BackgroundColor = UIColor.Clear;
}
public override void Draw (CGRect rect)
{
base.Draw (rect);
// Get the context
CGContext context = UIGraphics.GetCurrentContext ();
context.AddEllipseInRect (rect);
context.SetFillColor (color.CGColor);
context.FillPath ();
}
}
This is how I'm adding the circle:
Circle circle = new Circle (UIColor.Red);
circle.TranslatesAutoresizingMaskIntoConstraints = false;
AddSubview (circle);
AddConstraint(NSLayoutConstraint.Create(circle, NSLayoutAttribute.Left, NSLayoutRelation.Equal, line, NSLayoutAttribute.Left, 1, 10));
AddConstraint(NSLayoutConstraint.Create(circle, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, line, NSLayoutAttribute.CenterY, 1, 0));
AddConstraint(NSLayoutConstraint.Create(circle, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, 6));
AddConstraint(NSLayoutConstraint.Create(circle, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, 6));
This code above is again in the Draw method of the parent. The objects in the parent are drawn fine except the circle and even if I use the below code as circle it is shown correctly. So the constraints are ok.
UIView circle = new UIView() { BackgroundColor = UIColor.Red };
What I'm doing wrong? Can't I override both Draw methods (in the subclassed parent and in the subclassed circle)?
PS: I have to mention that the circle should overlaps a line. But the Draw is never called so it seems that it doesn't get a frame.
Are you aware that you are instantiating an UIView and not a Circle in this code snipped ?
UIView circle = new UIView() { BackgroundColor = UIColor.Red };
Also you shouldn't add subview in the draw method, because it will be called multiple time, in fact you should only override the Draw method with you are doing a custom draw (it´s the case of the Circle view, but not the case of the parent view).
From apple documentations:
View drawing occurs on an as-needed basis. When a view is first shown,
or when all or part of it becomes visible due to layout changes, the
system asks the view to draw its contents. For views that contain
custom content using UIKit or Core Graphics, the system calls the
view’s drawRect: method
So can you post the code snipe where you actually add the parent view? And the code of the parent view, you might have override a method and are not calling the base class method (like setNeedsDisplay or something similar) OR you are not adding the view.
If you take a look at the attached image, is there a way to get the drawing logic for this hover effect from the system renderer of the standard WinForms toolstrip ?
http://imageshack.us/photo/my-images/10/toolstriphovereffect.jpg/
EDIT: Anyway, I've manually implemented this with images, but if anyone comes here with a solution, please post.
Maybe this code helps. It draws red circle with black border around toolstripbutton when mouse is over it.
Set your toolstrip properties:
//Set render mode to professional
myToolStrip.RenderMode = ToolStripRenderMode.Professional;
//Assign new instance of your custom renderer
myToolStrip.Renderer = new MyCustomRenderer();
Custom renderer class:
public class MyCustomRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
{
if (!e.Item.Selected)
base.OnRenderButtonBackground(e);
else
{
Rectangle rectangle = new Rectangle(0, 0, e.Item.Size.Width - 1, e.Item.Size.Height - 1);
//Draw red circle
e.Graphics.FillEllipse(Brushes.Red, rectangle);
//Draw black border
e.Graphics.DrawEllipse(Pens.Black, rectangle);
}
}
}
C#3.0,.net framework 3.5
I am drawing ( using the draw method in the graphics class) a lot of solid rectangles on a windows form vertically. The form starts at 500 x 500 px and the rectangles are only drawn at runtime after data is downloaded from the net -and the number of rectangles depends on the download so I do not know it upfront.
So only a few rectangles are drawn as the size of the form is fixed.
So I googled/Binged ( lest someone suggest I do that) and found a few tips but they don't work in this case -like setting the forms AutoScroll property to true or trying double buffering.I also tried to draw on a listbox control and set it's scroll property etc...but no dice.
I'm guessing there is no way to display , say 200 rectangles vertically on a windows form using draw. I need some other solution... any ideas please.
Maybe a list of pictureboxes and then populate each picturebox with the solid color ?
Thanks
You are drawing GDI+ rectangles on a form during the paint event? The form would have no idea that you are creating objects outside of the clipping space and would therefore have no idea that you need to scroll.
You would need to add a scrollbar to the form and then calculate the value\position of the scrollbar and use that to determine what portion of your rectangles to draw upon the paint event. This would involve a bit of manual effort. You could draw them all to an in-memory bitmap of the appropriate size and then just copy the portions of that to the form upon draw.
Or:
If you wanted the form to do this for you, create a custom rectangle control and place 200 of those on the form. Since they are components and have a concrete height & width, the form would then know it needed to scroll, and would do so accordingly provided that autoscroll was set.
it can be as simple as this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.AutoScroll = true;
for (int i = 0; i < 100; i++)
this.Controls.Add(new Rectangle() { Top = i * 120, Left = 10 });
}
}
public class Rectangle : Control
{
public Rectangle()
{
this.Width = 100;
this.Height = 100;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawRectangle(new Pen(Color.Black, 5), 0, 0, 100, 100);
}
}
Can I delete the old rectangle which I have drawn and draw a new rectangle?
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
Graphics g = this.panel1.CreateGraphics();
Pen pen = new Pen(Color.Black, 2);
g.DrawRectangle(pen, 100,100, 100, 200);
g.dispose();
}
No, you cannot "delete" something that's already been drawn. You can overwrite it with something else, but drawing with Graphics objects is like painting in real-life: once the paint is dry, you can only paint over it with another colour, you can't "erase" it.
You probably shouldn't be drawing things in response to a MouseClick, either. It's best to only draw things in response to a Paint event. What I would do in this situation is add a Rectangle structure to a list on the MouseClick and then call panel1.Invalidate() to ask it to redraw itself. Then in the Paint event for the panel, do the drawing there.
This will kill two birds with one stone, because you will be able to "erase" thing by simply removing them from the list of stuff to draw.
This is usually done by maintaining a collection of objects you want drawn. The mouse click should update this collection and then tell the window (or the affect region) to refresh. This has the enormous advantage of preserving whatever you've drawn if the window is moved off-screen, hidden behind other windows, minimized, etc.
For a rudimentary solution, create a hierarchy of drawable shape types derived from a common abstract Shape class, and use, e.g., a List for the collection. The base Shape class will have an abstract Draw method that the derived classes override.
For a more industrial-strength solution, look around for 2-D scene graphs.
One can use Graphics.Save() and Graphics.Restore(state) methods for that. For example:
private void SaveRestore2(PaintEventArgs e)
{
// Translate transformation matrix.
e.Graphics.TranslateTransform(100, 0);
// Save translated graphics state.
GraphicsState transState = e.Graphics.Save();
// Reset transformation matrix to identity and fill rectangle.
e.Graphics.ResetTransform();
e.Graphics.FillRectangle(new SolidBrush(Color.Red), 0, 0, 100, 100);
// Restore graphics state to translated state and fill second
// rectangle.
e.Graphics.Restore(transState);
e.Graphics.FillRectangle(new SolidBrush(Color.Blue), 0, 0, 100, 100);
}
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.restore.aspx
Also, depending on the application, you might look at using DrawReversibleFrame. You can change the rectangle location by calling the Offset method.
Instead of calling g.DrawRectangle(pen, 100,100, 100, 200); , maintain the rectangle as a object which will be drawn by the graphics object. Each time you will update this rectangle object with new one and graphics object will draw the new one.
The refresh should clear the old rectangle and graphics will draw the new one.
You can just use VisualBasic PowerPacks, it is included with my version of Visual Studio 2008
Here's a sample code that will draw a rectangle over a TextBox, i.e. I am giving it a custom border
Dim x = TextBox1.Location.X
Dim y = TextBox1.Location.Y
Dim width = TextBox1.Width
Dim height = TextBox1.Height
Dim ShapeContainer1 As New Microsoft.VisualBasic.PowerPacks.ShapeContainer
Me.Controls.Add(ShapeContainer1)
Dim RectangleShape1 As New Microsoft.VisualBasic.PowerPacks.RectangleShape
ShapeContainer1.Shapes.AddRange(New Microsoft.VisualBasic.PowerPacks.Shape() {RectangleShape1})
RectangleShape1.Location = New System.Drawing.Point(x - 1, y - 1)
RectangleShape1.Size = New System.Drawing.Size(width + 1, height + 1)
RectangleShape1.BorderColor = Color.MistyRose
ShapeContainer1.Refresh()
Code is self describing but if you'd have any problem, just leave a message...
I think using DrawReversibleFrame is the right solution.
The first call draw the rectangle, the second call undraw it and so on.
Here is a sample code, a clic on the button will make the rectangle appear/disapper.
Rectangle pRect = new Rectangle(10, 10, 20, 20);
private void rect_Click(object sender, EventArgs e)
{
ControlPaint.DrawReversibleFrame(pRect, this.BackColor, FrameStyle.Thick);
}