Aligning labels in array in C# to form a grid - c#

I have created an array of black labels and have displayed them on a picture box. Unfortunately, I am not able to line them up directly at each intersection of the black lines. How can I do this?
InitializeComponent();
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
// create 361 labels, set their properties
for (int i = 0; i < 361; i++)
{
board[i] = new Label();
board[i].Parent = pictureBox1;
board[i].Location = new Point(x, y);
board[i].Name = "label" + i;
board[i].Text = "0";
board[i].BackColor = Color.Black;
//set size of labels
board[i].Size = new Size(31,31);
}
// set the position of the label
foreach (Label i in board)
{
//set distance between labels
if (x >= 1024)
{
x = pictureBox1.Location.X;
y += 52;
}
else
{
x += 52;
}
this.Controls.Add(i);
i.BringToFront();
i.Location = new Point(x, y);
}

as far as i have understand your question, and saw your code.
you are creating labels at same
Location(x,y) where x = 100 and y = 0
in the next loop
foreach (Label i in board)
{
if (x >= 1024)
{
x = 0;
y += i.Height + 55;
}
else if (y >= 1024)
{
y = 0;
x += i.Width + 55;
}
}
None of your condition will become true, because your x = 100 and y = 0
so location will remain same and all labels will be at same location
if you want to display a chess grid see this method
Chess Grid in Winforms
if you want to display labels on intersection of lines then lets modify your Code
x = PictureBox1.Location.X + 55;
y = pictureBox1.Location.Y + 55;
for (int i = 0; i < 361; i++)
{
board[i] = new Label();
board[i].Parent = pictureBox1;
board[i].Location = new Point(x,y);
board[i].Name = "label" + i;
board[i].Text = "0";
board[i].BackColor = Color.Black;
board[i].Size = new Size(55,55); //Define size of label according to your choice
if(x >= 1024)
{
x = PictureBox1.Location.X + 55; //Start position
y += 55; // Step to next line
}
else
x += 55; //jump to next horizontal box
}
I hope this helps

Related

which button is pressed in dynamically created button 2d array

I have a 2d array of LEDButton : Button.
I want to find out the index [x,y] of each buttons the user clicks.
I am new to Windows Forms and not used to working outside of a console so these GUI objects are very unfamiliar to me.
private void Form1_Load(object sender, EventArgs e)
{
LEDButton[,] leds = new LEDButton[11, 11];
for (int x = 0; x < leds.GetUpperBound(0); x++)
{
listBox1.Items.Add("x = " + x);
for (int y = 0; y < leds.GetUpperBound(1); y++)
{
leds[x, y] = new LEDButton()
{
Name = String.Format("Button{0}{1}", x, y),
TabIndex = 40 * x + y,
Location = new Point(40 * y + 50, 40 * x + 50)
};
leds[x, y].pointx = x;
leds[x, y].pointy = y;
}
}
// add buttons to controls
for (int x = 0; x < leds.GetUpperBound(0); x++)
{
for (int y = 0; y < leds.GetUpperBound(1); y++)
{
Controls.Add(leds[x, y]);
leds[x, y].Click += Form1_Click;
}
}
public class LEDButton : Button
{
public const int LEDWidth = 20;
public const int LEDHeight = 20;
public int pointx = 0;
public int pointy = 0;
public LEDButton()
{
BackColor = Color.FromArgb(0, 64, 0);
ForeColor = Color.Black;
FlatStyle = FlatStyle.Flat;
Size = new Size(LEDWidth, LEDHeight);
UseVisualStyleBackColor = false;
this.Click += LEDButton_Click; //throws error
}
}
I think I found my answer with the help of Lars.
Code should be
private void Form1_Click(object? sender, EventArgs e)
{
LEDButton btn = sender as LEDButton;
listBox2.Items.Add(btn.Name);
}

How to create scrolling tiles in Visual Studio C# Forms

I want to make a tiles based scrolling game in Visual Studio C# using forms. I know its not the best platform for this but those are set parameters. I suppose the easiest way to think of the end program is like pokemon 2d top down world scrolling.
I can create a 2d array of picture boxes and allocated images to them based on a text 2d array of tile ids. I can scroll the picture boxes and when they reach a certain place, jump back to the original location and display a shifted tile.
My issue is adding controls, it only adds a column rather than the full grid. I have tried using tables but with the same problem.
Has anyone done this type of large world scroller using VSC# and forms? Are there any tutorials or suggestions? Thanks.
EDIT - Code added'
public Form1()
{
InitializeComponent();
TableLayoutPanel wholescreen = new TableLayoutPanel();
wholescreen.Location = new System.Drawing.Point(0,0);
wholescreen.Size = new System.Drawing.Size(200,200);
wholescreen.RowCount = 2;
wholescreen.ColumnCount = 2;
Controls.Add(wholescreen);
PictureBox item = new PictureBox();
item.Size = new System.Drawing.Size(50, 50);
item.ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < 2; y++)
{
item.Left = x * 50;
item.Top = y * 50;
wholescreen.Controls.Add(item,x,y);
}
}
}
'
another way i tried....'
int WIDTH = 3;
int HEIGHT = 3;
PictureBox[] grid = new PictureBox[9];
//PictureBox[,] grid = new PictureBox[3, 3];
//int[,] level1 = new int[2, 2] { { 1, 2 }, { 3, 4 } };
int playerx = 0;
public Form1()
{
InitializeComponent();
int y = 0;
int x = 0;
for (int cntr = 0; cntr < HEIGHT*WIDTH; cntr++)
{
if ((cntr % HEIGHT) == 0)
{
x++;
y = 0;
}
grid[cntr] = new PictureBox();
grid[cntr].Left = x * 50;
grid[cntr].Top = y * 50;
grid[cntr].ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
Controls.Add(grid[cntr]);
}
}
'
I think you are just creating one square and moving it around. Try...
private void Method2()
{
TableLayoutPanel wholescreen = new TableLayoutPanel();
wholescreen.BackColor = Color.AliceBlue;
wholescreen.Location = new System.Drawing.Point(0, 0);
wholescreen.Size = new System.Drawing.Size(200, 200);
wholescreen.RowCount = 2;
wholescreen.ColumnCount = 2;
Controls.Add(wholescreen);
PictureBox item;
// item.ImageLocation = "C:\\Users\\i.price\\Documents\\1.png";
for (int x = 0; x < 2; x++)
{
for (int y = 0; y < 2; y++)
{
item = new PictureBox();
item.Size = new System.Drawing.Size(50, 50);
item.BackColor = Color.Blue;
//item.Left = 0;
//item.Top = 0;
wholescreen.Controls.Add(item, x, y);
}
}
}

