I need to add PictureBox's (pictureBox11 to pictureBox30) to an array.
So instead of adding PictureBox's like this:
PictureBox[] Coins = new PictureBox[20];
Coins[0] = pictureBox11;
...
Coins[19] = pictureBox30;
I wrote a for cycle like this (DOESN'T WORK) :
for (int i = 11; i < 31; i++)
{
for (int j = 0; j < Coins.Length; j++)
{
Coins[j] = (PictureBox)Controls.Find(
"pictureBox" + i.ToString(), true)[0];
}
}
There might be a small stupid mistake somewhere because I use the same cycle for another thing and it works, idk, maybe I'm just blind and cant see the mistake.
Maybe it is relevant, so I will include the code I am assigning for the array elements:
for (int i = 0; i < Coins.Length; i++)
{
if (player.Bounds.IntersectsWith(Coins[i].Bounds))
{
Coins[i].Visible = false;
}
}
EVERYTHING works fine if I add them as shown in first code, but it is not very practical.
Why isn't the second code (the for cycle) I wrote working for me?
Is there a better way to add multiple pictureboxes to an array?
I am guessing you are making this more complicated than it has to be. To try and understand better, I assume that when you say I need to add pictureboxes (pictureBox11 to pictureBox30) to an array. that you mean there are 30+ PictureBoxs on your form and each PictureBox uses a naming convention such that each is named “pictureBoxX” where “X” is 1,2,3…30,31. Then you want to get a (consecutive?) group of “PictureBoxes” on the form to make invisible. I hope this is correct.
To simply make the picture boxes invisible, I do not think an array is needed. Simply loop through the picture boxes and make it invisible if the name matches a string of the form “pictureBoxX “. I used IndexsAreValid method to validate the start and end indexes. It is also used in the code for an array implementation below this code.
Make PictureBoxes invisible without an array
private void SetPictureBoxesInvisible(int start, int end) {
int size = -1;
string targetString = "";
if (IndexsAreValid(start, end, out size)) {
for (int i = start; i < end + 1; i++) {
try {
targetString = "pictureBox" + i;
PictureBox target = (PictureBox)Controls.Find(targetString, true)[0];
if (target != null) {
target.Visible = false;
}
}
catch (IndexOutOfRangeException e) {
return;
}
}
}
}
If you must have a PictureBox array returned, then the code below should work.
First, to get an array of PictureBoxs as you want you need an array to store them. But first you need to know how big to make it. From your posted code it appears that you want to get picture boxes 11-30 and put them in an array. So we can get the size from these numbers… i.e. 30-11=19 +1 = 20. That’s about all you need. Simply create the array and loop through all the picture boxes and grab pictureBox11-pictureBox30. When done we can use this array to make these `PictureBoxes” invisible.
I created a method IsValidPic similar to a tryParse to validate if the given index (1,2,3..30) is valid. If it is out of range, I simply ignore that value. This gives you the ability to grab an individual picture box in case the desired picture boxes are not contiguous. I used a few buttons to test the methods.
Hope this helps.
private PictureBox[] GetPictureBoxes(int start, int end) {
int size = - 1;
if (IndexsAreValid(start, end, out size)) {
PictureBox curPic = null;
PictureBox[] allPics = new PictureBox[size];
int index = 0;
for (int i = start; i <= end; i++) {
if (IsValidPic(i, out curPic)) {
allPics[index] = curPic;
index++;
}
}
return allPics;
}
else {
return new PictureBox[0];
}
}
private Boolean IndexsAreValid(int start, int end, out int size) {
if (start < 1 || end < 1) {
size = -1;
return false;
}
if (start > end) {
size = -1;
return false;
}
size = end - start + 1;
return true;
}
private Boolean IsValidPic(int index, out PictureBox picture) {
string targetName = "pictureBox" + index;
try {
PictureBox target = (PictureBox)Controls.Find(targetName, true)[0];
if (target != null) {
picture = target;
return true;
}
picture = null;
return false;
}
catch (IndexOutOfRangeException e) {
picture = null;
return false;
}
}
private void ResetAll() {
foreach (PictureBox pb in this.Controls.OfType<PictureBox>()) {
pb.Visible = true;
}
}
private void button1_Click(object sender, EventArgs e) {
TurnInvisible(2, 3);
}
private void button3_Click(object sender, EventArgs e) {
TurnInvisible(11, 30);
}
private void button4_Click(object sender, EventArgs e) {
TurnInvisible(1,7);
}
private void TurnInvisible(int start, int end) {
PictureBox[] pictureBoxesToChange = GetPictureBoxes(start, end);
foreach (PictureBox pb in pictureBoxesToChange) {
if (pb != null)
pb.Visible = false;
}
}
private void button2_Click(object sender, EventArgs e) {
ResetAll();
}
Related
I'm a teacher with a very limited programming background struggling with C# to make some videos for my students who are pretty much anxious and depressed during the pandemic. I'm using GTA5 as my platform because it is easy to customize, has amazing locations, hundreds of potential characters, and supports voice as well (I'm using Amazon Polly). Needlessly to say I'm stripping out all the violence and swearing.
The roadblock I'm hitting, and there isn't any support to speak of on any GTA forums or Mods forums, is how to display lines of text on the screen on demand. I've managed to do this hardcoded, but I would prefer to read this from a text file and display line by line, not by a timer, but on demand with a single key binding, ideally with the ability to go back and forth (but line by line).
A friend of mine who works for a AAA gaming company, doesn't know the GTA5 environment but said the solution would be to read the lines into an array. Unfortunately I don't have that programming knowledge, so I'm stuck at this point. Here is my code. Right now it will only display the last line of a test text file. Code is put together from Microsoft documentation and random GTA forum posts. Again, I can do this manually through multiple hardcoded lines of text, each with a key bind, but that's totally impractical. Need text file, one keybinding and a way go line by line (and ideally backwards)
using System;
using System.Drawing;
using System.Windows.Forms;
using GTA;
using GTA.Math;
using GTA.Native;
namespace TextDrawing
{
public class TextDraw : Script
{
public static string TextString { get; set; }
public TextDraw()
{
Tick += onTick;
Interval = 0;
KeyDown += Basics_KeyDown;
}
private void onTick(object sender, EventArgs e)
{
if (Game.IsLoading) return;
DrawText();
}
private void DrawText()
{
var pos = new Point(100, 100);
// TextString = "Default Start Screen goes here if you want it on load";
var Text4Screen = new GTA.UI.TextElement(TextString, pos, 0.35f, Color.White, GTA.UI.Font.ChaletLondon, GTA.UI.Alignment.Left, true, false, 1000); //last parameter is wrap width
Text4Screen.Enabled = true;
Text4Screen.Draw();
}
private void Basics_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.NumPad7) //code replace code in Basics_Tick
{
string[] lines = System.IO.File.ReadAllLines
(#"C:\Users\UserName\test.txt");
foreach (string line in lines)
{
TextString = line; //"Lesson 1 Topics Today. \n\n Part 1. Drawing Text on Screen \n\n Part 2. Customizations" + TextString2;
DrawText();
}
}
}
}
}
There are many ways to do this. But a few key code changes should make it work.
Create two class-level variables, an array to keep all the read files and an int index to keep track of your current index.
Create a function to read and invoke that in the constructor (ideally it should not be read in the constructor but rather triggered by external user action. But let's keep it simple for now).
In the key press event, update the string and increase the index. Your code is currently not working because you are iterating through the entire array and assigning text to a single variable. So only the last value is remains on screen.
public class TextDraw : Script
{
public static string TextString { get; set; }
public string[] AllLines { get; set; }
public int currentIndex = 0;
public TextDraw()
{
Tick += onTick;
Interval = 0;
KeyDown += Basics_KeyDown;
ReadAllLines(); ///Ideally not here. But should work still.
}
private void ReadAllLines()
{
AllLines = System.IO.File.ReadAllLines (#"C:\Users\UserName\test.txt");
}
private void onTick(object sender, EventArgs e)
{
if (Game.IsLoading) return;
DrawText();
}
private void DrawText()
{
var pos = new Point(100, 100);
// TextString = "Default Start Screen goes here if you want it on load";
var Text4Screen = new GTA.UI.TextElement(TextString, pos, 0.35f, Color.White, GTA.UI.Font.ChaletLondon, GTA.UI.Alignment.Left, true, false, 1000); //last parameter is wrap width
Text4Screen.Enabled = true;
Text4Screen.Draw();
}
private void Basics_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.NumPad7) //code replace code in Basics_Tick
{
if (currentIndex >= 0 && currentIndex < AllLines.Length)
{
TextString = AllLines[currentIndex];
}
else
{
TextString = "The End";
}
currentIndex++;
DrawText();
}
}
}
I'm not familiar with GTA scripting, but maybe create a member variable: int index = 0; Then use that to figure out which line to print in DrawText():
namespace TextDrawing
{
public class TextDraw : Script
{
// The lines of the text file
string [] lines;
// The index of the next line to print
int index = 0;
public TextDraw()
{
Tick += onTick;
Interval = 0;
KeyDown += Basics_KeyDown;
// Read the file here
lines = System.IO.File.ReadAllLines(#"C:\Users\UserName\test.txt");
}
private void onTick(object sender, EventArgs e)
{
if (0 == lines.Length || Game.IsLoading) return;
DrawText();
}
private void DrawText()
{
var pos = new Point(100, 100);
// Get next line
string textString = lines[index];
var Text4Screen = new GTA.UI.TextElement(textString, pos, 0.35f, Color.White, GTA.UI.Font.ChaletLondon, GTA.UI.Alignment.Left, true, false, 1000);
Text4Screen.Enabled = true;
Text4Screen.Draw();
}
private void Basics_KeyDown(object sender, KeyEventArgs e)
{
// When Keys.NumPad7 is pressed, show next line
if (e.KeyCode == Keys.NumPad7)
{
if (index < lines.Length - 1) index++;
}
// When Keys.NumPad8 is pressed, show previous line
else if (e.KeyCode == Keys.NumPad8)
{
if (index > 0) index--;
}
}
}
}
Updated to use onTick and go backwards. Apparently the onTick is needed to continually redraw the text. Being unfamiliar with the GTA API, I did not realize that.
I have a PictueBox and I have some dice, I would like to play an animation for the "rolling" of the dice, I did a .gif with the dice, but after the dice stop rolling, I want the actual dice number that I got, I have a random funcion that handles that.
My question is, I press the "Roll Dice" button, it plays the animation and after the animation ends I should set int the picturebox the dice that actually came. but it immediately chnages to the dice number that actually came, skipping the animation;
This is how it works:
dice1.Image = Resources.DiceAnimation; //Here the gif is called to be played
int x = rollDice(); //Here I roll the dice
switch (x){
case 1: dice.Image = resources.diceFace1; //Image set depending on x
break
case 2: //etc...
}
There might be two things needed to do that.
Firstly, you may need to ensure that your PictureBox receives a gif image and it knows it. To do this, please check this answer and this answer. The posts have code to show GifImage frame by frame:
public class GifImage
{
private Image gifImage;
private FrameDimension dimension;
private int frameCount;
private int currentFrame = -1;
private bool reverse;
private int step = 1;
public GifImage(string path)
{
gifImage = Image.FromFile(path);
//initialize
dimension = new FrameDimension(gifImage.FrameDimensionsList[0]);
//gets the GUID
//total frames in the animation
frameCount = gifImage.GetFrameCount(dimension);
}
public bool ReverseAtEnd {
//whether the gif should play backwards when it reaches the end
get { return reverse; }
set { reverse = value; }
}
public Image GetNextFrame()
{
currentFrame += step;
//if the animation reaches a boundary...
if (currentFrame >= frameCount || currentFrame < 1) {
if (reverse) {
step *= -1;
//...reverse the count
//apply it
currentFrame += step;
}
else {
currentFrame = 0;
//...or start over
}
}
return GetFrame(currentFrame);
}
public Image GetFrame(int index)
{
gifImage.SelectActiveFrame(dimension, index);
//find the frame
return (Image)gifImage.Clone();
//return a copy of it
}
}
Use it like this (note that you need a Timer object):
private GifImage gifImage = null;
private string filePath = #"C:\Users\Jeremy\Desktop\ExampleAnimation.gif";
public Form1()
{
InitializeComponent();
//a) Normal way
//pictureBox1.Image = Image.FromFile(filePath);
//b) We control the animation
gifImage = new GifImage(filePath);
gifImage.ReverseAtEnd = false; //dont reverse at end
}
private void button1_Click(object sender, EventArgs e)
{
//Start the time/animation
timer1.Enabled = true;
}
//The event that is animating the Frames
private void timer1_Tick(object sender, EventArgs e)
{
pictureBox1.Image = gifImage.GetNextFrame();
}
Secondly, to know how long you want to run your GIF image, you may need to Get Frame Duration of GIF image like this:
double delayIn10Ms; //declare somewhere
//Initialize on your form load
PropertyItem item = img.GetPropertyItem (0x5100); // FrameDelay in libgdiplus
// Time is in 1/100th of a second
delayIn10Ms = (item.Value [0] + item.Value [1] * 256) * 10;
Then use the delayIn10Ms time plus, probably, a little bit more time to stop your timer. You may also want to check when was the last time your timer Ticks and store it. If it exceeds the given delay time, then you should stop your timer and start it again on dice roll, after image assignment in your switch case.
DateTime currentTick = DateTime.Min;
DateTime startTick = DateTime.Min;
private void timer1_Tick(object sender, EventArgs e)
{
currentTick = DateTime.Now;
if ((currentTick - startTick).TotalSeconds / 100 < delayIn10Ms)
pictureBox1.Image = gifImage.GetNextFrame();
else
timer1.Stop(); //stop the timer
}
//And somewhere else you have
timer1.Start(); //to start the timer
int x = rollDice(); //Here I roll the dice
switch (x){
case 1: dice.Image = resources.diceFace1; //Image set depending on x
break
case 2: //etc...
}
You can make a timer with the Interval property set to the length of the animation and set it's Tag to 0 and in the timer write the code:
if(timer.Tag == "0")
timer.Tag == "1";
else if(timer.Tag == "1")
{
int x = rollDice();
switch (x)
{
case 1: dice.Image = resources.diceFace1; break;
case 2: //etc...
}
timer.Tag == "0";
timer.Stop();
}
I'm developing a theatre reservation software. I'm using Windows Forms, the seats is represented by a 2-dimensioned array. And I draw the buttons as following:
public void DrawSeats()
{
// pnl_seats is a Panel
pnl_seats.Controls.Clear();
// Here I store all Buttons instance, to later add all buttons in one call (AddRange) to the Panel
var btns = new List<Control>();
// Suspend layout to avoid undesired Redraw/Refresh
this.SuspendLayout();
for (int y = 0; y < _seatZone.VerticalSize; y++)
{
for (int x = 0; x < _seatZone.HorizontalSize; x++)
{
// Check if this seat exists
if (IsException(x, y))
continue;
// Construct the button with desired properties. SeatSize is a common value for every button
var btn = new Button
{
Width = SeatSize,
Height = SeatSize,
Left = (x * SeatSize),
Top = (y * SeatSize),
Text = y + "" + x,
Tag = y + ";" + x, // When the button clicks, the purpose of this is to remember which seat this button is.
Font = new Font(new FontFamily("Microsoft Sans Serif"), 6.5f)
};
// Check if it is already reserved
if (ExistsReservation(x, y))
btn.Enabled = false;
else
btn.Click += btn_seat_Click; // Add click event
btns.Add(btn);
}
}
// As said before, add all buttons in one call
pnl_seats.Controls.AddRange(btns.ToArray());
// Resume the layout
this.ResumeLayout();
}
But already with a seat zone of 20 by 20 (400 buttons), it spent almost 1 minute to draw it, and in debug I checked that the lack of performance, is the instantiation of the buttons.
There is a way to make it faster? Perhaps disable all events during the instatiation or another lightweight Control that has the Click event too?
UPDATE:
lbl was a test, the correct is btn, sorry.
UPDATE 2:
Here is the IsException and ExistsReservations methods:
private bool IsException(int x, int y)
{
for (var k = 0; k < _seatsExceptions.GetLength(0); k++)
if (_seatsExceptions[k, 0] == x && _seatsExceptions[k, 1] == y)
return true;
return false;
}
private bool ExistsReservation(int x, int y)
{
for (var k = 0; k < _seatsReservations.GetLength(0); k++)
if (_seatsReservations[k, 0] == x && _seatsReservations[k, 1] == y)
return true;
return false;
}
Suppose that you change your arrays for reservations and exclusions to
public List<string> _seatsExceptions = new List<string>();
public List<string> _seatsReservations = new List<string>();
you add your exclusions and reservations in the list with something like
_seatsExceptions.Add("1;10");
_seatsExceptions.Add("4;19");
_seatsReservations.Add("2;5");
_seatsReservations.Add("5;5");
your checks for exclusions and reservations could be changed to
bool IsException(int x, int y)
{
string key = x.ToString() + ";" + y.ToString();
return _seatsExceptions.Contains(key);
}
bool ExistsReservation(int x, int y)
{
string key = x.ToString() + ";" + y.ToString();
return _seatsReservations.Contains(key);
}
of course I don't know if you are able to make this change or not in your program. However consider to change the search on your array sooner or later.
EDIT I have made some tests, and while a virtual grid of 20x20 buttons works acceptably well (31 millisecs 0.775ms on average), a bigger one slows down noticeably. At 200x50 the timing jumps to 10 seconds (1,0675 on average). So perhaps a different approach is needed. A bound DataGridView could be a simpler solution and will be relatively easy to handle.
I also won't use such a myriad of controls to implement such a thing. Instead you should maybe create your own UserControl, which will paint all the seats as images and reacts on a click event.
To make it a little easier for you i created such a simple UserControl, that will draw all the seats and reacts on a mouse click for changing of the state. Here it is:
public enum SeatState
{
Empty,
Selected,
Full
}
public partial class Seats : UserControl
{
private int _Columns;
private int _Rows;
private List<List<SeatState>> _SeatStates;
public Seats()
{
InitializeComponent();
this.DoubleBuffered = true;
_SeatStates = new List<List<SeatState>>();
_Rows = 40;
_Columns = 40;
ReDimSeatStates();
MouseUp += OnMouseUp;
Paint += OnPaint;
Resize += OnResize;
}
public int Columns
{
get { return _Columns; }
set
{
_Columns = Math.Min(1, value);
ReDimSeatStates();
}
}
public int Rows
{
get { return _Rows; }
set
{
_Rows = Math.Min(1, value);
ReDimSeatStates();
}
}
private Image GetPictureForSeat(int row, int column)
{
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
return Properties.Resources.emptySeat;
case SeatState.Selected:
return Properties.Resources.choosenSeat;
default:
case SeatState.Full:
return Properties.Resources.fullSeat;
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
var row = (int)(e.X / widthPerSeat);
var column = (int)(e.Y / heightPerSeat);
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
_SeatStates[row][column] = SeatState.Selected;
break;
case SeatState.Selected:
_SeatStates[row][column] = SeatState.Empty;
break;
}
Invalidate();
}
private void OnPaint(object sender, PaintEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
for (int row = 0; row < Rows; row++)
{
for (int column = 0; column < Columns; column++)
{
var seatImage = GetPictureForSeat(row, column);
e.Graphics.DrawImage(seatImage, row * widthPerSeat, column * heightPerSeat, widthPerSeat, heightPerSeat);
}
}
}
private void OnResize(object sender, System.EventArgs e)
{
Invalidate();
}
private void ReDimSeatStates()
{
while (_SeatStates.Count < Rows)
_SeatStates.Add(new List<SeatState>());
if (_SeatStates.First().Count < Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count < Columns)
columnList.Add(SeatState.Empty);
while (_SeatStates.Count > Rows)
_SeatStates.RemoveAt(_SeatStates.Count - 1);
if (_SeatStates.First().Count > Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count > Columns)
columnList.RemoveAt(columnList.Count - 1);
}
}
This will currently draw forty rows and columns (so there are 800 seats) and you can click on each seat to change its state.
Here are the images i used:
EmtpySeat:
ChoosenSeat:
FullSeat:
If you anchor this control and resize it or you click on a seat to change its state there can be some minor lacking for the repainting if you further increase the number of rows or columns, but that is still somewhere far below one second. If this still hurts you, you have to improve the paint method and maybe check the ClipRectangle property of the paint event and only paint the really needed parts, but that's another story.
Rather than using actual button controls, just draw the image of the seats then when the user clicks on a seat translate the mouse X,Y coordinates to determine which seat was clicked. This will be more efficient. Of course, the drawback is that you have to write the method to translate x,y coordinates to a seat, but that really isn't that difficult.
EDIT; it has been pointed out to me this will not work in Windows Forms!
Well, you are Sequentially working through it.
if one iteration costs 1 sec, the full process will take 400*1 in time.
Perhaps you should try and make a collection of your objects, and process it 'parallel'.
try the .Net framework (4 and above) 'parallel foreach' method:
http://msdn.microsoft.com/en-s/library/system.threading.tasks.parallel.foreach(v=vs.110).aspx
edit: so, if you have a list buttonnames, you can say
buttonNames.ForEach(x=>CreateButton(x));
while your CreateButton() method is as following:
private Button CreateButton(string nameOfButton) { Button b = new
Button(); b.Text = nameOfButton; //do whatever you want...
return b; }
When i drag one picturebox, it drags both of mine. Because in the pbxMap_DragDrop method i have to call both of the methods that should fire when i drag one.
private void pbxMap_DragDrop(object sender, DragEventArgs e)
{
myDetectMouse.setMinotaur(e, myMap.myCells);
myDetectMouse.setTheseus(e, myMap.myCells);
}
SetTheseus:
public void setTheseus(DragEventArgs e, List<Cell> cells)
{
for (int i = 0; i < cells.Count; i++)
{
int[] mapData = myMapController.getMapData(i, cells);
int column = mapData[0];
int row = mapData[1];
int right = mapData[2];
int bottom = mapData[3];
Point RelativeMouseLoc = myMapController.myMap.myForm.pbxMap.PointToClient(Cursor.Position);
if (RelativeMouseLoc.X > column &&
RelativeMouseLoc.X < column + myMapController.myMap.myCellSize
&& RelativeMouseLoc.Y > row && RelativeMouseLoc.Y <
row + myMapController.myMap.myCellSize)
{
myMapController.myMap.myCells[i].hasTheseus = true;
}
else
{
myMapController.myMap.myCells[i].hasTheseus = false;
}
}
}
SetMinotaur is much the same but replace hasTheseus with hasMinotaur. As soon as a cell "hasTheseus" or "hasMinotaur" it will be drawn to the cell.
So it draws them both when i drag one because they both get set in pbxMap_DragDrop.
I thought i could have multiple event handlers for pbxMap_DragDrop depending on which picturebox was dragged.
You can check the sender parameter to determine whether you want to move the minotaur or Theseus. It would look something like this:
var pic = (PictureBox)sender;
if (pic.Name == "minotaur")
{
myDetectMouse.setMinotaur(e, myMap.myCells);
}
else
{
myDetectMouse.setTheseus(e, myMap.myCells);
}
If you don't want to use the Name property, you can use something else like the Tag property - just make sure you set it for each of the PictureBox objects.
I have problem with my C# WinForms project. I have a function that should change the place of buttons if they touch each other. For example, if I have btn1 at oldloction = (4,2) and btn2 at oldlocaction (2,6), then if I will move the buttons and they will touch bt1 new location = (2,6) and bt2 new location = (4,2)
now i did that with 2 buttons and it works.
locationx - means the x location on the button and its orgenize firat place of the location feat to the first buttons[0], the second feat to locationx[1] = buttons[1].location.x;
location - works the same ass locationx but uts the y locaion.
private void myText_MouseUp(object sender, MouseEventArgs e)
{
Point oldlocation = new Point(locationx[0], locationy[0]);
Point oldlocation2 = new Point(locationx[1], locationy[1]);
if (buttons[0].Location.Y == buttons[1].Location.Y)
{
buttons[1].Location = oldlocation;
buttons[0].Location = oldlocation2;
}
}
When I tried to make that as a global function it doesn't work and I don't know why.
This is the code of the global function that doesn't work:
private void myText_MouseUp(object sender, MouseEventArgs e)
{
for (int i = 0; i < counter; i++)
{
Point oldlocation = new Point(locationx[i], locationy[i]);
for (int j = 0; j < counter; j++)
{
if (i != j)
{
Point oldlocation2 = new Point(locationx[j], locationy[j]);
if (buttons[i].Location.Y != buttons[j].Location.Y)
{
buttons[j].Location = oldlocation2;
buttons[i].Location = oldlocation;
}
else if (buttons[i].Location.Y == buttons[j].Location.Y)
{
buttons[j].Location = oldlocation;
buttons[i].Location = oldlocation2;
}
}
}
}
}
Try using the button event for when it is pressed to call the function, rather than creating your own.
If the second function is not part of the control or form containing the buttons, it won't have a way to access the buttons array or locationx and locationy. You may need to pass these values as arguments to your function or ensure that they are provided as members of the class containing the second function. Note that generally a utility function would not take in "sender" and "MouseEventArgs" - pass only the specific data that the utility function needs to do its job.