C# Drawing rectangle - c#

I have create a ListView and get a data from a ListView to draw a rectangle.
The ListView items count is always change with unknown count and also the x and y too. My ListView will be like this :
Subitem[0].Text || Subitem[1].text
500 100
100 200
++ ++
By Subitem[0] is X ,Subitem[1] is Y
And now I have create a code to draw the rectangle like this:
private void Draw_Tick(object sender, EventArgs e)
{
this.Invalidate();
Pen p = new Pen(Color.Red);
SolidBrush sb = new SolidBrush(Color.Red);
Graphics g = PaintingPanel.CreateGraphics();
for (int i = 0; i < ListView1.Items.Count + 1; i++)
{
p.Width = 3;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.InterpolationMode = InterpolationMode.Low;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
Rectangle rectf = new Rectangle(X.Split(',')[i],Y.Split(',')[i], 50, 75);
g.DrawRectangle(p,rectf);
}
}
Add the X and Y to Array
Public static string X;
Public static string Y;
for (int i = 0; i < ListView1.Items.Count + 1; i++)
{
List<string> ls = new List<string>();
foreach (ListViewItem item in ListView1.Items)
{
ls.Add(item.SubItems[0].Text);
}
X = string.Join(",", ls);
}
for (int i = 0; i < ListView1.Items.Count + 1; i++)
{
List<string> ls2 = new List<string>();
foreach (ListViewItem item in ListView1.Items)
{
ls2.Add(item.SubItems[1].Text);
}
Y = string.Join(",", ls2);
}
But my point is I have used this.Invalidate() to clear the drawing and create a new drawing because the data changed. My question is how can I just move the rectangle instead of using this.invalidate to clear the drawing (Because its kind of flashing when this.Invalidate();.

Related

Get the clicked rectangle in 2d array

I have a 2D array that contains rectangles. They are stored in a dynamic UniformGrid. How do I find out which rectangle in the array was MouseDown?
I tried this but I keep getting [0,0]:
if (e.OriginalSource is Shape s)
{
cellRow = (int)s.GetValue(Grid.RowProperty);
cellColumn = (int)s.GetValue(Grid.ColumnProperty);
rectangle[cellRow,cellColumn].Fill = new SolidColorBrush(Colors.Black);
}
And this is how I generated the rectangles:
rectangle = new Rectangle[rowcol, rowcol];
for (int x = 0; x < rowcol; x++)
{
for (int y = 0; y < rowcol; y++)
{
rectangle[y, x] = new Rectangle { Stroke = Brushes.Black, StrokeThickness = 0.5, Fill = Brushes.White };
GameUniformGrid.Children.Add(rectangle[y, x]);
}
}
The MouseDown event in xaml:
<UniformGrid x:Name="GameUniformGrid" HorizontalAlignment="Left" Height="272" VerticalAlignment="Top" Width="272" Grid.Row="0" Grid.Column="0" Rectangle.MouseDown="ToggleGrid"/>
I think the problem is with initializing a rectangle,
When you work with multidimentional array you have some rows and column and what you are doing is using row only in both row,column.
What if rowcol =0 ? the loop will not run because this condition.
x < rowcol (0<0);
You should
rectangle = new Rectangle[row, col];
for (int x = 0; x < row; x++)
{
for (int y = 0; y < col; y++)
{
rectangle[y, x] = new Rectangle { Stroke = Brushes.Black, StrokeThickness = 0.5, Fill = Brushes.White };
GameUniformGrid.Children.Add(rectangle[y, x]);
}
}
(For example)
where row = 2 ,col =2

How to create a Grid system where each square has an x and y value using visual studios graphics?

My goal is to have a robot use this grid to create a map base off the information it collects from its surroundings. When the robot detects an object the square in front of it turns red. Currently I am stuck on how I can give each square an x and Y value for location purposes. Also when I scroll the screen the block sizes change, can someone provide help with that as well?
Rectangle rect = new Rectangle(700, 350, 50, 50);
g.DrawRectangle(myPen, rect); // Draws the Rectangle to the screen
e.Graphics.FillEllipse(myBrush, 700,350,50,50);`
for (int i = 0; i < 9900; i = i + 50)
{
rect = new Rectangle(0 + i, 0, 50, 50);
g.DrawRectangle(myPen, rect);
for (int j = 0; j < 9900; j = j + 50)
{
rect = new Rectangle(0 + i, 0 + j, 50, 50);
g.DrawRectangle(myPen, rect);
}
}
Here is a very quick example of how to do this using a 2d array. It was written in LINQPad, so it may look a little odd, but it should give you some leads. It allows you to store a map and look up values using x and y coordinates. You can use the CellInfo class to add any extra information about the cell that you need, beyond if it is blocking or not.
Ideally, you would want to wrap the entire array up in your own Map class, that abstracts away the details, and gives you a lot of helpful utility functions. For instance, if your map is extremely large, you may run out of memory. You could have the Map class only load smaller blocks of the map from files on disk as needed, or even make the map wrap around its self easily.
void Main()
{
var map = new CellInfo[10, 10];
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
map[x, y] = new CellInfo();
}
}
var rnd = new Random();
for (int i = 0; i < 20; i++)
{
map[rnd.Next(0, 10), rnd.Next(0, 10)].IsBlocked = true;
}
DrawMap(map).Dump();
}
public Bitmap DrawMap(CellInfo[,] map)
{
var img = new Bitmap(320, 320, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(img))
{
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
var cell = map[x, y];
Brush brush = cell.IsBlocked ? Brushes.Red : Brushes.White;
g.FillRectangle(brush, x * 32, y * 32, 31, 31);
g.DrawRectangle(Pens.Black, x * 32, y * 32, 31, 31);
}
}
}
return img;
}
public class CellInfo
{
public bool IsBlocked { get; set; } = false;
}
It produces the following output (varies each time it is run):

Place a grid of labels on a form

I'm trying to place a grid of labels on my winforms app. First, I'm populating a list of label objects of size (200 x 50) and then trying to place them so that when x reaches the width of the form (581), I increment y by 50 + 1
Here is my code:
private List<Label> _labels;
private int xOffset = 10;
private int yOffset = 10;
public Form1()
{
InitializeComponent();
_labels = new List<Label>();
for(var i = 0; i <= 20; i++)
_labels.Add(new Label() { Name = "lbl" + i, Height = 50, Width = 200, MinimumSize = new Size(200, 50), BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D, Text = "Label "+i});
// 581, 517
var x = 0;
var y = 0;
foreach (var lbl in _labels)
{
if (x >= 580)
{
x = 0;
y = y + lbl.Height + 2;
lbl.Location = new Point(x, y);
}
this.Controls.Add(lbl);
x += x + lbl.Width;
}
}
It's only placing the even labels from the list on new lines. I'm not sure what I'm doing wrong.
I'm trying to place all of the labels in a grid like design. When one row is full, go to the next row and continue placing labels from the list on that new "row"
You need to move the Location setting code out of the resetting loop:
foreach (var lbl in _labels)
{
if (x >= 580)
{
x = 0;
y = y + lbl.Height + 2;
}
lbl.Location = new Point(x, y);
this.Controls.Add(lbl);
x += lbl.Width;
}
The problematic part is here
x += x + lbl.Width; //+= x
change it to
x += lbl.Width;
Get the
lbl.Location = new Point(x, y);
out of the if statement
if (x >= 580)
{
x = 0;
y = y + lbl.Height + 2;
//lbl.Location = new Point(x, y);
}
lbl.Location = new Point(x, y);
this.Controls.Add(lbl);
x += lbl.Width;
Try this using a Docked FlowLayoutPanel:
public partial class Form1 : Form
{
List<Label> labels;
public Form1()
{
InitializeComponent();
this.labels=new List<Label>();
AddLabelsToFrom(20);
}
void AddLabelsToFrom(int count)
{
for (int i=0; i<count; i++)
{
var lbl=new Label() { Name="lbl"+i, Height=50, Width=200, MinimumSize=new Size(200, 50), BorderStyle=System.Windows.Forms.BorderStyle.Fixed3D, Text="Label "+i };
labels.Add(lbl);
flowLayoutPanel1.Controls.Add(lbl);
}
}
}
void SetGridLabel()
{
for (int i = 0; ; i++)
{
for (int j = 0; ; j++)
{
Label L = new Label();
L.TextAlign = ContentAlignment.MiddleCenter;
L.AutoSize = false;
L.Size = new Size(70, 70);
L.Text = "Test_" + j + "_" + i;
L.Location = new Point(j * L.Size.Width, i * L.Size.Height);
if ((i + 1) * L.Size.Height > this.Size.Height)
return;
if ((j + 1) * L.Size.Width > this.Size.Width)
break;
this.Controls.Add(L);
}
}
}
private List<Label> _labels;
public Form1()
{
InitializeComponent();
_labels = new List<Label>();
for (var i = 0; i <= 20; i++)
_labels.Add(new Label()
{
Name = "lbl" + i, Height = 50,Width = 200,
Size = MinimumSize = new Size(200, 50),
Location = new Point(i * 200 % 600, 50 * (i * 200 / 600)),
BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D,
Text = "Label " + i
});
foreach (var lbl in _labels) this.Controls.Add(lbl);
}

How to get randomly drawn rectangles to be vertically stacked next to each other?

I am trying to get randomly drawn rectangles to line up next to each other on a form but my loop is not working and giving me undesired results, any help would be greatly appreciated.
I have already created a method that creates random rectangles and then stores them in the list collection.
List<Rectangle> rectangleCollection = new List<Rectangle>();
void CreateRectangle()
{
int TallestRectangle = 0; ;
int PrevRecX = 0;
int PrevRecY = 0;
Pen pen = new Pen(Color.Black);
Graphics graphic = this.CreateGraphics();
foreach (Rectangle rect in rectangleCollection)
{
if (rect.Height > TallestRectangle)
TallestRectangle = rect.Height;
}
foreach (Rectangle rect in rectangleCollection)
{
if (PrevRecX + PrevRecY == 0)
{
graphic.DrawRectangle(pen, new Rectangle(rect.X, (TallestRectangle - rect.Height), rect.Width, rect.Height));
}
else
{
graphic.DrawRectangle(pen, new Rectangle((PrevRecX + PrevRecY), (TallestRectangle - rect.Height), rect.Width, rect.Height));
}
PrevRecX = rect.X;
PrevRecY = rect.Width;
}
}
void GetRandomRectangle()
{
Random ran = new Random();
int x = 0;
int y = 0;
int width = ran.Next(100, 500);
int height = ran.Next(200, 700);
Rectangle rec = new Rectangle(x, y, width, height);
rectangleCollection.Add(rec);
}
Your second foreach looks way too complicated. And I don't think you really need PrevRecX. Try this and see if it does what you expect.
void CreateRectangle()
{
int TallestRectangle = 0;
int PrevRecY = 0;
Pen pen = new Pen(Color.Black);
Graphics graphic = this.CreateGraphics();
foreach (Rectangle rect in rectangleCollection)
{
if (rect.Height > TallestRectangle)
TallestRectangle = rect.Height;
}
foreach (Rectangle rect in rectangleCollection)
{
graphic.DrawRectangle(pen, new Rectangle(rect.X + PrevRecY, (TallestRectangle - rect.Height), rect.Width, rect.Height));
PrevRecY += rect.Width; // note the +=
}
}
As for the static Random, just declare the variable outside the method and use it inside, like that:
private static Random ran = new Random();
void GetRandomRectangle()
{
int x = 0;
int y = 0;
int width = ran.Next(100, 500);
int height = ran.Next(200, 700);
// ...
}

Drawing a border on an image

I'm currently trying to make a mask generator to generate polygons for images. Here's my code.
Bitmap bmp = new Bitmap(file);
int w = bmp.Width;
int h = bmp.Height;
List<Point> vertices = new List<Point>();
for (int y=0; y<h; y++)
{
bool rowbegin = false;
for (int x=0; x<w; x++)
{
Color c = bmp.GetPixel(x, y);
if (!rowbegin)
{
// Check for a non alpha color
if (c.A != Color.Transparent.A)
{
rowbegin = true;
// This is the first point in the row
vertices.Add(new Point(x, y));
}
} else {
// Check for an alpha color
if (c.A == Color.Transparent.A)
{
// The previous pixel is the last point in the row
vertices.Add(new Point(x-1, y));
rowbegin = false;
}
}
}
}
// Convert to an array of points
Point[] polygon = vertices.ToArray();
Graphics g = Graphics.FromImage(bmp);
g.DrawPolygon(Pens.LawnGreen, polygon);
g.Dispose();
But I'm getting wrong output.
The required.
What I want is also the gaps between the characters to be empty. Also why DrawPolygon is filling it?
Thanks.
Do you trying something like this:i hope my code help you:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(#"C:\Users\Ali\Desktop\1.png");
int w = bmp.Width;
int h = bmp.Height;
Lst_Data lastpointcolor = new Lst_Data() ;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
Color c = bmp.GetPixel(x, y);
if (c.A != Color.Transparent.A)
{
if (lastpointcolor.color.A == Color.Transparent.A)
{
bmp.SetPixel(lastpointcolor.point.X, lastpointcolor.point.Y, Color.Red);
}
}
lastpointcolor = new Lst_Data() { point = new Point(x, y), color = bmp.GetPixel(x, y) };
}
}
for (int y = h-1; y > 0; y--)
{
for (int x = w-1; x > 0; x--)
{
Color c = bmp.GetPixel(x, y);
if (c.A != Color.Transparent.A)
{
if (lastpointcolor.color.A == Color.Transparent.A)
{
bmp.SetPixel(lastpointcolor.point.X, lastpointcolor.point.Y, Color.Red);
}
}
lastpointcolor = new Lst_Data() { point = new Point(x, y), color = bmp.GetPixel(x, y) };
}
}
pictureBox1.Image = bmp;
}
}
public struct Lst_Data
{
public Point point;
public Color color;
}
}
Edited:
And Another idea i have for you:D
Make a mask for original image with the same size and do this:
Bitmap orginal = new Bitmap(#"C:\Users\Ali\Desktop\orginal.png");
Bitmap mask = new Bitmap(#"C:\Users\Ali\Desktop\mask.png");
for (int i = 0; i < orginal.Width; i++)
{
for (int j = 0; j < orginal.Height; j++)
{
if (orginal.GetPixel(i, j).A == Color.Transparent.A)
{
mask.SetPixel(i, j, Color.Transparent);
}
}
}
Bitmap bitmap = new Bitmap(mask, mask.Height, mask.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(mask, 0, 0);
g.DrawImage(orginal,0,0);
}
pictureBox1.Image = bitmap;
Result:

Categories