Recognizing texts as URLs in Winforms - c#

I am rendering some text in GUI and trying to recoganize the URLs. Also I need to open the URLs in browser when click events are performed. I have attached the model code snippent below. My question is how to make these texts a valid URLs and how to make them to respond to click events. And one more thing this due to some requirements I cant change the structure of the below code snnipet.
namespace Model
{
public partial class ParentView : Form
{
public ParentView()
{
InitializeComponent();
}
private void ParentView_Paint(object sender, PaintEventArgs e)
{
GraphicsState state = e.Graphics.Save();
GraphicsRenderer renderer = new GraphicsRenderer(e.Graphics);
renderer.RenderAsImage();
e.Graphics.Restore(state);
e.Graphics.DrawRectangle(new Pen(Brushes.Black), 0, 0, 300, 300);
//I believe need to do something here
}
}
public class GraphicsRenderer
{
Graphics PageGraphics;
public GraphicsRenderer(Graphics g)
{
PageGraphics = g;
}
public void RenderAsImage()
{
Point currentLocation = new Point(0, 0);
PageGraphics.TranslateTransform(20, 40);
PageGraphics.DrawString("www.google.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
PageGraphics.TranslateTransform(20, -40);
PageGraphics.DrawString("www.stackoverflow.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
currentLocation = new Point(50, 60);
PageGraphics.DrawString("www.stackoverflow.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
}
}
}
Thanks,
Mkn

If you're just writing text to the screen as graphics you can't make it clickable. You'll need to position a LinkLabel or other clickable control at the right position to trigger the url opening in a browser.

Thanks for your response. I have analyzed further and found a way. Drawing rectangles over the text and finding the rectangles in mouse click events using Rectangle. Contains(MouseLeftClikLocation).
Now I am having another problem. If scale transformation is performed I could not able to get the location after restoring the graphics.
Please find the code snnipet below.
private void ParentView_Paint(object sender, PaintEventArgs e)
{
GraphicsState state = e.Graphics.Save();
GraphicsRenderer renderer = new GraphicsRenderer(e.Graphics);
renderer.RenderAsImage();
e.Graphics.Restore(state);
e.Graphics.DrawRectangle(new Pen(Brushes.Black), 0, 0, 300, 300);
//I am changing here
float[] transformPoints = renderer.transformPoints.Elements;
e.Graphics.TranslateTransform(transformPoints[4], transformPoints[5]);
Point currentLocation = renderer.currentLocation;
e.Graphics.DrawRectangle(new Pen(Brushes.Black),new Rectangle(currentLocation.X,currentLocation.Y,190,30));
}
public class GraphicsRenderer
{
Graphics PageGraphics;
internal Matrix transformPoints = new Matrix();
internal Point currentLocation = new Point(0, 0);
public GraphicsRenderer(Graphics g)
{
PageGraphics = g;
}
public void RenderAsImage()
{
currentLocation = new Point(50, 60);
//PageGraphics.ScaleTransform(3, 3);
PageGraphics.DrawString("www.bing.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
transformPoints = PageGraphics.Transform;
}
}

Related

Creating another Graphics with different coordinates?

Is it possible to create another Graphics form an existing Graphics with a different coordinate system? For example, let's say that the black rectangle is the ClipRectangle of the Graphics object I got in OnPaint(). If I only want to draw inside the blue rectangle, I would have to constantly calculate the offset. That is, to draw at the logical point (0,0) in the blue rectangle, I would have to add the x and y offsets. That makes drawing code complicated.
Is there a way to create some sort of virtual Graphics using the Graphics above but with a different coordinate system? Something like below
//not actual code
var virtualG = Graphics.FromExistingGraphics(e.Graphics, 200/*x1*/, 200/*y1*/, 1000/*x2*/, 600/*y2*/);
//Doing the same thing as e.Graphics.DrawLine(pen, 200, 200, 400, 400)
virtualG.DrawLine(pen, 0, 0, 200, 200);
//Draws nothing, NOT the same as e.Graphics.DrawLine(pen, 1100, 200, 1200, 400)
//, because its outside of the virtualG's bounds.
virtualG.DrawLine(pen, 900, 0, 1000, 200);
I thought about creating a new Graphics using bitmap, draw there and then copy the bitmap to the specified location of the Graphics from OnPaint, but that could be slow.
If you don't want any scaling, and simply want to move the origin to (200, 200), then use TranslateTransform as suggested previously. If you want to clip any drawings outside that rectangle, then use SetClip.
Here's an example, showing the same set of lines drawn before and after translating and clipping. The black lines are before, while the blue line is after (the second blue line is clipped and therefore not visible). The red rectangle shows the clipping region:
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class Line
{
public Point ptA;
public Point ptB;
public void Draw(Graphics G, Color color)
{
using (Pen P = new Pen(color))
{
G.DrawLine(P, ptA, ptB);
}
}
}
private List<Line> Lines = new List<Line>();
private void Form1_Load(object sender, EventArgs e)
{
Lines.Add(new Line() { ptA = new Point(0,0), ptB = new Point(200, 200)});
Lines.Add(new Line() { ptA = new Point(900, 0), ptB = new Point(1000, 200) });
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics G = e.Graphics;
G.Clear(Color.DarkGray);
foreach(Line line in Lines)
{
line.Draw(G, Color.Black);
}
Rectangle rc = new Rectangle(new Point(200, 200), new Size(800, 400));
G.DrawRectangle(Pens.Red, rc);
G.SetClip(rc);
G.TranslateTransform(rc.Left, rc.Top); // origin is now at (200, 200)
foreach (Line line in Lines)
{
line.Draw(G, Color.Blue);
}
}
}

Is it possible to use NGraphics to draw geometric shapes on .net Forms?

I am trying to draw some geometric shapes using NGraphics in a picture box on a WinForm:
public partial class DrawingForm : Form
{
public DrawingForm()
{
InitializeComponent();
}
private void DrawingForm_Load(object sender, EventArgs e)
{
var canvas = Platforms.Current.CreateImageCanvas(new NGraphics.Size(100), scale: 2);
var skyBrush = new LinearGradientBrush(NGraphics.Point.Zero, NGraphics.Point.OneY, Colors.Blue, Colors.White);
canvas.FillRectangle(new Rect(canvas.Size), skyBrush);
canvas.FillEllipse(10, 10, 30, 30, Colors.Yellow);
canvas.FillRectangle(50, 60, 60, 40, Colors.LightGray);
canvas.FillPath(new PathOp[] { new MoveTo (40, 60),
new LineTo (120, 60),
new LineTo (80, 30),
new ClosePath ()
}, Colors.Gray);
this.pictureBox1.Image = (Image)canvas.GetImage();
}
}
This source code is giving the following exception:
Additional information: Unable to cast object of type 'NGraphics.ImageImage' to type 'System.Drawing.Image'.
This is one problem. Another question is: is it possible to draw shapes directly on the Forms?
Take a look at the source code for the NGraphics package, it looks like you should construct the GraphicsCanvas based on a standard Graphics context that you could obtain from the form.
https://github.com/praeclarum/NGraphics/blob/master/Platforms/NGraphics.Net/SystemDrawingPlatform.cs#L152
Something like this perhaps
var canvas = new GraphicsCanvas(this.CreateGraphics());
The other thing you need to do is use the Paint event
private void Form1_Paint(object sender, PaintEventArgs e)
{
var graphics = this.CreateGraphics();
var canvas = new GraphicsCanvas(graphics);
var skyBrush = new LinearGradientBrush(NGraphics.Point.Zero,
NGraphics.Point.OneY, Colors.Blue, Colors.White);
canvas.FillRectangle(new Rect(0, 0, 100, 100), skyBrush);
canvas.FillEllipse(10, 10, 30, 30, Colors.Yellow);
canvas.FillRectangle(50, 60, 60, 40, Colors.LightGray);
canvas.FillPath(new PathOp[] { new MoveTo (40, 60),
new LineTo (120, 60),
new LineTo (80, 30),
new ClosePath ()
}, Colors.Gray);
}

How to draw graph in c#

I'm new ,and I don't understand why this method when copied to windows forms doesn't do anything when running the program. I was copy it from MSDN page.
public void DrawLinesPoint(PaintEventArgs e)
{
// Create pen.
Pen pen = new Pen(Color.Black, 3);
// Create array of points that define lines to draw.
Point[] points =
{
new Point(10, 10),
new Point(10, 100),
new Point(200, 50),
new Point(250, 300)
};
//Draw lines to screen.
e.Graphics.DrawLines(pen, points);
}
Typically, when you draw on a form, you handle the form’s Paint event and perform the drawing using the Graphics property of the PaintEventArgs
In your code you need to add the DrawLinesPoint to the paint event before being able to use it
In your Constructor() add
InitializeComponent();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.DrawLinesPoint);
And in your Paint PaintEventHandler
private void DrawLinesPoint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Black, 3);
// Create array of points that define lines to draw.
Point[] points =
{
new Point(10, 10),
new Point(10, 100),
new Point(200, 50),
new Point(250, 300)
};
//Draw lines to screen.
e.Graphics.DrawLines(pen, points);
}