Multiple Y axis Labels/Title overlap each others

I am showing multiple Y axis for chart by using below code. When any axis label value is having more than 3 digits then that axis Label/Title is getting overlap with other axis Label (as shown in image).
int leftIndex = 0, rightIndex = 0;
int relativePosition = 0;
foreach (Steema.TeeChart.Axis axis in this.tChart.Axes.Custom)
{
axis.Visible = true;
axis.PositionUnits = Steema.TeeChart.PositionUnits.Pixels;
axis.RelativePosition = 0 - (axis.OtherSide ? rightIndex++ : leftIndex++) * 60;
relativePosition = relativePosition + (axis.AxisRect().Width + 60);
}
You should be able to get your chart to render correctly by slightly modifying the constant in your calculation, e.g.
TChart _tChart;
public Form1()
{
InitializeComponent();
_tChart = new TChart();
_tChart.Dock = DockStyle.Fill;
_tChart.Series.Add(typeof(Line)).FillSampleValues();
_tChart.Series.Add(typeof(Line)).FillSampleValues();
_tChart.Series.Add(typeof(Line)).FillSampleValues();
_tChart.Series[0].YValues.Value = _tChart.Series[2].YValues.Value.Select(x => x * 100).ToArray();
_tChart.Header.Text = Utils.Version;
_tChart[0].CustomVertAxis = _tChart.Axes.Custom.Add();
_tChart[0].CustomVertAxis.Title.Text = "Axis One Title";
_tChart[0].CustomVertAxis.Title.Angle = 90;
_tChart[1].CustomVertAxis = _tChart.Axes.Custom.Add();
_tChart[1].CustomVertAxis.Title.Text = "Axis Two Title";
_tChart[1].CustomVertAxis.Title.Angle = 90;
_tChart[2].CustomVertAxis = _tChart.Axes.Custom.Add();
_tChart[2].CustomVertAxis.Title.Text = "Axis Three Title";
_tChart[2].CustomVertAxis.Title.Angle = 90;
int leftIndex = 0, rightIndex = 0;
for (int i = 0; i < this._tChart.Axes.Custom.Count; i++)
{
var axis = this._tChart.Axes.Custom[i];
axis.Visible = true;
axis.PositionUnits = Steema.TeeChart.PositionUnits.Pixels;
axis.RelativePosition = 0 - (axis.OtherSide ? rightIndex++ : leftIndex++) * (i == 1 ? 80: 70);
}
_tChart.Panel.MarginLeft = 30;
this.Controls.Add(_tChart);
}
Which here gives me:

