I am trying to write program with C# to dynamicaly create PictureBox'es from another class.
Here what is done:
In class Form1 creating object of another class and call procedure in that class which creates objects(many PictureBox'es) I want
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;
namespace Lines_online
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//trying to draw NxM table
//where N is horizontal cell count M is vertical cell count
Table tbl = new Table();
tbl.Tablenm(9, 9);
}
}
}
The class Table code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace Lines_online
{
public class Table : Form1
{
List<PictureBox> cell = new List<PictureBox>();
public void Tablenm(int n, int m)
{
for (int i = 0; i < n*m; i++)
{
PictureBox pict = new PictureBox();
cell.Add(pict);
cell[i].Size = new Size(20, 20);
cell[i].Location = new Point(30 + (i % n) * 19, 30 + (i / m) * 19);
cell[i].Image = Properties.Resources.lang20x20;
Controls.Add(cell[i]);
}
}
}
}
Then code is executed it does nothing and gives no errors (I think it creates the objects somethere, but definetaly not in Form1 window). If procedure in the class Table moved to Form1 class it works perfectly, but I want to control it from other class to reduce code size in Form1. I tried to create Form1 object in Class Table:
Form1 frm1 = new Form1();
It did not help. What I am doing wrong, or maybe using bad approach to this problam?
Note: in your code you are inheriting table from Form1. This does mean that Table represents a new form, instead of a reference to the current existing form, and therefore it doesn't do anything.
In the Controls property of your original form, you are just adding another form, which definitely isn't the behaviour that you need.
I've tooked your code as a start and adapted it a bit.
I do think that this should work.
Create your class Table, but DON'T inherit from Form1.
Make your class that it looks like the following:
public class Table
{
public List<PictureBox> Render(int n, int m)
{
List<PictureBox> returnList = new List<PictureBox>();
for (int i = 0; i < n*m; i++)
{
PictureBox pict = new PictureBox();
pict.Size = new Size(20, 20);
pict.Location = new Point(30 + (i % n) * 19, 30 + (i / m) * 19);
pict.Image = Properties.Resources.lang20x20;
returnList.Add(pict);
}
return returnList;
}
}
Then, in your main form, you can call your method:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var table = new Table();
IEnumerable<Control> controls = table.Render(10, 10);
foreach (var control in controls)
{ this.Controls.Add(control); }
}
}
I believe that should work, but I haven't tested it. Also note that this code is not optimized. You should have parameters passed to the function in order to make it more generic.
//You need to add picturebox control to form1 control in loop,
//Form1.Control.Add(cell[i]);
//-------------------
public void Tablenm(int n, int m, Form Form1)
{
for (int i = 0; i < n*m; i++)
{
PictureBox pict = new PictureBox();
cell.Add(pict);
cell[i].Size = new Size(20, 20);
cell[i].Location = new Point(30 + (i % n) * 19, 30 + (i / m) * 19);
cell[i].Image = Properties.Resources.lang20x20;
Form1.Control.Add(cell[i]);
}
}
You can return the List<PictureBox> to Form1
public List<PictureBox> Tablenm(int n, int m)
{
for (int i = 0; i < n*m; i++)
{
PictureBox pict = new PictureBox();
cell.Add(pict);
cell[i].Size = new Size(20, 20);
cell[i].Location = new Point(30 + (i % n) * 19, 30 + (i / m) * 19);
cell[i].Image = Properties.Resources.lang20x20;
}
return cell;
}
Then add it inside you form:
private void Form1_Load(object sender, EventArgs e)
{
//trying to draw NxM table
//where N is horizontal cell count M is vertical cell count
Table tbl = new Table();
var pictureBoxes = tbl.Tablenm(9, 9)
foreach (var pictureBox in pictureBoxes)
{
Controls.Add(picturebox)}
}
}
Related
Buttons very close to each other.
Component Code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
namespace CustomExplorer.Components
{
public partial class RunningApps : TableLayoutPanel
{
public RunningApps()
{
InitializeComponent();
}
public RunningApps(IContainer container)
{
container.Add(this);
InitializeComponent();
this.ColumnStyles.Clear();
this.RowStyles.Clear();
this.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
this.HandleCreated += new EventHandler(this.Form_Load);
}
private void Form_Load(object sender, EventArgs e)
{
// Process list and spawn buttons
List<WindowData> ar = WindowsTasks.GetActiveTasks();
this.ColumnCount = ar.Count;
this.MinimumSize = new Size(50 * ar.Count, 54);
this.Size = new Size(50 * ar.Count, 54);
for (int i = 0; i < ar.Count; i++)
{
this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100 / this.ColumnCount));
Button button = new Button();
WindowData w = ar[i];
// Setup Button Style
button.Name = string.Format("Button_{0:D}", i);
button.Text = string.Format("Button_{0:D}", i);
button.BackColor = Color.Transparent;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
// Icon
button.Image = w.icon.ToBitmap();
button.ImageAlign = ContentAlignment.MiddleCenter;
// Sizes
button.MinimumSize = new Size(50, 54);
button.Margin = new Padding(5);
button.Size = new Size(50, 54);
// Utils
this.Controls.Add(button, i, 0);
}
}
}
}
The way buttons are exposed:
The function gives the running process that have "Graphics", add them all to Array ar. Then the for loop adds columns for each of the buttons and them other for loop add the buttons with the image
Tried all that I could found. Margins, Paddings and stuff seems to be only applied at the first Button.
The component is imported to a tablelayout at main Component
I'm trying to make a little game where you turn all panels green.
I do this by getting a 5x5 grid of panels, every panel has a 1/3 chance to be green, otherwise it will start as red.
my problem is that i do not have the slightest clue how to start the main problem.
when i click a panel, the panel above, left ,right and below need to change color aswell.
at the moment i do not know how to identify which panels are next to the one being clicked.
this is my code:
public partial class Form1 : Form
{
Panel[,] PanelArray = new Panel[5,5];
Random R = new Random();
int R1;
public Form1()
{
InitializeComponent();
for (int r = 0; r < 5; r++)
{
for (int c = 0; c < 5; c++)
{
R1 = R.Next(0, 3);
PanelArray[r, c] = new Panel
{
Size = new Size(50, 50),
Location = new Point(PanelContainer.Width / 5 * c, PanelContainer.Height / 5 * r),
BackColor = Color.Red,
BorderStyle = BorderStyle.Fixed3D
};
PanelArray[r, c].Click += new EventHandler(PanelArray_Click);
if (R1 == 1) PanelArray[r, c].BackColor = Color.Green;
PanelContainer.Controls.Add(PanelArray[r, c]);
}
}
}
private void PanelArray_Click(object sender, EventArgs e)
{
Panel P = (Panel)sender;
if (P.BackColor == Color.Red) P.BackColor = Color.Green;
else if (P.BackColor == Color.Green) P.BackColor = Color.Red;
if (CheckWin()) MessageBox.Show("test");
}
private bool CheckWin()
{
//foreach panel green blah blah
return false;
}
}
}`
You can use the Tag property in your Panel objects to store some information.
PanelArray[r, c] = new Panel
{
Size = new Size(50, 50),
Location = new Point(PanelContainer.Width / 5 * c, PanelContainer.Height / 5 * r),
BackColor = Color.Red,
BorderStyle = BorderStyle.Fixed3D,
Tag = (Row: r, Column: c)
};
In your PanelArray_Click method, you can get the indexes:
var indexes = ((int Row, int Column))P.Tag;
var row = indexes.Row;
var column = indexes.Column;
// Todo: your logic here
In the Tag property, you can store any object, so you can create some class to store data, if you need.
Other solution is two for loops, to get the indexes, like:
private (int Row, int Column) GetIndexes(Panel panel)
{
for (int x = 0; x < PanelArray.GetLength(0); x++)
{
for (int y = 0; y < PanelArray.GetLength(1); y++)
{
if (PanelArray[x, y] == panel)
{
return (x, y);
}
}
}
throw new Exception("Not found.");
}
And then you can use in your PanelArray_Click method:
var indexes = this.GetIndexes(P);
var row = indexes.Row;
var column = indexes.Column;
// Todo: your logic here
Here is easy trick to get row and column. Create a class that inherits the Panel and adds a row and column. See code below
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;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
MyPanel[,] PanelArray = new MyPanel[5, 5];
Random R = new Random();
int R1;
public Form1()
{
InitializeComponent();
for (int r = 0; r < 5; r++)
{
for (int c = 0; c < 5; c++)
{
R1 = R.Next(0, 3);
PanelArray[r, c] = new MyPanel
{
Size = new Size(50, 50),
Location = new Point(PanelContainer.Width / 5 * c, PanelContainer.Height / 5 * r),
BackColor = Color.Red,
BorderStyle = BorderStyle.Fixed3D,
row = r,
col = c
};
PanelArray[r, c].Click += new EventHandler(PanelArray_Click);
if (R1 == 1) PanelArray[r, c].BackColor = Color.Green;
PanelContainer.Controls.Add(PanelArray[r, c]);
}
}
}
private void PanelArray_Click(object sender, EventArgs e)
{
MyPanel P = sender as MyPanel;
int row = P.row;
int col = P.col;
if (P.BackColor == Color.Red) P.BackColor = Color.Green;
else if (P.BackColor == Color.Green) P.BackColor = Color.Red;
if (CheckWin()) MessageBox.Show("test");
}
private bool CheckWin()
{
//foreach panel green blah blah
return false;
}
}
public class MyPanel : Panel
{
public int row { get; set; }
public int col { get; set; }
}
}
I just want to create multiple web control using c# in visual studio. I have written the code for that but it create only once, I think it show the control created at the last in the loop.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MDMScreenSharing
{
public partial class Form2 : Form
{
private List<Skybound.Gecko.GeckoWebBrowser> geckowebbrouser;
public Form2()
{
InitializeComponent();
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
this.AutoSize = true;
this.Padding = new Padding(0, 0, 20, 20);
this.StartPosition = FormStartPosition.CenterScreen;
}
private void Form2_Load(object sender, EventArgs e)
{
int inputNumber =5;
geckowebbrouser = new List<Skybound.Gecko.GeckoWebBrowser>();
for (int i = 1; i <= inputNumber; i++)
{
int j = 1;
String wbname = "br" + i;
Skybound.Gecko.GeckoWebBrowser gw = new Skybound.Gecko.GeckoWebBrowser();
gw.Width = 200;
gw.Height = 200;
gw.Parent = panel1;
gw.Name = wbname;
gw.Location = new Point(gw.Width, panel1.Bottom + (i * 30));
gw.Navigate("http://192.168.1.162:8080");
geckowebbrouser.Add(gw);
this.Controls.Add(gw);
j = j*gw.Width;
}
}
}
}
This will show the web control created at the last. I think the program should be more dynamic for that. What am I doing wrong?
The form output, that show only once.
with the new addition of code i have code that one of you provided. the code is
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MDMScreenSharing
{
public partial class Form2 : Form
{
private List<Skybound.Gecko.GeckoWebBrowser> geckowebbrouser;
public Form2()
{
InitializeComponent();
// this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
// this.AutoSize = true;
//this.Padding = new Padding(0, 0, 20, 20);
// this.StartPosition = FormStartPosition.CenterScreen;
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(602, 395);
this.flowLayoutPanel1.TabIndex = 0;
}
private void Form2_Load(object sender, EventArgs e)
{
int inputNumber =4;
geckowebbrouser = new List<Skybound.Gecko.GeckoWebBrowser>();
for (int i = 1; i <= inputNumber; i++)
{
String wbname = "br" + i;
Skybound.Gecko.GeckoWebBrowser gw = new Skybound.Gecko.GeckoWebBrowser();
gw.Parent = flowLayoutPanel1;
gw.Width = 200;
gw.Height = 200;
gw.Name = wbname;
gw.Navigate("http://192.168.1.162:8080");
geckowebbrouser.Add(gw);
flowLayoutPanel1.Controls.Add(gw);
}
}
}
}
but the problem in this case only one browser window navigate the page.
like this
as you can see.
I think better approach will be using FlowLoayoutPanel so that you don't have to handle the position of each new control.
Go like this:
Add the FlowLayoutPanel through visual designer from toolbox.
Then on your designer.cs you should automatically have:
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(602, 395);
this.flowLayoutPanel1.TabIndex = 0;
FormLoad event:
private void Form1_Load ( object sender, EventArgs e )
{
int inputNumber = 5;
geckowebbrouser = new List<Skybound.Gecko.GeckoWebBrowser>();
for ( int i = 1; i <= inputNumber; i++ )
{
int j = 1;
String wbname = "br" + i;
var gw = new Skybound.Gecko.GeckoWebBrowser();
gw.Width = 300;
gw.Height = 300;
gw.Name = wbname;
geckowebbrouser.Add(gw);
flowLayoutPanel1.Controls.Add(gw);
gw.Navigate("http://www.google.com");
}
}
Update
The only difference from the WebBrowser implementation is that you need to call the Navigate method after you've added the control to the panel. Check the updated code above.
I have tested with default Skybound.Gecko.GeckoWebBrowser control too, and it's working just fine too:
I have a winforms application
Here is my code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication12
{
public partial class Form1 : Form
{
Graphics gr;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
gr = this.CreateGraphics();
MyLine myline = new MyLine();
myline.P1 = new Point(100, 0);
myline.P2 = new Point(200, 80);
gr.DrawLine(new Pen(Color.Red), myline.P1,myline.P2);
Rectangle r = new Rectangle(0, 0, 50, 50);
gr.DrawRectangle(new Pen(Color.Teal, 5), r);
if (r.Contains(0,25)) MessageBox.Show("within");
}
private void btnClear_Click(object sender, EventArgs e)
{
gr.Clear(this.BackColor);
}
}
}
class MyLine
{
public Point P1 {get; set;}
public Point P2 { get; set; }
}
My problem is this..
I can draw a rectangle, and I can see whether a point is within it.
So I could extend the program to say "yes" when a click on the form is within the rectangle. The Rectangle has a Contains function which is great.
But I want to do the same for Line.
The problem, is that winforms has no Line class. I could write my own Line class, but the problem remains.. how to find whether a click landed on it?
I notice that WPF has such a class How do I recognize a mouse click on a line?
But i'm using winforms.
Using GraphicsPath.IsOutlineVisible method you can determine whether the specified point is under the outline of the path when drawn with the specified Pen. You can set width of the pen.
So you can create a GraphicsPath and then add a line using GraphicsPath.AddLine to the path and check if the path contains the point.
Example:
The below method, checks if the p is on the line with end points p1 and p2 using the specified width.
You can use wider width to increase the tolerance or if the line is wider than 1:
//using System.Drawing;
//using System.Drawing.Drawing2D;
bool IsOnLine(Point p1, Point p2, Point p, int width = 1)
{
using (var path = new GraphicsPath())
{
using (var pen = new Pen(Brushes.Black, width))
{
path.AddLine(p1, p2);
return path.IsOutlineVisible(p, pen);
}
}
}
I implemented a simple Line class to check if a dot fall on the line.
You can capture a mouse position out of Form_Click event
Here's the snippet
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;
namespace WindowsFormsApplication
{
public partial class Form1 : Form
{
Line myLine;
int x1 = 10;
int x2 = 40;
int y1 = 0;
int y2 = 30;
public Form1()
{
InitializeComponent();
myLine = new Line() { Start = new Point(x1, y1), Stop = new Point(x2, y2), Epsilon = 10 };
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));
e.Graphics.DrawLine(pen, x1, y1, x2, y2);
pen.Dispose();
}
private void Form1_Click(object sender, EventArgs e)
{
MouseEventArgs me = (MouseEventArgs)e;
bool contain = myLine.contain(new Point(me.X,me.Y));
}
}
public class Line
{
public Point Start { get; set; }
public Point Stop { get; set; }
public float Epsilon { get; set; }
public bool contain(Point p)
{
// y = mx + c
float m = (Stop.Y - Start.Y) / (Stop.X - Start.X);
float c = Stop.Y - (m * Stop.X);
return p.X >= Math.Min(Start.X, Stop.X)
&& p.X <= Math.Max(Start.X, Stop.X)
&& p.Y >= Math.Min(Start.Y, Stop.Y)
&& p.Y <= Math.Max(Start.Y, Stop.Y)
&& Math.Abs(Math.Abs(p.Y) - Math.Abs((m * p.X) + c)) < epsilon; //with relax rules
//&& (p.Y == (m*p.X)+c); // strict version
}
}
UPDATE
careful of a case where X1 == X2. It will throw exception.
I am initiating me into programming thanks to Stack Overflow.
The game I'm doing in c #, consists of several bees flying around the desktop, which I have to give Click and SCORE is going to increase by a certain time.
To which I did the following:
Create a list PictureBox dynamically (at runtime): OK
Load PictureBox with these GIF images randomly: OK
![Bee Games][1]
In this part I was stuck:
Place these randomly PictureBox (in the bottom of the form).
Make the PictureBox move randomly (more or less marked routes).
each PictureBox Click Event, Change the PictureBox image and hide (visible = false), and increase in SCORE + 1.
I need help please.
My code is as follows:
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;
namespace MiPrimerJuego
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int x = 20;
int y = 600;
List<System.Windows.Forms.PictureBox> objeto = new List<PictureBox>();
for (int i = 0; i < 10; i++, x += 90)
{
PictureBox pBox = new PictureBox();
pBox.Height = 80;
pBox.Width = 50;
pBox.Location = new System.Drawing.Point(x, y);
objeto.Add(pBox);
pBox.SizeMode = PictureBoxSizeMode.StretchImage;
Controls.Add(pBox);
var rand = new Random();
var files = Directory.GetFiles(Application.StartupPath + #"/Images", "*.gif");
pBox.Image = System.Drawing.Bitmap.FromFile(files[rand.Next(files.Length)]);
}
}
}
}
Declare rand and files outside the for-loop and objeto outside the function/void as a Private member variable:
private List<PictureBox> objeto = new List<PictureBox>();
private void button1_Click(object sender, EventArgs e)
{
var files = Directory.GetFiles(Application.StartupPath + #"/Images", "*.gif");
int x = 20;
int y = 600;
var rand = new Random();
for (int i = 0; i < 10; i++)
{
x += 90;
PictureBox pBox = new PictureBox();
pBox.Height = 80;
pBox.Width = 50;
pBox.Location = new System.Drawing.Point(x, y);
objeto.Add(pBox);
pBox.SizeMode = PictureBoxSizeMode.StretchImage;
Controls.Add(pBox);
pBox.Image = System.Drawing.Bitmap.FromFile(files[rand.Next(files.Length)]);
}
}
}
Sorry, I did not explain properly.
What I do is this:
1 Make the PictureBox move randomly from the bottom of the form (more or less marked routes).
2 In the Click event of each PictureBox, Changing the PictureBox image and hide (visible = false), and increase in SCORE + 1.
My code is as follows:
using System;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
using System.IO;
namespaceMiPrimerJuego
{
publicpartialclassForm1 : Form
{
public Form1()
{
InitializeComponent();
}
privatevoid button1_Click(object sender, EventArgs e)
{
int x = 20;
int y = 600;
List<System.Windows.Forms.PictureBox>objeto = newList<PictureBox>();
for (inti = 0; i< 10; i++, x += 90)
{
PictureBoxpBox = newPictureBox();
pBox.Height = 80;
pBox.Width = 50;
pBox.Location = newSystem.Drawing.Point(x, y);
objeto.Add(pBox);
pBox.SizeMode = PictureBoxSizeMode.StretchImage;
Controls.Add(pBox);
var rand = newRandom();
var files = Directory.GetFiles(Application.StartupPath + #"/Images", "*.gif");
pBox.Image = System.Drawing.Bitmap.FromFile(files[rand.Next(files.Length)]);
}
}
}
}