How do I repaint my picturebox when the picture disappears?

I don't know how to repaint my picturebox. This is just a demonstration. The production code is too time consuming to put in the paint event. What I need is a way to capture the image that is drawn in the pucturebox with the graphics methods so I can quickly repaint it when needed.
Here's a demo:
public partial class Form1 : Form
{
Image Outout;
public Form1()
{
InitializeComponent();
button1.Click += Button1_Click;
}
private void Button1_Click(Object sender, EventArgs e)
{
PrintPageEventArgs eOutput;
Graphics g;
string OutputText;
Font PrintFont;
OutputText = "CERTIFICATION";
PrintFont = new Font("Arial", 16, FontStyle.Bold);
g = pictureBox1.CreateGraphics();
eOutput = new PrintPageEventArgs(g, new Rectangle(new Point(25, 25), new Size(new Point(825, 1075))), new Rectangle(new Point(0, 0), new Size(new Point(850, 1100))), new PageSettings());
eOutput.Graphics.DrawString(OutputText, PrintFont, Brushes.Black, 0, 0);
Outout = pictureBox1.Image;
pictureBox1.Paint += PictureBox1_Paint;
}
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
pictureBox1.Image = Outout;
}
}
Thanks TaW for pointing me in the right direction. The example I posted is from an ERP system and the actual problem uses over a dozen objects plus the graphics is from a multipage report. So drawing in the paint event will not work. For starters, keeping a list of things to draw is pointless, since EVERYTHING needs to be drawn when the part number changes. Also the report generator needs to run twice, the first time just to calculate the number of pages and the second time to actually draw the pages. Also I cant use the PrintPreview of the PrintDocument because of its limitations. But you were spot on about using Graphics g = Graphics.FromImage(bmp). That's what I needed.
#LarsTech, you are correct, that is a weird use of the PrintPageEventArgs. That is merely a side effect when an issue embedded in a couple of events and several objects needs to be reduced in form to present a representation of a problem. If its reduced too small, the proposed solutions do not scale, therefore, do not work. If it is not reduced enough, it can be difficult to understand the actual problem, as people will present solutions to different aspects, some of which are artificial due to the reduction of the issue.
ANSWER
Drawing on the graphics created by the picturebox was not persistent. Drawing on a bitmap, however, worked perfectly as suggested by TaW. Thank you for your assistance!
PrintPageEventArgs eOutput;
Graphics g;
string OutputText;
Font PrintFont;
Bitmap Output;
OutputText = "CERTIFICATION";
PrintFont = new Font("Times New Roman", 24, FontStyle.Regular);
Output = new Bitmap(850, 1100);
g = Graphics.FromImage(Output);
eOutput = new PrintPageEventArgs(g, new Rectangle(new Point(25, 25), new Size(new Point(825, 1075))), new Rectangle(new Point(0, 0), new Size(new Point(850, 1100))), new PageSettings());
eOutput.Graphics.DrawString(OutputText, PrintFont, Brushes.Black, 0, 0);
pictureBox1.Image = Output;

