I have program that is some kind of testing. I keep questions in panel, but when I run my program, it show the middle of panel. How to make it show the beginning of the panel?
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
Dictionary<string, bool> answers = new Dictionary<string,bool>();
for (int j = 0; j < 4; j++)
{
string ans = "Відповідь " + (j+1);
bool flag = false;
if( i > 5)
{
if( j == 0 || j == 2)
{
flag = true;
}
}else
if (j == 0)
{
flag = true;
}
answers.Add(ans, flag);
}
string q_text = "Питання № " + (i+1);
this.AddQuestion(q_text, answers);
}
panel1.ScrollControlIntoView(panel1.Controls[0]);
}
Try to set focus on the first control in the panel on Form_Load event:
panel1.Controls[0].Select();
You could use:
The ScrollControlIntoView method:
panel.ScrollControlIntoView(panel.Controls[0]);
Panel's VerticalScroll property:
panel.VerticalScroll.Value = 0;
Related
the problem i'm facing right now is that i don't know how to check on the opponent's move which ships it sinks so i can display a message saying "Your ____ has sunk".
this is the code i have written
namespace Naval
{
public partial class Form2 : Form
{
const int Size_grid = 10;
const int picturebox = 50;
PictureBox[,] playerBoard = new PictureBox[Size_grid, Size_grid];
PictureBox[,] opponentBoard = new PictureBox[Size_grid, Size_grid];
int[,] playerShips = new int[Size_grid, Size_grid];
int[,] opponentShips = new int[Size_grid, Size_grid];
int[] Lengths = new int[] { 5, 4, 3, 2 };
//string[] Names = new string[] { "Αεροπλανοφόρο", "Αντιτορπιλικό", "Πολεμικό", "Υποβρύχιο" };
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
for (int row = 0; row < Size_grid; row++)
{
for (int col = 0; col < Size_grid; col++)
{
PictureBox playerPictureBox = new PictureBox();
playerPictureBox.Size = new Size(picturebox, picturebox);
playerPictureBox.Location = new Point(col * (picturebox + 10) + 185, row * (picturebox + 10) + 245);
playerPictureBox.Click += PictureBox_Click;
playerPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
playerPictureBox.BackColor = Color.Gray;
panel1.Controls.Add(playerPictureBox);
playerBoard[row, col] = playerPictureBox;
}
}
for (int row = 0; row < Size_grid; row++)
{
for (int col = 0; col < Size_grid; col++)
{
PictureBox opponentPictureBox = new PictureBox();
opponentPictureBox.Size = new Size(picturebox, picturebox);
opponentPictureBox.Location = new Point(col * (picturebox + 10) + 1145, row * (picturebox + 10) + 245);
opponentPictureBox.Click += PictureBox_Click;
opponentPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
opponentPictureBox.BackColor = Color.Gray;
panel1.Controls.Add(opponentPictureBox);
opponentBoard[row, col] = opponentPictureBox;
}
}
PlacePlayerShips(playerShips, Lengths);
PlaceOpponentShips(opponentShips, Lengths);
}
private void PictureBox_Click(object sender, EventArgs e)
{
PictureBox pictureBox = (PictureBox)sender;
int row = (pictureBox.Location.Y - 245) / (picturebox + 10);
int col = (pictureBox.Location.X - 1145) / (picturebox + 10);
if (pictureBox.Location.X >= 1145 && pictureBox.ImageLocation == null) // opponent board
{
if (row >= 0 && row < opponentShips.GetLength(0) && col >= 0 && col < opponentShips.GetLength(1))
{
if (opponentShips[row, col] > 0)
{
pictureBox.ImageLocation = "x.png";
}
else
{
pictureBox.ImageLocation = "-.png";
}
ComputerMove();
}
}
}
private void ComputerMove()
{
Random random = new Random();
int row = random.Next(Size_grid);
int col = random.Next(Size_grid);
while (playerBoard[row, col].ImageLocation != null)
{
row = random.Next(Size_grid);
col = random.Next(Size_grid);
}
if (playerShips[row, col] > 0)
{
playerBoard[row, col].ImageLocation = "x.png";
}
else
{
playerBoard[row, col].ImageLocation = "-.png";
}
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
private void PlacePlayerShips(int[,] playerShips, int[] shipLengths)
{
Random random = new Random(DateTime.Now.Millisecond);
foreach (int shipLength in shipLengths)
{
int row, col;
int direction = random.Next(2);
int placed = 0;
while (placed == 0)
{
if (direction == 0) // Horizontal
{
row = random.Next(Size_grid);
col = random.Next(Size_grid - shipLength + 1);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (playerShips[row, col + i] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
playerShips[row, col + i] = 1;
playerBoard[row, col + i].BackColor = Color.LightBlue;
}
}
}
else // Vertical
{
row = random.Next(Size_grid - shipLength + 1);
col = random.Next(Size_grid);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (playerShips[row + i, col] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
playerShips[row + i, col] = 1;
playerBoard[row + i, col].BackColor = Color.LightBlue;
}
}
}
// Change direction if ship couldn't be placed
if (placed == 0)
{
direction = (direction + 1) % 2;
}
}
}
}
private void PlaceOpponentShips(int[,] opponentShips, int[] shipLengths)
{
Random random = new Random(DateTime.Now.Millisecond);
;
foreach (int shipLength in shipLengths)
{
int row, col;
int direction = random.Next(2);
int placed = 0;
while (placed == 0)
{
if (direction == 0) // Horizontal
{
row = random.Next(Size_grid);
col = random.Next(Size_grid - shipLength + 1);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (opponentShips[row, col + i] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
opponentShips[row, col + i] = 1;
}
}
}
else // Vertical
{
row = random.Next(Size_grid - shipLength + 1);
col = random.Next(Size_grid);
// Check if ship overlaps with other ships
int overlap = 0;
for (int i = 0; i < shipLength; i++)
{
if (opponentShips[row + i, col] == 1)
{
overlap = 1;
}
}
// Place ship if no overlap
if (overlap == 0)
{
placed = 1;
for (int i = 0; i < shipLength; i++)
{
opponentShips[row + i, col] = 1;
}
}
}
// Change direction if ship couldn't be placed
if (placed == 0)
{
direction = (direction + 1) % 2;
}
}
}
}
private void label1_Click(object sender, EventArgs e)
{
}
int time = 0;
private void timer1_Tick(object sender, EventArgs e)
{
time++;
label42.Text= time.ToString();
}
private void timer2_Tick(object sender, EventArgs e)
{
label44.Text = " ";
timer2.Enabled = false;
}
}
}
i tried adding a switch with choices 1-4 but it didn't work i've also tried having a int[] ship Hits = new int[] {0,0,0,0} and just adding 1 every time a ship was hit but that didn't go as planned because i didn't know how to bind each item of the array to a ship . and i think that's about it
One approach that you might find helpful would be to bundle up all the information about a Ship into a class. This is an abstraction that could make it easier for displaying ship names when they are sunk. At the same time, use inheritance so that a Ship is still a PictureBox with all the functionality that implies.
Ship minimal class example
Member properties tell us what we need know about a ship. Use enum values to make the intent perfectly clear.
class Ship : PictureBox
{
#region P R O P E R T I E S
[Description("Type")]
public τύπος τύπος
{
get => _τύπος;
set
{
if (!Equals(_τύπος, value))
{
_τύπος = value;
switch (_τύπος)
{
case τύπος.Αεροπλανοφόρο: Image = Image.FromFile(Path.Combine(_imageDir, "aircraft-carrier.png")); break;
case τύπος.Αντιτορπιλικό: Image = Image.FromFile(Path.Combine(_imageDir, "destroyer.png")); break;
case τύπος.Πολεμικό: Image = Image.FromFile(Path.Combine(_imageDir, "military.png")); break;
case τύπος.Υποβρύχιο: Image = Image.FromFile(Path.Combine(_imageDir, "submarine.png")); break;
}
}
}
}
τύπος _τύπος = 0;
public bool Sunk { get; set; }
[Description("Flag")]
public σημαία σημαία
{
get => _σημαία;
set
{
_σημαία = value;
onUpdateColor();
}
}
σημαία _σημαία = σημαία.Player;
#endregion P R O P E R T I E S
private void onUpdateColor()
{
var color =
Sunk ? Color.Red :
σημαία.Equals(σημαία.Player) ?
Color.Navy :
Color.DarkOliveGreen;
for (int x = 0; x < Image.Width; x++) for (int y = 0; y < Image.Height; y++)
{
Bitmap bitmap = (Bitmap)Image;
if (bitmap.GetPixel(x, y).R < 0x80)
{
bitmap.SetPixel(x, y, color);
}
}
Refresh();
}
public Point[] Hits { get; set; } = new Point[0];
public override string ToString() =>
$"{σημαία} {τύπος} # {((TableLayoutPanel)Parent)?.GetCellPosition(this)}";
private readonly static string _imageDir =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
}
Where enum values are:
enum Direction
{
Horizontal,
Vertical,
}
enum τύπος
{
[Description("Aircraft Carrier")]
Αεροπλανοφόρο = 5,
[Description("Destroyer")]
Αντιτορπιλικό = 4,
[Description("Military")]
Πολεμικό = 3,
[Description("Submarine")]
Υποβρύχιο = 2,
}
/// <summary>
/// Flag
/// </summary>
enum σημαία
{
Player,
Opponent,
}
Displaying ships names when they are sunk
When the inherited Ship version of PictureBox is clicked the information is now available.
private void onAnyShipClick(object sender, EventArgs e)
{
if (sender is Ship ship)
{
MessageBox.Show(ship.ToString());
}
}
Images credit: Robuart
Used under license.
I'm trying to give the letters in my richtextbox different colors for my subnet calculator, but the richtextbox doesn't change the colors until the 26th letter.
How it looks:
int iValueSm = trackBarSmMask.Value;
rtbScroll.Text = "";
rtbScroll.SelectionStart = rtbScroll.TextLength;
rtbScroll.SelectionLength = 0;
for (int i = 1; i <= iValueSm; i++)
{
rtbScroll.SelectionColor = Color.Blue;
rtbScroll.AppendText("N");
if (i%8==0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
for (int i = iValueSm+1; i <= 32; i++)
{
rtbScroll.SelectionColor = Color.Red;
rtbScroll.AppendText("H");
if (i % 8 == 0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
labelAmountNetID.Text = "/" + iValueSm.ToString();
Well, can be a lot of approaches to deal with this problem but here is one suggestion:
// Track bar definitions...
private void SetTrackBarVals()
{
trackBar1.Minimum = 0;
trackBar1.Maximum = 31;
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
var counter = 0;
var dotsCounter = 0;
rtbScroll.Text = "";
int iValueSm = trackBar1.Value + 1; // +1 because we start counting from 0
for (int i = 1; i <= 32; i++)
{
if (counter > 0 && counter % 8 == 0)
{
// new octet
rtbScroll.AppendText(".");
dotsCounter++;
}
if (i > iValueSm)
{
// It is red
rtbScroll.AppendText("H");
rtbScroll.SelectionStart = (i - 1) + dotsCounter;
rtbScroll.SelectionLength = 1 ;
rtbScroll.SelectionColor = Color.Red;
}
else
{
rtbScroll.AppendText("N");
}
counter++;
}
}
Anytime you set the .Text() property, you RESET all formatting back to black and white.
Here is how I'd write it using SelectedText:
private void Form1_Load(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_ValueChanged(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_Scroll(object sender, EventArgs e)
{
updateRTB();
}
private void updateRTB()
{
rtbScroll.Text = "";
rtbScroll.SelectionStart = 0;
rtbScroll.SelectionLength = 0;
int iValueSm = trackBarSmMask.Value;
labelAmountNetID.Text = "/" + iValueSm.ToString();
for (int i = 1; i <= 32; i++)
{
rtbScroll.SelectionColor = (i <= iValueSm) ? Color.Blue : Color.Red;
rtbScroll.SelectedText = (i <= iValueSm) ? "N" : "H";
if (i % 8 == 0 && i != 32)
{
rtbScroll.SelectionColor = Color.Black;
rtbScroll.SelectedText = ".";
}
}
}
I wrote a C# Windows Form program, the effect which I want is in the below.
When the users click the All checkbox, and all the checkboxs of the row will be checked. On the other hand, if the user click the All checkbox again, all the checkbox of the row will be unchecked. In addition, if the user unckeck any checkbox(exclusive All checkbox), the All checkbox have to be unchecked. However, the CellValueChanged will be invoked when the value of the any box changed. It is difficult to handle. And, I always get infinite loop by my code. Can Anybody can fix it? Thanks a lot!!
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1 && e.RowIndex >= 0)
{
if (Convert.ToBoolean(dataGridView1.Rows[e.RowIndex].Cells[1].Value))
{
//check all the Checkboxs
for (int i = 2; i < 26; i++)
dataGridView1.Rows[e.RowIndex].Cells[i].Value = true;
//if the other row all checked, unchecked it all
for(int i = 0; i < dataGridView1.Rows.Count; i++)
{
if (i == e.RowIndex)
continue;
if(Convert.ToBoolean(dataGridView1.Rows[i].Cells[1].Value))
{
for(int j = 1; j < dataGridView1.Rows[i].Cells.Count; j++)
{
dataGridView1.Rows[i].Cells[j].Value = false;
}
}
}
}
else
for (int i = 2; i < 26; i++)
dataGridView1.Rows[e.RowIndex].Cells[i].Value = false;
}
else if(e.ColumnIndex > 1 && e.RowIndex >= 0)
{
bool flag = true;
for (int i = 2; i < dataGridView1.Rows[e.RowIndex].Cells.Count; i++)
{
if (!Convert.ToBoolean(dataGridView1.Rows[e.RowIndex].Cells[i].Value))
flag = false;
}
if (flag)
dataGridView1.Rows[e.RowIndex].Cells[1].Value = false;
else
dataGridView1.Rows[e.RowIndex].Cells[1].Value = true;
}
}
The problem of the infinite loop is that dataGridView1_CellValueChanged call itself each time.
I suggest to add Lock(object) to dataGridView1_CellValueChanged, in this case the call that check if all the rows all check or not will not invoked until all the check boxes marked as checked.
I'm making this pacman console based game, in which there is a 40x40 board. There are pacmans and enemies on the board eating food. pacman is represented by 0 and enemy by #. Everytime there position changes the display function gets called, which in current logic, after every second clears the whole console and reprints each element on the board.. but this way, there are these jerks whenever whole board gets displayed. Kindly tell me a better way to achieve a smooth motion of paacman and enemy, ideally i should only change only the position of pacman and enemy, but i need to clear the console in order to show the grid on the same spot, otherwise it will just keep scrolling down. The code for display function is below:
public static void display()
{
Console.Clear();
for (int i = 0; i < 40; i++)
{
for (int j = 0; j < 40; j++)
{
bool packFound = false;
bool enmFound = false;
foreach (Packman element in myVers.packmans)
{
if (element.x == i && element.y == j)
{
packFound = true;
break;
}
}
foreach (Packman element in myVers.enemys)
{
if (element.x == i && element.y == j)
{
enmFound = true;
break;
}
}
if (packFound == true)
{
Console.Write('0');
myVers.board[i, j] = ' ';
}
else if (enmFound == true)
{
myVers.board[i, j] = ' ';
Console.Write('#');
}
else
{
Console.Write(myVers.board[i, j]);
}
}
Console.Write('\n');
}
//Console.Write("\nFood Count " + myVers.foodCount + "\n");
}
What if you would only redraw the characters that really changed? Maybe with use of Console.SetCursorPosition
Try building the String for the board first then pass the whole thing to the console at one time. Still perform the clear operation.
This would be a job for:
String Builder
public static void display()
{
var boardStr = new StringBuilder();
for (int i = 0; i < 40; i++)
{
for (int j = 0; j < 40; j++)
{
bool packFound = false;
bool enmFound = false;
foreach (Packman element in myVers.packmans)
{
if (element.x == i && element.y == j)
{
packFound = true;
break;
}
}
foreach (Packman element in myVers.enemys)
{
if (element.x == i && element.y == j)
{
enmFound = true;
break;
}
}
if (packFound == true)
{
boardStr.Append("0");
myVers.board[i, j] = ' ';
}
else if (enmFound == true)
{
myVers.board[i, j] = ' ';
boardStr.Append("#");
}
else
{
boardStr.Append(myVers.board[i, j].ToString());
}
}
boardStr.Append("\n");
}
//Console.Write("\nFood Count " + myVers.foodCount + "\n");
Console.Clear();
Console.Write(boardStr.ToString());
}
So, I am trying to emulate the minesweeper game in winforms, just as an exercise. So far I have two classes, one called "Cell" which derives from regular button class, but has few properties of its own and a class that handles the logic (basically I made a two-dimensional array filled with objects of type "Cell" and populate it with bombs). I ran into a problem - how do I attach my array of "Cell" button controls to the form? Without re-writing everything from scratch? Both classes are unfinished obviously, it's just that I wanted to check how it would look on a form and realized that I am stuck.
Here is my Cell class
class Cell : Button
{
//private GraphicsPath path;
const int width = 20;
const int height = 20;
public byte Value { get; set; }
public bool IsBomb { get; set; }
public Cell()
{
}
public Cell(int x, int y)
{
this.Location = new Point(x, y);
}
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
this.Width = width;
this.Height = height;
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
this.Text = Value.ToString();
}
}
And here is my array class
class CellArray
{
private int _rows = 0;
private int _columns = 0;
private int _bombAmount = 0;
private Random rand;
private Cell[,] cellMatrix;
public CellArray(int rows, int columns, int bombAmount)
{
_rows = rows;
_columns = columns;
_bombAmount = bombAmount;
populate();
setBombs();
}
private void populate()
{
cellMatrix = new Cell[_rows, _columns];
for (int i = 1; i < _rows; i++)
{
for (int j = 1; j < _columns; j++)
{
cellMatrix[i, j] = new Cell();
cellMatrix[i, j].IsBomb = false;
}
}
}
private void setBombs()
{
//*****************************************QUESTIONABLE************************************
rand = new Random();
int k = 1;
while (k < _bombAmount)
{
Flag:
{
int i = rand.Next(_rows);
int j = rand.Next(_columns);
if (cellMatrix[i, j].IsBomb == false)
cellMatrix[i, j].IsBomb = true;
else
goto Flag;
}
}
//*****************************************QUESTIONABLE************************************
for (int i = 1; i < _rows; i++)
{
for (int j = 1; j < _columns; j++)
{
if (cellMatrix[i - 1, j - 1].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i - 1, j].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i, j - 1].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i - 1, j + 1].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i, j + 1].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i + 1, j + 1].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i + 1, j].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
if (cellMatrix[i + 1, j - 1].IsBomb == true)
{
cellMatrix[i, j].Value++;
}
}
}
}
}
how do I attach my array of "Cell"
button controls to the form
This issue can be solved similar to this one:
Using programatically created CheckBoxes in Windows Form [C#]
The idea is to use YourForm.Controls.Add(...). Don't forget to provide proper locations for your cells/buttons within the forms coordinate system.
Of course, I would like to mention that IMHO deriving Cell from Button is a horrible design decision. Better separate your data classes (like Cell) completely from the GUI classes (like Button) and choose a technique like the one Asher suggested in his first answer (add a cell to the Tag property of each Button) to create a connection between Cell objects and corresponding Button objects.