Windows Forms, accessing picturebox from class in main form - c#

I'm making a game where I want to make things fall down and the player should try to catch it.
Currently, my items which are falling are drawn and made in a class separated from the main form, so when I try to access them from the main form where I control the gravitation.I can't seem to find the picturebox (picCoin).
Could you please take a look at my code and come with some solution?
This is the class were i create Coins
class Coin
{
private PictureBox picCoin = new PictureBox();
public Coin()
{
picCoin.BackColor = Color.Transparent;
picCoin.ImageLocation = #"C:\Users\sebfre1104\source\repos\SPEL\SPEL\Resources\hamburger.png";
picCoin.Width = 100;
picCoin.Height = 100;
picCoin.SizeMode = PictureBoxSizeMode.StretchImage;
}
public void DrawTo(Form f)
{
f.Controls.Add(picCoin);
}
public Rectangle getBounds()
{
return picCoin.Bounds;
}
public void setposition(int x, int y)
{
picCoin.Location = new Point(x, y);
}
}
i want to reach this picCoin in my main form so i can add gravity in private void TimerGravitation_Tick(object sender, EventArgs e)
public partial class Form1 : Form
{
bool IsJumping = false;
List<Coin> clist = new List<Coin>();
int poƤng = 0;
public Form1()
{
InitializeComponent();
}
private void TimerGravitation_Tick(object sender, EventArgs e)
{
if(!picSpelare.Bounds.IntersectsWith(picMark.Bounds) && IsJumping==false)
{
picSpelare.Top += 10;
}
}
I would be very grateful with any tips as this is my final project in class.

i dont know if i understanded question correctly but make picCoin public
make
private PictureBox picCoin = new PictureBox();
to
public PictureBox picCoin = new PictureBox();

At first, you should follow Umut Arpat's answer (turn picCoin from private to public).
Then you should initialize the Coin class in Form1 constructor like this:
private Coin _coin;
public Form1()
{
InitializeComponent();
_coin = new Coin();
}
And then you should add picture box from Coin class to list of Form1 controls like this:
this.Controls.Add(_coin.picCoin)
You can do that in Form1 constructor too.
Don't add PictureBox to Controls of the form from the Coin class (method DrawTo()).

class Coin
{
private PictureBox picCoin = new PictureBox();
public PictureBox Box {
get { return picCoin};
set { picCoin = value};
}
....
}
To use/access the box:
clist[i].Box // This is what you want

Related

How to save and open the content in the one of subforms separately?

There are two forms, a MainForm and a GraphicsForm.
In MainForm, there are "New" and "Save", "Open" buttons. When clicking the "New", a GraphicsForm created (When the "New" is clicked multiple times, multiple GraphicsForms are created).
The question is, when created multiple GraphicsForms, and the user only wants to save the content in one of them or open a content file to one of them, How to implement this?
MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private ToolStripMenuItem _winMenuItem = new ToolStripMenuItem();
private GraphicsForm _graphicsForm;
private int _counter = 1;
private ContentDoc _contentDoc = new ContentDoc();
private void New_Click(objec sender, EventArgs e)
{
_winMenuItem.Name = "Win";
_winMenuItem.Text = "Windows";
int item = MainMenuStrip.Items.IndexOf(_winMenuItem);
if (item == -1)
{
MainMenuStrip.Items.Add(_winMenuItem);
MainMenuStrip.MdiWindowListItem = _winMenuItem;
}
_graphicsForm = new GraphicsForm(_contentDoc);
_graphicsForm.Name = string.Concat("Win_", _counter.ToString());
_graphicsForm.Text = _graphicsForm.Name;
_graphicsForm.MdiParent = this;
_graphicsForm.Show();
_graphicsForm.WindowState = FormWindowState.Maximized;
_counter++;
}
private void Save_Click(object sender, EventArgs e)
{
... // here
}
private void Open_Click(object sender, EventArgs e)
{
... // here
}
}
GraphicsForm.cs
public partial class GraphicsForm : Form
{
//ContentDoc is a class to manage all the graphics drawn by the user in the form.
private ContentDoc _contentDoc = new ContentDoc();
public GraphicsForm(ContentDoc contentDoc)
{
InitializeComponent();
_contentDoc = contentDoc;
}
private Canvas_MouseDown()
{
}
private Canvas_Paint()
{
}
...
The parent form has an ActiveMdiChild property, so you can use the to access the currently-selected GraphicsForm instance:
var activeGraphicsForm = ActiveMdiChild as GraphicsForm;
There are other variations you might use, e.g. pattern matching, depending on the specific details and your preference.
You can then put your saving logic in a public method in GraphicsForm and call it from the parent form. Alternatively, you can put your saving logic in the parent form and expose the data to be saved via one or more public properties in GraphicsForm.

Create your own mouse event in a class

I haven't been learning C# for very long and was wondering if it is possible to create a mouse event from another class?
The intention is that when a mousedown happens, something is drawn on a panel. I would like to do all this from a different class is this possible?
This is what I've already tried:
class Circle: Form1
{
Graphics g;
Pen pen = new Pen(Color.Black);
// Making a event ?
public event EventHandler<MouseEventArgs> MouseDown;
protected void OnClick(MouseEventArgs e)
{
EventHandler<MouseEventArgs> handler = MouseDown;
if (handler != null)
{
handler(this, e);
}
}
public Circle()
{
g = this.panel1.CreateGraphics();
}
public void Mouse_Down(object sender, MouseEventArgs e)
{
// Draw something
g.DrawLine(pen, 0, 0, 50, 50);
}
}
}
So instead of calling the panel1_MouseDown event in this class I want to call it from the circle class:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
// So instead of calling the panel1_MouseDown event in this class I want to call it from the circle class
}
}
}
Yes, you can "do all this from a different class"
Referring to the the example below:
In Form1 constructor create initializes the instance of the Circle class and passes to its constructor an instance of Form1.
Make sure that the control you want to draw on is public (panel1 in the example).
Add MouseDown and Paint events to panel1.
Always use the Paint event to draw graphics - it's the best practice.
More info on Control.Paint Event please: read here
Form1:
public partial class Form1 : Form
{
Circle circle;
public Form1()
{
InitializeComponent();
// Start the measuring time for reauthentication
circle = new Circle(this);
}
}
Circle Class:
class Circle
{
private Form1 Instance;
public Circle(Form1 instance)
{
this.Instance = instance;
// Make sure the access modifier of panel1 is Public and add mousedown event
Instance.panel1.MouseDown += panel1_MouseDown;
// Add a paint event - this is the best practice to draw graphics
Instance.panel1.Paint += panel1_Paint;
}
private int X;
private int Y;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
this.X = e.X;
this.Y = e.Y;
// Redraw the panel when mouse is down
Instance.panel1.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (this.X > 0 && this.Y > 0)
{
Graphics g = e.Graphics;
Pen p = new Pen(Color.Red);
g.DrawEllipse(p, X, Y, 50, 50);
}
}
}
Output:

C# - Keeping the values from functions

I want to call a function like Spawn() in this case, but without losing values from it after calling it (for example, I want entityPicture to still be available after I call Spawn(), so I can use it later on MainWindow_KeyDown() function). Same with X and other variables like that.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace EpicGame
{
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
}
public void MainWindow_Load(object sender, EventArgs e)
{
int EntityCount = 0;
Background.ImageLocation = "Background.jpg";
Background.SizeMode = PictureBoxSizeMode.AutoSize;
Spawn(600, 600, EntityCount, "Player 1.png"); EntityCount++;
}
// Controls
public void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.D) MoveRight();
entityPicture.Location = new Point(X, Y);
}
// Movement
public void MoveRight()
{
X++;
}
// Entity spawning
public void Spawn(int X, int Y, int ID, string Path)
{
PictureBox entityPicture = new PictureBox();
Image Entity = Image.FromFile(Path);
entityPicture.Image = Entity;
entityPicture.SizeMode = PictureBoxSizeMode.AutoSize;
entityPicture.Location = new Point(X, Y);
entityPicture.BackColor = Color.Transparent;
Controls.Add(entityPicture);
entityPicture.BringToFront();
}
private void Background_Click(object sender, EventArgs e)
{
}
}
}
You can declare it public in the form class like:
public partial class MainWindow : Form
{
PictureBox entityPicture = new PictureBox();
}
I don't know the type of entityPicture so just used PictureBox as example, you use the correct type.
Your root issue is one of scope. Have a look at this video, it walks through your exact issue: https://www.youtube.com/watch?v=NemPMKTxM7w
You can technically move entityPicture to the top of the class, however given this appears to be a WinForms window, I would add the PictureBox via the designer so it's only declared once. If you declare it at the class level and reinitialize it in Spawn (i.e. = new PictureBox()) repeatedly, you're going to create a memory leak.