C# Non-rectangular pictureboxes

Is there a way to create non-rectangular pictureBoxes. I have round shapes that should overlap and if possible should be in different pictureboxes..
I tried the this here, but you could not see both pictureboxes that are overlapping at a time, but just one..
Here the picture that resulted from my tests:
You can make the PictureBoxes circular by adding an Ellipse to a GraphicsPath and then building a new Region from it.
Here's a quick example:
public class Target : PictureBox
{
public Target()
{
this.Size = new Size(100, 100);
this.Paint += Target_Paint;
Rectangle rc = this.ClientRectangle;
rc.Inflate(-10, -10);
System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
gp.AddEllipse(rc);
this.Region = new Region(gp);
}
void Target_Paint(object sender, PaintEventArgs e)
{
Rectangle rc = this.ClientRectangle;
rc.Inflate(-10, -10);
using (Pen pen = new Pen(Color.Blue, 5))
{
e.Graphics.DrawEllipse(pen, rc);
}
rc = new Rectangle(new Point(this.Size.Width / 2, this.Size.Height / 2), new Size(1, 1));
rc.Inflate(9, 9);
e.Graphics.FillEllipse(Brushes.Red, rc);
}
}
After compiling, the new control appears at the top of your ToolBox.
Here's a screenshot with three of them overlapping each other:

Categories