Button next to the users in a loop

I got a form with 7 users on it among each other. But I want to set 7 button next to it in a loop. Right now I've got this.
int x = 12;
int y = 30;
foreach (details dets1 in detailsList)
{
var label = new Label();
label.AutoSize = true;
label.Location = new Point(x, y);
label.Name = dets1.fname;
label.Text = dets1.fname;
this.Controls.Add(label);
y += label.Height + 5;
}
for (int i = 0; i < 7 ; i++)
{
Button button = new Button();
button.Location = new Point(200, 30);
button.Text = "Off";
button.Tag = i;
button.BackColor = Color.Red;
this.Controls.Add(button);
button.Click += button_Click;
}
Your problem is in the Location: you put all the buttons on the same place
for (int i = 0; i < 7 ; i++) {
...
button.Location = new Point(200, 30);
...
}
Let's organaize all the buttons vertically:
const int shift = 50;
for (int i = 0; i < 7 ; i++) {
...
button.Location = new Point(200, 30 + shift * i);
...
}
Or horizontally:
const int shift = 90;
for (int i = 0; i < 7 ; i++) {
...
button.Location = new Point(200 + shift * i, 30);
...
}

How to detect black Bullets in Image?

Given the following image, How can I detect black bullets (90 bullet) in this image using C#, EmguCV or AForge?
I tried to use GetPixel(x,y) method but it checks only pixel by pixel, it is very slow and I need to detect the bullets not pixels.
Algorithm/Idea 1
You can divide your image in squares as shown in this sample:
With this logic you only have to check every 20th pixel. As soon as you know where the first dot is, you will know that every other dot have to be in the same horizontal line (in your provided sample).
A sample algorithm would look similar to this (please note that it need further improvement):
Bitmap myBitmap = new Bitmap ("input.png");
int skipX = 12;
int skipY = 12;
int detectedDots = 0;
for (int x = 0; x < myBitmap.Width; x += skipX) {
for (int y = 0; y < myBitmap.Height; y += skipY) {
Color pixelColor = myBitmap.GetPixel (x, y);
if (pixelColor.R + pixelColor.G + pixelColor.B == 0) {
myBitmap.SetPixel (x, y, Color.Red);
detectedDots++;
}
}
}
myBitmap.Save ("output.png");
Console.WriteLine (detectedDots + " dots detected");
I added an output so you can check which dots got detected (all containing red pixels).
Further improvement would be to find the center of a dot. After that you should know the width (and height) and can start at first upper left dot with an offset of the dots width.
Algorithm 2
The second algorithm analyses each pixel and is a lot easier to implement. As soon as there's a black pixel it checks if there was a black pixel in the same vertical or horizontal line before and skips in this case until there is no black pixel in line.
Further improvement would be to store the height of the first dot and to make the condition in the middle of the snippet more beautiful.
Stopwatch watch = new Stopwatch(); watch.Start();
Bitmap myBitmap = new Bitmap ("input.png");
int dotsDetected = 0;
List<int> xFound = new List<int>();
for (int x = 0; x < myBitmap.Width; x++) {
bool yFound = false;
bool dotFound = false;
for (int y = 0; y < myBitmap.Height; y++) {
Color pixelColor = myBitmap.GetPixel (x, y);
if (pixelColor.R + pixelColor.G + pixelColor.B == 0) {
dotFound = true;
if (yFound)
continue;
if (xFound.Contains (y)
|| xFound.Contains (y + 1)
|| xFound.Contains (y + 2)
|| xFound.Contains (y + 3)
|| xFound.Contains (y + 4)
|| xFound.Contains (y - 1)
|| xFound.Contains (y - 2)
|| xFound.Contains (y - 3)
|| xFound.Contains (y - 4)) {
yFound = true;
continue;
}
xFound.Add (y);
//myBitmap.SetPixel (x, y, Color.Red);
dotsDetected++;
yFound = true;
} else
yFound = false;
}
if(!dotFound) //no dot found in this line
xFound.Clear();
}
//myBitmap.Save ("output.png");
watch.Stop();
Console.WriteLine("Picture analyzed in " + watch.Elapsed.TotalSeconds.ToString("#,##0.0000"));
Console.WriteLine (dotsDetected + " dots detected");
Unless you are doing this to learn more about image processing, do not re-invent the wheel. Just use emgucv (or a similar library). The emgucv syntax is rather unfriendly (mostly because of its underlying Win32 OpenCV implementation), but basically it comes down to
Contour<Point> contour = img.FindContours(CV_CHAIN_APPROX_TC89_L1, RETR_TYPE.CV_RETR_LIST);
for (; contour != null; contour = contour.HNext)
{
// You now have the contours. These have characteristics like a boundingRect, which is an easy way to approach the center of a circle.
}
I created a full solution for the problem (relying only on Bitmap.GetPixel(Int32,Int32)).
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace StackOverflow
{
public static class Program
{
static void Main(string[] args)
{
const String PATH = #"C:\sim\sbro6.png";
Stopwatch watch = new Stopwatch(); watch.Start();
List<Bitmap> l_new, l_old;
{
Bitmap bmp = Image.FromFile(PATH) as Bitmap;
// Initialization
l_old = new List<Bitmap>();
l_new = new List<Bitmap>(); l_new.Add(bmp);
// Splitting
while (l_new.Count > l_old.Count)
{
l_old = l_new; l_new = new List<Bitmap>();
l_new.AddRange(SplitBitmapsVertically(SplitBitmapsHorizontally(l_old)));
}
// for (Int32 i = 0; i < l_new.Count; i++)
// {
// l_new[i].Save(#"C:\sim\bitmap_" + i + ".bmp");
// }
}
watch.Stop();
Console.WriteLine("Picture analyzed in ".PadRight(59,'.') + " " + watch.Elapsed.TotalSeconds.ToString("#,##0.0000"));
Console.WriteLine("Dots found ".PadRight(59, '.') + " " + l_new.Count);
Console.WriteLine();
Console.WriteLine("[ENTER] terminates ...");
Console.ReadLine();
}
static List<Bitmap> SplitBitmapsVertically(List<Bitmap> l_old)
{
Int32 x_start = -1; Bitmap bmp; Boolean colContainsData = false;
List<Bitmap> l = new List<Bitmap>();
foreach(Bitmap b in l_old)
{
for (Int32 x = 0; x < b.Width; x++)
{
colContainsData = false;
for (Int32 y = 0; y < b.Height; y++)
{
if (b.GetPixel(x, y).ToArgb() != Color.White.ToArgb())
{
colContainsData = true;
}
}
if (colContainsData) if (x_start < 0) { x_start = x; }
if (!colContainsData || (x == (b.Width - 1))) if (x_start >= 0)
{
bmp = new Bitmap(x - x_start, b.Height);
for (Int32 x_tmp = x_start; x_tmp < x; x_tmp++)
for (Int32 y_tmp = 0; y_tmp < b.Height; y_tmp++)
{
bmp.SetPixel(x_tmp - x_start, y_tmp, b.GetPixel(x_tmp, y_tmp));
}
l.Add(bmp); x_start = -1;
}
}
}
return l;
}
static List<Bitmap> SplitBitmapsHorizontally(List<Bitmap> l_old)
{
Int32 y_start = -1; Bitmap bmp; Boolean rowContainsData = false;
List<Bitmap> l = new List<Bitmap>();
foreach (Bitmap b in l_old)
{
for (Int32 y = 0; y < b.Height; y++)
{
rowContainsData = false;
for (Int32 x = 0; x < b.Width; x++)
{
if (b.GetPixel(x, y).ToArgb() != Color.White.ToArgb())
{
rowContainsData = true;
}
}
if (rowContainsData) if (y_start < 0) { y_start = y; }
if (!rowContainsData || (y == (b.Height - 1))) if (y_start >= 0)
{
bmp = new Bitmap(b.Width, y - y_start);
for (Int32 x_tmp = 0; x_tmp < b.Width; x_tmp++)
for (Int32 y_tmp = y_start; y_tmp < y; y_tmp++)
{
bmp.SetPixel(x_tmp, y_tmp - y_start, b.GetPixel(x_tmp, y_tmp));
}
l.Add(bmp); y_start = -1;
}
}
}
return l;
}
}
}
It takes roughly half a second to process the image (see attached picture)
The idea is to iteratively split the provided image into rows and colums that do only contain a subset of dots until there is exactly one dot contained.
The dots may be arbitrarily spread over the image. Hope this helps

Categories

Resources