How to share declaration of integer between two forms?

I am currently making some basic incremental game in c# in WFA. Here's the code:
namespace Xadrs
{
public partial class Form1 : Form
{
public void Ref()
{
label2.Text = Points.ToString();
button2.Text = "Level up! (" + Upgradeprice.ToString() + ")";
label4.Text = Upgrade.ToString();
label6.Text = Upgradeautoclick.ToString();
button4.Text = "Level up PPS! (" + Upgradeautoclickprice.ToString() + ")";
}
public int ach_beginner = 0;
public int ach_intermediate = 0;
public int ach_expert = 0;
public int ach_master = 0;
int Points = 0;
int Upgrade = 1;
int Upgradeautoclick = 0 ;
int Upgradeautoclickprice = 110;
int Upgradeprice = 25;
public Form1()
{
InitializeComponent();
Ref();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (Upgrade == 5)
{
Points++;
Ref();
}
}
private void button1_Click(object sender, EventArgs e)
{
Points += Upgrade;
Ref();
}
private void button2_Click(object sender, EventArgs e)
{
if (Points >= Upgradeprice)
{
Upgrade += 1;
Points -= Upgradeprice;
Upgradeprice += Upgradeprice / 4;
}
else
{
MessageBox.Show("Not Enough Nico points...");
}
Ref();
if (Upgrade == 5)
{
MessageBox.Show("Beginner: Reach 5 PPS.\nReward: AutoClick!", "ACHIEVEMENT UNLOCKED!");
ach_beginner = 1;
timer1.Enabled = true;
Upgradeautoclick = 1;
button4.Visible = true;
Ref();
}
}
Form2 achievements = new Form2();
private void button3_Click(object sender, EventArgs e)
{
Form2.Show();
}
private void button4_Click(object sender, EventArgs e)
{
if (Points >= Upgradeautoclickprice)
timer1.Interval = timer1.Interval / 2;
Points -= Upgradeautoclickprice;
Upgradeautoclickprice += Upgradeautoclickprice;
}
and in form2 I want to have:
if (ach_beginner = 1)
{
//Text in this label = something like: Beginner - Reach 5 Points per click
labelwithachievement.Visible = true;
}
but the ach_beginner isn't declared in form2. I would like to somehow "connect" this integer to have its declaration from form1 in form2.
Don't think of it as sharing the integer itself, instead think of it as Form2 has a dependency on something in Form1.
Since the variable is currently public (we'll get to that in a minute), at the simplest all you need to do is provide Form2 with a reference to the instance of Form1. Put a property on Form2 and require a value in its constructor:
private Form1 form1Instance;
public Form2(Form1 form1)
{
this.form1Instance = form1;
}
Then when you create an instance of Form2, pass it a reference to the current instance of Form1:
Form2 achievements = new Form2(this);
Then in Form2 you can refer to its new member variable to get information from Form1:
if (this.form1Instance.ach_beginner == 1)
Note regarding public variables... It's generally considered best practice to expose properties publicly instead of variables. So replace this:
public int ach_beginner = 0;
with this:
public int Ach_Beginner { get; set; }
And update references to it accordingly. There are a variety of reasons for this, but ultimately the idea is that a class should hide its values and provide access to them rather than just provide the values themselves.
This is a pretty simple start to the idea of providing a dependency to an object, and there are a number of places you can go from here. For example, if you don't want to pass around entire forms as dependencies (since they include considerably more data/functionality than is otherwise needed for the dependency), you can encapsulate your values in an object of their own and pass around that object as the dependency.
Extrapolating from there, you can continue to separate business logic from UI elements (like forms and controls), and begin to move your logic into those business logic objects and components. This will make your logic more portable onto other UI platforms, easier to test, etc.
For example, suppose you have a class such as:
public class LevelInfo // guessing on an appropriate name here
{
public int Ach_Beginner { get; set; }
public int Ach_Intermediate { get; set; }
public int Ach_Expert { get; set; }
public int Ach_Master { get; set; }
}
Then in Form1 you use that object instead:
private LevelInfo levelInfo = new LevelInfo();
// elsewhere...
levelInfo.Ach_Beginner = 1;
// etc.
Then Form2 can require a reference to that object:
private LevelInfo levelInfo;
public Form2(LevelInfo level)
{
this.levelInfo = level;
}
and use that object:
if (this.levelInfo.Ach_Beginner == 1)
At this point LevelInfo is de-coupled from the UI and can contain portable business logic/information.
All you need is a Parameter. You call the Form2.Show Method. As any other Method a method of Form2 can become a parameter. So in Form2 you could do the following:
public void Show(int ach_beginner)
{
//Do sth. with your int
this.Show();
}
If you call Form2 on Form1 now you can pass your integer:
private void button3_Click(object sender, EventArgs e)
{
Form2.Show(ach_beginner);
}
I think this is the easiest approach. Instead of overriding the Show Method you could make a Property as well. In Form2 declare:
public int AchBeginner {get;set;}
In Form1 you set this value before you call the Show Method:
private void button3_Click(object sender, EventArgs e)
{
Form2.AchBeginner = ach_beginner;
Form2.Show();
}
As David explained in comments, the value won't be updated on Form2. If you want to achieve this you could use an Interface:
public interface IBeginner
{
int AchBeginner{get;set;}
}
public void Form1 : Form, IBeginner
{
public int AchBeginner{get;set;}
//The place you create Form2
Form2.Beginner = this;
}
public void Form2 : Form
{
public IBeginner Beginner{get;set;}
//Here you can access
int achBeginner = Beginner.AchBeginner:
}
UPDATE
Based on the comment from the question author i think an event would be the most usefull think. So you can tell your Form2 that your character on Form1 reaches level 5. For example:
public class LevelEventArgs : EventArgs
{
public int Level {get;}
public LevelEventArgs(int level)
{
Level = level;
}
}
//Form1 need to implement an Event which later can notify any subscriber (Form2 in this case)
public class Form1 : Form
{
public event EventHandler<LevelEventArgs> LevelUp;
//When your character reach new level do following:
LevelUp?.Invoke(this, new LevelEventArgs(ach_beginner));
//Show Form2
Form2 form = new Form2(this);
form.Show();
}
Form2 needs to subscribe this event now. For this you need to put Form1 to Form2 (or better an Interface as described above)
public class Form2 : Form
{
public Form2(Form form1)
{
//Register Event LevelUp from Form1
form1.LevelUp += (args) =>
{
if (args.Level == 5)
//Level 5 reached
}
}
}

C# Adding controls to a form from another class

Every time I create a new instance of Player I want to do the following code
private void button1_Click(object sender, EventArgs e)
{
Player Player1 = new Player();
}
Player class
{
public Player()
{
Form1.AddControls(someControl)
}
}
I can't seem to do anything to do with form1 e.g. textbox1.text = "Test". I assume this is a scope issue but I can't find an answer on the internet. Does anyone know how I can access + add controls to my form1 through a class?
Thank you for your time.
It's not entirely clear what you're trying to do. It sounds like you want to add controls from the Player class into the form that you're calling from like this:
public class Form1 : Form
{
public void SomeMethod()
{
Player player1 = new Player(this);
}
}
public class Player()
{
public Player(Form form)
{
Textbox tb = new Textbox();
form.Controls.Add(tb);
}
}

Categories

Resources