So I made a game for a school project in windows forms. Only problem is, is that my pictures are overlapping with each other. So my question how do I get them all on a different location where they don't touch each other or not overlap?
In this Method I create the zombies and here I just choose for random locations between -100 and 0 on the x-as
public void ZombieMaker(int aantal, Form formInstance, string ZombieDik)
{
for (int i = 0; i < aantal; i++)
{
PictureBox picture = new PictureBox();
picture.Image = Properties.Resources.ZombieDik;
picture.Size = new Size(200, 200);
picture.Location = new Point(random.Next(1500), random.Next(-100,0));
picture.SizeMode = PictureBoxSizeMode.Zoom;
picture.Click += zombie_Click;
picture.BackColor = Color.Transparent;
formInstance.Controls.Add(picture);
picture.Tag = zombies[i];
}
}
pic of zombies overlapping
Keep track of the already placed pictureboxes, and validate if the bound would overlap.
//List of all pictureBoxes
private List<PictureBox> _pictureBoxes = new List<PictureBox>();
public void ZombieMaker(int aantal, Form formInstance, string ZombieDik)
{
for (int i = 0; i < aantal; i++)
{
Rectangle newPosition;
//loop till you found a new position
while (true)
{
var newPoint = new Point(random.Next(1500), random.Next(-100,0));
var newSize = new Size(200, 200);
newPosition = new Rectangle(newPoint, newSize);
//validate the newPosition
if (!_pictureBoxes.Any(x => x.Bounds.IntersectsWith(newPosition)))
{
//break the loop when there isn't an overlapping rectangle found
break;
}
}
PictureBox picture = new PictureBox();
_pictureBoxes.Add(picture);
picture.Image = Properties.Resources.ZombieDik;
picture.Size = newPosition.Size;
picture.Location = newPosition.Location;
...
}
}
To validate the overlapping I am using the IntersectWith method of the Rectangle class
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.rectangle.intersectswith?view=net-6.0#system-drawing-rectangle-intersectswith(system-drawing-rectangle)
Edit:
Here a do/while loop instead of the while loop.
Rectangle newPosition;
do
{
var newPoint = new Point(random.Next(1500), random.Next(-100,0));
var newSize = new Size(200, 200);
newPosition = new Rectangle(newPoint, newSize);
} while(_pictureBoxes.Any(x => x.Bounds.IntersectsWith(newPosition))
I fixed your code so the picture boxes do not overlap each other:
public void ZombieMaker(int aantal, Form formInstance, string ZombieDik)
{
for (int i = 0; i < aantal; i++)
{
PictureBox picture = new PictureBox();
picture.Image = Properties.Resources.ZombieDik;
picture.Size = new Size(200, 200);
picture.Location = new Point(picture.Width * i, random.Next(-100,0));
picture.SizeMode = PictureBoxSizeMode.Zoom;
picture.Click += zombie_Click;
picture.BackColor = Color.Transparent;
formInstance.Controls.Add(picture);
picture.Tag = zombies[i];
}
}
Related
Let's write a C# program of type "Windows Forms Application" to create a
application simulating the modulation and amplitude demodulation of signal transmission
Analog.
The carrier signal, the modulator signal, the modulated signal will be graphically displayed/
demodulated and the function of spectral density of signals.
I tried to color the picture boxes and they are displayed, but not their content.
My goal is to draw the 4 lines which I want to display in the 4 Picture boxes.
How can I modify this code to get the spec waveformsifice modulation and demodulation in amplitude of an analog signal?
My code:
using System;
using System.Windows.Forms;
using System.Drawing;
using static System.Math;
static class Program
{
[STAThread]
public static void Main()
{
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(new ModulationDemodulationExample());
Application.EnableVisualStyles();
}
}
public class ModulationDemodulationExample : Form
{
// Declare controls and variables
private const int SignalLength = 100;
private PictureBox carrierSignalBox = new PictureBox();
private PictureBox modulatorSignalBox = new PictureBox();
private PictureBox modulatedSignalBox = new PictureBox();
private PictureBox demodulatedSignalBox = new PictureBox();
private double[] carrierSignal = new double[SignalLength];
private double[] modulatorSignal = new double[SignalLength];
private double[] modulatedSignal = new double[SignalLength];
private double[] demodulatedSignal = new double[SignalLength];
private double carrierFrequency = 2.0;
private Bitmap carrierSignalBmp;
private Bitmap modulatorSignalBmp;
private Bitmap modulatedSignalBmp;
private Bitmap demodulatedSignalBmp;
public ModulationDemodulationExample()
{
InitializeComponent();
}
private void InitializeComponent()
{
// Initialize form and controls
Text = "Modulation and Demodulation Simulator";
Size = new Size(800, 600);
PictureBox carrierSignalBox = new PictureBox()
{
Location = new Point(10, 10),
Size = new Size(360, 180),
Visible = true,
Name = "Carrier Signal"
};
PictureBox modulatorSignalBox = new PictureBox()
{
Location = new Point(10, 200),
Size = new Size(360, 180),
Visible = true,
Name = "Modulator Signal"
};
PictureBox modulatedSignalBox = new PictureBox()
{
Location = new Point(400, 10),
Size = new Size(360, 180),
Visible = true,
Name = "Modulated Signal"
};
PictureBox demodulatedSignalBox = new PictureBox()
{
Location = new Point(400, 200),
Size = new Size(360, 180),
Visible = true,
Name = "Demodulated Signal"
};
Controls.Add(carrierSignalBox);
Controls.Add(modulatorSignalBox);
Controls.Add(modulatedSignalBox);
Controls.Add(demodulatedSignalBox);
GenerateSignal();
CreateBitmaps();
DrawSignals();
}
private void GenerateSignal()
{
for (int i = 0; i < SignalLength; i++)
{
carrierSignal[i] = Math.Sin(2 * Math.PI * carrierFrequency * i);
modulatorSignal[i] = Math.Sin(2 * Math.PI * i);
modulatedSignal[i] = carrierSignal[i] * modulatorSignal[i];
demodulatedSignal[i] = modulatedSignal[i] * carrierSignal[i];
}
}
private void CreateBitmaps()
{
carrierSignalBmp = new Bitmap(carrierSignalBox.Width, carrierSignalBox.Height);
modulatorSignalBmp = new Bitmap(modulatorSignalBox.Width, modulatorSignalBox.Height);
modulatedSignalBmp = new Bitmap(modulatedSignalBox.Width, modulatedSignalBox.Height);
demodulatedSignalBmp = new Bitmap(demodulatedSignalBox.Width, demodulatedSignalBox.Height);
//carrierSignalBox.Image = carrierSignalBmp;
carrierSignalBox.DrawToBitmap(carrierSignalBmp, carrierSignalBox.ClientRectangle);
modulatorSignalBox.Image = modulatorSignalBmp;
modulatedSignalBox.Image = modulatedSignalBmp;
demodulatedSignalBox.Image = demodulatedSignalBmp;
}
private void DrawSignals()
{
DrawSignal(carrierSignalBox, carrierSignal, Color.Blue);
DrawSignal(modulatorSignalBox, modulatorSignal, Color.Red);
DrawSignal(modulatedSignalBox, modulatedSignal, Color.Green);
DrawSignal(demodulatedSignalBox, demodulatedSignal, Color.Black);
}
void DrawSignal(PictureBox pictureBox, double[] signal, Color color)
{
// Get the graphics object for the PictureBox
var graphics = pictureBox.CreateGraphics();
// Clear the PictureBox
graphics.Clear(Color.White);
// Set the pen color
var pen = new Pen(color);
// Scale the signal's values to the size of the PictureBox
var yScale = (double)pictureBox.Height / 2.0;
var xScale = (double)pictureBox.Width / (double)signal.Length;
// Draw the signal
for (int i = 0; i < signal.Length - 1; i++)
{
var x1 = (int)(i * xScale);
var y1 = (int)(yScale + (signal[i] * yScale));
var x2 = (int)((i + 1) * xScale);
var y2 = (int)(yScale + (signal[i + 1] * yScale));
graphics.DrawLine(pen, x1, y1, x2, y2);
}
}
}
I created the 4 signals but I can not display them in form ,I would have liked each signal to be displayed in the PictureBox.
You can change your program with an override Paint method for each PictureBox like this
public partial class ModulationDemodulationExample : Form
{
// Declare controls and variables
private const int SignalLength = 100;
private PictureBox carrierSignalBox = new PictureBox();
private PictureBox modulatorSignalBox = new PictureBox();
private PictureBox modulatedSignalBox = new PictureBox();
private PictureBox demodulatedSignalBox = new PictureBox();
private double[] carrierSignal = new double[SignalLength];
private double[] modulatorSignal = new double[SignalLength];
private double[] modulatedSignal = new double[SignalLength];
private double[] demodulatedSignal = new double[SignalLength];
private double carrierFrequency = 2.0;
public ModulationDemodulationExample()
{
InitializeComponent();
// Initialize form and controls
Text = "Modulation and Demodulation Simulator";
Size = new Size(800, 600);
PictureBox carrierSignalBox = new PictureBox()
{
Location = new Point(10, 10),
Size = new Size(360, 180),
Visible = true,
Name = "Carrier Signal"
};
carrierSignalBox.Paint += new PaintEventHandler(carrierSignalBox_Paint);
PictureBox modulatorSignalBox = new PictureBox()
{
Location = new Point(10, 200),
Size = new Size(360, 180),
Visible = true,
Name = "Modulator Signal"
};
modulatorSignalBox.Paint += new PaintEventHandler(modulatorSignalBox_Paint);
PictureBox modulatedSignalBox = new PictureBox()
{
Location = new Point(400, 10),
Size = new Size(360, 180),
Visible = true,
Name = "Modulated Signal"
};
modulatedSignalBox.Paint += new PaintEventHandler(modulatedSignalBox_Paint);
PictureBox demodulatedSignalBox = new PictureBox()
{
Location = new Point(400, 200),
Size = new Size(360, 180),
Visible = true,
Name = "Demodulated Signal"
};
demodulatedSignalBox.Paint += new PaintEventHandler(demodulatedSignalBox_Paint);
Controls.Add(carrierSignalBox);
Controls.Add(modulatorSignalBox);
Controls.Add(modulatedSignalBox);
Controls.Add(demodulatedSignalBox);
GenerateSignal();
}
private void GenerateSignal()
{
for (int i = 0; i < SignalLength; i++)
{
carrierSignal[i] = Math.Sin(2 * Math.PI * carrierFrequency * i);
modulatorSignal[i] = Math.Sin(2 * Math.PI * i);
modulatedSignal[i] = carrierSignal[i] * modulatorSignal[i];
demodulatedSignal[i] = modulatedSignal[i] * carrierSignal[i];
}
}
private void carrierSignalBox_Paint(object? sender, PaintEventArgs e)
{
DrawSignal(e.Graphics, carrierSignalBox, carrierSignal, Color.Blue);
}
private void modulatorSignalBox_Paint(object? sender, PaintEventArgs e)
{
DrawSignal(e.Graphics, modulatorSignalBox, modulatorSignal, Color.Red);
}
private void modulatedSignalBox_Paint(object? sender, PaintEventArgs e)
{
DrawSignal(e.Graphics, modulatedSignalBox, modulatedSignal, Color.Green);
}
private void demodulatedSignalBox_Paint(object? sender, PaintEventArgs e)
{
DrawSignal(e.Graphics, demodulatedSignalBox, demodulatedSignal, Color.Black);
}
void DrawSignal(Graphics graphics, PictureBox pictureBox, double[] signal, Color color)
{
// Get the graphics object for the PictureBox
//var graphics = pictureBox.CreateGraphics();
// Clear the PictureBox
graphics.Clear(Color.White);
// Set the pen color
var pen = new Pen(color);
// Scale the signal's values to the size of the PictureBox
var yScale = (double)pictureBox.Height / 2.0;
var xScale = (double)pictureBox.Width / (double)signal.Length;
// Draw the signal
for (int i = 0; i < signal.Length - 1; i++)
{
var x1 = (int)(i * xScale);
var y1 = (int)(yScale + (signal[i] * yScale));
var x2 = (int)((i + 1) * xScale);
var y2 = (int)(yScale + (signal[i + 1] * yScale));
graphics.DrawLine(pen, x1, y1, x2, y2);
}
}
}
When you want to redraw the PictureBox, just call the Invalidate method and the Paint event is automatically called. Example:
carrierSignalBox.Invalidate()
I ran into a problem when trying to change the size of all PictureBoxes in a project.
The PictureBoxes have been created like this:
for (int x = 0; x < 2; x++)
{
string filePath = fileEntries[i];
string fileName = Path.GetFileName(filePath);
int index = Array.IndexOf(fileEntries, filePath);
PictureBox image = new PictureBox();
image.Text = filePath;
image.Top = (int)y * 185 + 8 + 185;
image.Left = (int)x * 325 + 9;
image.Name = "picbox";
image.Click += picbox_Click;
image.Image = Image.FromFile(filePath);
image.BackColor = Color.FromArgb(0, 0, 110);
image.Height = 181;
image.Width = 318;
image.Padding = new Padding(2);
image.Name = "picbox";
this.Controls.Add(image);
}
Then, when clicking a box, I want to change the height, width, padding and Name of all PictureBoxes on the Form. Currently, I am using the following code:
picbox.BackColor = Color.FromArgb(0, 0, 110);
picbox.Height = 177;
picbox.Width = 314;
picbox.Padding = new Padding(0);
picbox.Name = "picboxnew";
This is not working, does anyone know how I can make this work?
Kind regards,
you can do it using Linq:
var pictureboxes = this.Controls.OfType<PictureBox>().ToList();
foreach (PictureBox pb in pictureboxes)
{
pb.Height = 500;
pb.Name = "some_name";
//etc
}
I have a robot that outputs x,y,z position in space. My problem is that I can only find 2D plot in windows forms using chart.
I want to plot my robot in 3D space. Any tools I can use??
Something similar to this:
I need a free software solution for this
EDIT:
My 2D graph atm:
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = 12;
chart1.ChartAreas[0].AxisX.Interval = 1;
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = 7;
chart1.ChartAreas[0].AxisY.Interval = 1;
//example
posicao_atual_master.X = 10;
posicao_atual_master.Y = 5;
chart1.Series[0].Points.Clear();
chart1.Series[0].Points.AddXY(posicao_atual_master.X, posicao_atual_master.Y);
DESIGNER:
// chart1
//
chartArea1.AxisX.MajorGrid.Enabled = false;
chartArea1.AxisX.MajorTickMark.Enabled = false;
chartArea1.AxisY.MajorGrid.Enabled = false;
chartArea1.AxisY.MajorTickMark.Enabled = false;
chartArea1.Name = "ChartArea1";
chartArea1.Position.Auto = false;
chartArea1.Position.Height = 100F;
chartArea1.Position.Width = 90F;
this.chart1.ChartAreas.Add(chartArea1);
legend1.BackColor = System.Drawing.Color.Transparent;
legend1.BorderColor = System.Drawing.Color.Transparent;
legend1.Font = new System.Drawing.Font("Microsoft Sans Serif", 4F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Millimeter, ((byte)(1)), true);
legend1.IsTextAutoFit = false;
legend1.Name = "legen";
legend1.TableStyle = System.Windows.Forms.DataVisualization.Charting.LegendTableStyle.Tall;
this.chart1.Legends.Add(legend1);
this.chart1.Location = new System.Drawing.Point(543, 49);
this.chart1.Name = "chart1";
series1.ChartArea = "ChartArea1";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
series1.Color = System.Drawing.Color.Transparent;
series1.Legend = "legen";
series1.MarkerBorderColor = System.Drawing.Color.Black;
series1.MarkerImage = "C:\\Users\\Tiago\\Desktop\\CODIGO_TESE_FINAL_BACKUP1408_BOM\\C# - AR.Drone SDK\\AR.Dron" +
"e\\icone_drone_verde.png";
series1.MarkerImageTransparentColor = System.Drawing.Color.Red;
series1.Name = "Master";
series2.ChartArea = "ChartArea1";
series2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
series2.Legend = "legen";
series2.MarkerImage = "C:\\Users\\Tiago\\Desktop\\CODIGO_TESE_FINAL_BACKUP1408_BOM\\Fotos dos Relatórios\\icon" +
"e_drone_vermelho.png";
series2.Name = "Slave";
this.chart1.Series.Add(series1);
this.chart1.Series.Add(series2);
this.chart1.Size = new System.Drawing.Size(1159, 359);
this.chart1.TabIndex = 7;
this.chart1.Text = "chart1";
this.chart1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseDown);
this.chart1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseMove);
this.chart1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseUp);
EDIT: IMAGE
You are correct, there is no proper way to use a real z-axis in the Chart control.
It does have a 3D style though, which can be used for a reasonably nice ChartArea.
You will have to do the painting of the graph in code though, as the built-in z-axis only support as many, or rather as few discret values as you have Series in the chart.
This is ok for some things, like a color cube, but when you need arbitryry data values it just won't do.
Instead you can do this:
Store the z-value of each DataPoint along with the Y-value in the YValues array.
For this you need a ChartType that supports several YValues
Code one of the xxxPaint events to draw the graphics
For this you need a conversion from values to pixels
First we prepare the chart. Many details are up to your needs;
void prepare3dChart(Chart chart, ChartArea ca)
{
ca.Area3DStyle.Enable3D = true; // set the chartarea to 3D!
ca.AxisX.Minimum = -250;
ca.AxisY.Minimum = -250;
ca.AxisX.Maximum = 250;
ca.AxisY.Maximum = 250;
ca.AxisX.Interval = 50;
ca.AxisY.Interval = 50;
ca.AxisX.Title = "X-Achse";
ca.AxisY.Title = "Y-Achse";
ca.AxisX.MajorGrid.Interval = 250;
ca.AxisY.MajorGrid.Interval = 250;
ca.AxisX.MinorGrid.Enabled = true;
ca.AxisY.MinorGrid.Enabled = true;
ca.AxisX.MinorGrid.Interval = 50;
ca.AxisY.MinorGrid.Interval = 50;
ca.AxisX.MinorGrid.LineColor = Color.LightSlateGray;
ca.AxisY.MinorGrid.LineColor = Color.LightSlateGray;
// we add two series:
chart.Series.Clear();
for (int i = 0; i < 2; i++)
{
Series s = chart.Series.Add("S" + i.ToString("00"));
s.ChartType = SeriesChartType.Bubble; // this ChartType has a YValue array
s.MarkerStyle = MarkerStyle.Circle;
s["PixelPointWidth"] = "100";
s["PixelPointGapDepth"] = "1";
}
chart.ApplyPaletteColors();
addTestData(chart);
}
Here we add some test data:
void addTestData(Chart chart)
{
Random rnd = new Random(9);
for (int i = 0; i < 100; i++)
{
double x = Math.Cos(i/10f )*88 + rnd.Next(5);
double y = Math.Sin(i/11f)*88 + rnd.Next(5);
double z = Math.Sqrt(i*2f)*88 + rnd.Next(5);
AddXY3d( chart.Series[0], x, y, z);
AddXY3d( chart.Series[1], x-111, y-222, z);
}
}
The DataPoints are added with this routine:
int AddXY3d(Series s, double xVal, double yVal, double zVal)
{
int p = s.Points.AddXY(xVal, yVal, zVal);
// the DataPoint are transparent to the regular chart drawing:
s.Points[p].Color = Color.Transparent;
return p;
}
If this Paint event we draw the data as we like it. Here are either Lines or Points:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
Chart chart = sender as Chart;
if (chart .Series.Count < 1) return;
if (chart .Series[0].Points.Count < 1) return;
ChartArea ca = chart .ChartAreas[0];
e.ChartGraphics.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
List<List<PointF>> data = new List<List<PointF>>();
foreach (Series s in chart .Series)
data.Add(GetPointsFrom3D(ca, s, s.Points.ToList(), e.ChartGraphics));
renderLines(data, e.ChartGraphics.Graphics, chart , true); // pick one!
renderPoints(data, e.ChartGraphics.Graphics, chart , 6); // pick one!
}
The coodinates are calculated using axis methods:
List<PointF> GetPointsFrom3D(ChartArea ca, Series s,
List<DataPoint> dPoints, ChartGraphics cg)
{
var p3t = dPoints.Select(x => new Point3D((float)ca.AxisX.ValueToPosition(x.XValue),
(float)ca.AxisY.ValueToPosition(x.YValues[0]),
(float)ca.AxisY.ValueToPosition(x.YValues[1]))).ToArray();
ca.TransformPoints(p3t.ToArray());
return p3t.Select(x => cg.GetAbsolutePoint(new PointF(x.X, x.Y))).ToList();
}
The actual drawing happens in these routines; one draws lines the other dots:
void renderLines(List<List<PointF>> data, Graphics graphics, Chart chart, bool curves)
{
for (int i = 0; i < chart.Series.Count; i++)
{
if (data[i].Count > 1)
using (Pen pen = new Pen(Color.FromArgb(64, chart.Series[i].Color), 2.5f))
if (curves) graphics.DrawCurve(pen, data[i].ToArray());
else graphics.DrawLines(pen, data[i].ToArray());
}
}
void renderPoints(List<List<PointF>> data, Graphics graphics, Chart chart, float width)
{
for (int s = 0; s < chart.Series.Count; s++)
{
Series S = chart.Series[s];
for (int p = 0; p < S.Points.Count; p++)
using (SolidBrush brush = new SolidBrush(Color.FromArgb(64, S.Color)))
graphics.FillEllipse(brush, data[s][p].X-width/2,
data[s][p].Y-width/2,width, width);
}
}
Other drawing routines like meshes or areas can be coded just as well.. Simply add new routines using user GDI+ methods like DrawCurve or FillPolygon or maybe even DrawImage..
You can set the ChartArea.Area3DStyle.Rotation and the ChartArea.Area3DStyle.Inclination for different views, as can be seen in the animation.
Edit I have update the PostPaint method to minimze dependencies.
I'm new to C# and I want to draw some rectangles on a chart (System.Windows.Forms.DataVisualization.Charting.Chart). I've tried looking at some tutorials, althought most of them are about drawing on a form and not on a chart.
Here is some code I've made based on some tutorials. It does not work, the chart simply goes blank.
public partial class Form1 : Form
{
private RectangleF r1;
private RectangleF r2;
public Form1()
{
r1.X = 10;
r1.Y = 10;
r1.Width = 20;
r1.Height = 20.5F;
r1.X = 100;
r1.Y = 100;
r1.Width = 200;
r1.Height = 300;
System.Windows.Forms.DataVisualization.Charting.Chart chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();
InitializeComponent();
this.chart1.PostPaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(this.PostPaint);
}
private void PostPaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e)
{
e.ChartGraphics.GetAbsoluteRectangle(r1);
}
}
In this example I've created as well, only the second rectangle is drawn and the chart shows no axis at all. I want to draw multiples triangles using floats.
public partial class Form1 : Form
{
private Rectangle r1;
private Rectangle r2;
public Form1()
{
r1.X = 10;
r1.Y = 10;
r1.Width = 20;
r1.Height = 20;
r1.X = 100;
r1.Y = 100;
r1.Width = 200;
r1.Height = 300;
System.Windows.Forms.DataVisualization.Charting.Chart chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();
InitializeComponent();
this.chart1.PostPaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(this.PostPaint);
}
private void PostPaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e)
{
e.ChartGraphics.Graphics.DrawRectangle(new Pen(Color.Red, 3), r1);
e.ChartGraphics.Graphics.DrawRectangle(new Pen(Color.Black, 5), r2);
}
}
In both examples, you're setting the values for r1 twice instead of r1 and r2.
In your first example, GetAbsoluteRectangle does not draw a rectangle. It is used for converting coordinates. You should use DrawRectangle like you are in the second example.
Simply change
r1.X = 100;
r1.Y = 100;
r1.Width = 200;
r1.Height = 300;
By that :
r2.X = 100;
r2.Y = 100;
r2.Width = 200;
r2.Height = 300;
It will - normaly - works fine.
I want to print one tall (long) image in many pages. So in every page, I take a suitable part from the image and I draw it in the page.
the problem is that I have got the image shrunk (its shape is compressed) in the page,so I added an scale that its value is 1500 .
I think that I can solve the problem if I knew the height of the page (e.Graphics) in pixels.
to convert Inches to Pixel, Do I have to multiply by (e.Graphics.DpiX = 600) or multiply by 96 .
void printdocument_PrintPage(object sender, PrintPageEventArgs e)
{
if (pageImage == null)
return;
e.Graphics.PageUnit = GraphicsUnit.Pixel;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
float a = (e.MarginBounds.Width / 100) * e.Graphics.DpiX;
float b = ((e.MarginBounds.Height / 100) * e.Graphics.DpiY);
int scale = 1500;
scale = 0; //try to comment this
RectangleF srcRect = new RectangleF(0, startY, pageImage.Width, b - scale);
RectangleF destRect = new RectangleF(0, 0, a, b);
e.Graphics.DrawImage(pageImage, destRect, srcRect, GraphicsUnit.Pixel);
startY = Convert.ToInt32(startY + b - scale);
e.HasMorePages = (startY < pageImage.Height);
}
could you please make it works correctly.
you can download the source code from (here).
thanks in advanced.
I tried to complete your task.
Here you go. Hope it helps.
This method prints the image on several pages (or one if image is small).
private void printImage_Btn_Click(object sender, EventArgs e)
{
list = new List<Image>();
Graphics g = Graphics.FromImage(image_PctrBx.Image);
Brush redBrush = new SolidBrush(Color.Red);
Pen pen = new Pen(redBrush, 3);
decimal xdivider = image_PctrBx.Image.Width / 595m;
int xdiv = Convert.ToInt32(Math.Ceiling(xdivider));
decimal ydivider = image_PctrBx.Image.Height / 841m;
int ydiv = Convert.ToInt32(Math.Ceiling(ydivider));
/*int xdiv = image_PctrBx.Image.Width / 595; //This is the xsize in pt (A4)
int ydiv = image_PctrBx.Image.Height / 841; //This is the ysize in pt (A4)
// # 72 dots-per-inch - taken from Adobe Illustrator
if (xdiv >= 1 && ydiv >= 1)
{*/
for (int i = 0; i < xdiv; i++)
{
for (int y = 0; y < ydiv; y++)
{
Rectangle r;
try
{
r = new Rectangle(i * Convert.ToInt32(image_PctrBx.Image.Width / xdiv),
y * Convert.ToInt32(image_PctrBx.Image.Height / ydiv),
image_PctrBx.Image.Width / xdiv,
image_PctrBx.Image.Height / ydiv);
}
catch (Exception)
{
r = new Rectangle(i * Convert.ToInt32(image_PctrBx.Image.Width / xdiv),
y * Convert.ToInt32(image_PctrBx.Image.Height),
image_PctrBx.Image.Width / xdiv,
image_PctrBx.Image.Height);
}
g.DrawRectangle(pen, r);
list.Add(cropImage(image_PctrBx.Image, r));
}
}
g.Dispose();
image_PctrBx.Invalidate();
image_PctrBx.Image = list[0];
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += PrintDocument_PrintPage;
PrintPreviewDialog previewDialog = new PrintPreviewDialog();
previewDialog.Document = printDocument;
pageIndex = 0;
previewDialog.ShowDialog();
// don't forget to detach the event handler when you are done
printDocument.PrintPage -= PrintDocument_PrintPage;
}
This method prints every picture in the List in the needed dimensions (A4 size):
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
// Draw the image for the current page index
e.Graphics.DrawImageUnscaled(list[pageIndex],
e.PageBounds.X,
e.PageBounds.Y);
// increment page index
pageIndex++;
// indicate whether there are more pages or not
e.HasMorePages = (pageIndex < list.Count);
}
This method crops the image and returns every part of the image:
private static Image cropImage(Image img, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea, System.Drawing.Imaging.PixelFormat.DontCare);
return (Image)(bmpCrop);
}
The Image gets loaded from the PictureBox, so make sure the image is loaded. (No exception handling yet).
internal string tempPath { get; set; }
private int pageIndex = 0;
internal List<Image> list { get; set; }
These variables are defined as global variables.
You can download a sample project here:
http://www.abouchleih.de/projects/PrintImage_multiplePages.zip // OLD Version
http://www.abouchleih.de/projects/PrintImage_multiplePages_v2.zip // NEW
I have Created a Class file for multiple page print a single large image.
Cls_PanelPrinting.Print Print =new Cls_PanelPrinting.Print(PnlContent/Image);
You have to Pass the panel or image.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Printing;
namespace Cls_PanelPrinting
{
public class Print
{
readonly PrintDocument printdoc1 = new PrintDocument();
readonly PrintPreviewDialog previewdlg = new PrintPreviewDialog();
public int page = 1;
internal string tempPath { get; set; }
private int pageIndex = 0;
internal List<Image> list { get; set; }
private int _Line = 0;
private readonly Panel panel_;
public Print(Panel pnl)
{
panel_ = pnl;
printdoc1.PrintPage += (printdoc1_PrintPage);
PrintDoc();
}
private void printdoc1_PrintPage(object sender, PrintPageEventArgs e)
{
Font myFont = new Font("Cambria", 10, FontStyle.Italic, GraphicsUnit.Point);
float lineHeight = myFont.GetHeight(e.Graphics) + 4;
float yLineTop = 1000;
int x = e.MarginBounds.Left;
int y = 25; //e.MarginBounds.Top;
e.Graphics.DrawImageUnscaled(list[pageIndex],
x,y);
pageIndex++;
e.HasMorePages = (pageIndex < list.Count);
e.Graphics.DrawString("Page No: " + pageIndex, myFont, Brushes.Black,
new PointF(e.MarginBounds.Right, yLineTop));
}
public void PrintDoc()
{
try
{
Panel grd = panel_;
Bitmap bmp = new Bitmap(grd.Width, grd.Height, grd.CreateGraphics());
grd.DrawToBitmap(bmp, new Rectangle(0, 0, grd.Width, grd.Height));
Image objImage = (Image)bmp;
Bitmap objBitmap = new Bitmap(objImage, new Size(700, objImage.Height));
Image PrintImage = (Image)objBitmap;
list = new List<Image>();
Graphics g = Graphics.FromImage(PrintImage);
Brush redBrush = new SolidBrush(Color.Red);
Pen pen = new Pen(redBrush, 3);
decimal xdivider = panel_.Width / 595m;
// int xdiv = Convert.ToInt32(Math.Ceiling(xdivider));
decimal ydivider = panel_.Height / 900m;
int ydiv = Convert.ToInt32(Math.Ceiling(ydivider));
int xdiv = panel_.Width / 595; //This is the xsize in pt (A4)
for (int i = 0; i < xdiv; i++)
{
for (int y = 0; y < ydiv; y++)
{
Rectangle r;
if (panel_.Height > 900)
{
try
{
if (list.Count > 0)
{
r = new Rectangle(0, (900 * list.Count), PrintImage.Width, PrintImage.Height - (900 * list.Count));
}
else
{
r = new Rectangle(0, 0, PrintImage.Width, 900);
}
list.Add(cropImage(PrintImage, r));
}
catch (Exception)
{
list.Add(PrintImage);
}
}
else { list.Add(PrintImage); }
}
}
g.Dispose();
PrintImage = list[0];
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += printdoc1_PrintPage;
PrintPreviewDialog previewDialog = new PrintPreviewDialog();
previewDialog.Document = printDocument;
pageIndex = 0;
printDocument.DefaultPageSettings.PrinterSettings.PrintToFile = true;
string path = "d:\\BillIng.xps";
if (File.Exists(path))
File.Delete(path);
printDocument.DefaultPageSettings.PrinterSettings.PrintFileName = "d:\\BillIng.xps";
printDocument.PrintController = new StandardPrintController();
printDocument.Print();
printDocument.PrintPage -= printdoc1_PrintPage;
}
catch { }
}
private static Image cropImage(Image img, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea, System.Drawing.Imaging.PixelFormat.DontCare);
return (Image)(bmpCrop);
}
}
}