I am very new to visual C#
I want to make a ticket booking system (like in cinemas), I have created the seats using panel, each seating is 40 * 40
Here's my code:
private void panel2_Paint(object sender, PaintEventArgs e)
{
int a, b;
for (a = 0; a <= 1; a++)
{
for (b = 0; b < 12; b++)
{
Graphics g = e.Graphics;
g.FillRectangle(new SolidBrush(Color.White), b * 40, a * 40, 40, 40);
g.DrawRectangle(new Pen(Color.Black), b * 40, a * 40, 40, 40);
}
}
}
Now I want to change the color of each seating by a mouse click to show what seat has been selected; but so far no luck
You would be better off creating seperate controls for each of your selected seats and handling their Click events. In this example I added 24 PictureBox's to the Panel. I then placed their index in the Tag Property of the Control and attached a common Click Event Handler. I am also using a Bool array to keep track of selected status.
public partial class Form1 : Form
{
bool[] selected = new bool[24];
public Form1()
{
InitializeComponent();
foreach (PictureBox pb in panel1.Controls)
{
pb.Click += new EventHandler(pictureBox_Click);
}
}
private void pictureBox_Click(object sender, EventArgs e)
{
PictureBox pb = (PictureBox)sender;
int index ;
if (int.TryParse(pb.Tag.ToString(), out index))
{
if (selected[index])
{
selected[index] = false;
pb.BackColor = Color.White;
}
else
{
selected[index] = true;
pb.BackColor = Color.Red;
}
}
}
}
You can use what you have if you create a boolean array to store the state of the Seat, use the Panel's MouseDown Event to set the variable and Invalidate the screeen rectangle that is accociated with your seat.
Something like this.
public partial class Form1 : Form
{
bool[,] selected = new bool[2,12];
public Form1()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
int a, b;
for (a = 0; a <= 1; a++)
{
for (b = 0; b < 12; b++)
{
if (selected[a, b])
{
e.Graphics.FillRectangle(new SolidBrush(Color.Red), b * 40, a * 40, 40, 40);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(Color.White ), b * 40, a * 40, 40, 40);
}
e.Graphics.DrawRectangle(new Pen(Color.Black), b * 40, a * 40, 40, 40);
}
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
int xPos, yPos;
xPos = e.X / 40;
yPos = e.Y / 40;
if ((xPos > 11) || (yPos > 1)) return;
if(selected[yPos,xPos])
selected[yPos, xPos] = false;
else
selected[yPos, xPos] = true;
((Panel)sender).Invalidate(new Rectangle(xPos * 40,yPos *40,40,40)) ;
}
}
Rather than using a Graphics object and drawing directly to the form, you may be able to get away with simply setting the BackColor property of the control that corresponds to the selected seat when the OnMouseClick event fires.
Related
I just need to show scrollbars on forms if my shape height is greater than the form height. That way, when the user scrolls down, it can show the end of the shape.
This is my code:
public partial class Form1: Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
}
private void Form1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawLine(new Pen(Color.Black, 2), 100, 50, 100, 1000);
//if line height > form height then show scroll bars
}
}
You need to enable the AutoScroll property of the form, use the AutoScrollPosition coordinates in drawings, and set the AutoScrollMinSize property to contain your shapes:
In the constructor add:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AutoScroll = true;
}
}
and the painting routine:
private void Form1_Paint(object sender, PaintEventArgs e)
{
using (Matrix m = new Matrix(1, 0, 0, 1, AutoScrollPosition.X, AutoScrollPosition.Y))
{
var sY = VerticalScroll.Value;
var sH = ClientRectangle.Y;
var w = ClientRectangle.Width - 2 - (VerticalScroll.Visible ? SystemInformation.VerticalScrollBarWidth : 0);
var h = ClientRectangle.Height;
var paintRect = new Rectangle(0, sY, w, h); //This will be your painting rectangle.
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Transform = m;
g.Clear(BackColor);
using (Pen pn = new Pen(Color.Black, 2))
e.Graphics.DrawLine(pn, 100, 50, 100, 1000);
sH += 1050; //Your line.y + line.height
//Likewise, you can increase the w to show the HorizontalScroll if you need that.
AutoScrollMinSize = new Size(w, sH);
}
}
Good Luck.
Here is the following rectangle below:
When I resize the form, I need this rectangle to match the size of the form.
When changing the width of the rectangle, do not interfere with its visibility within the form.
I'm using the following:
Note:
I did the rectangle manually, but if you have rectangle ready, better yet!
public Form1()
{
InitializeComponent();
this.Paint += Form1_Paint;
this.rectangles = new Dictionary<string, Rectangle>();
this.sizeScreen = this.Size;
this.sizeRectangles = new Size(8, 8);
this.brush = new SolidBrush(Color.Red);
FillLeft();
FillRight();
FillUp();
FillDown();
}
private Size sizeScreen;
private Size sizeRectangles;
private SolidBrush brush;
private Dictionary<string, Rectangle> rectangles;
private void FillLeft()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeScreen.Height,
Width = this.sizeRectangles.Width,
X = 0,
Y = this.sizeRectangles.Height
};
this.rectangles.Add("left", rectangle);
}
private void FillRight()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeScreen.Height,
Width = this.sizeRectangles.Width,
X = this.sizeScreen.Width - (this.sizeRectangles.Width * 5),
Y = this.sizeRectangles.Height
};
this.rectangles.Add("right", rectangle);
}
private void FillUp()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeRectangles.Height,
Width = this.sizeScreen.Width,
X = 0,
Y = this.sizeRectangles.Height
};
this.rectangles.Add("up", rectangle);
}
private void FillDown()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeRectangles.Height,
Width = this.sizeScreen.Width,
X = 0,
Y = this.sizeScreen.Height - (this.sizeRectangles.Height * 11)
};
this.rectangles.Add("down", rectangle);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int i = 0; i < this.rectangles.Count; i++)
{
e.Graphics.FillRectangles(this.brush, this.rectangles.Values.ToArray());
}
}
I want to set the rectangle on the form when it is resized
This is the way I'm creating the rectangle, but it does not stay right on the screen, to resize it I do not know
I think this would simplify what you are trying to do:
const int PenWidth = 10;
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = this.ClientRectangle;
Pen pen = new Pen(Color.Red, PenWidth);
e.Graphics.DrawRectangle(pen, r);
}
You could even add a margin:
const int PenWidth = 10;
const int PenMargin = 10;
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = this.ClientRectangle;
r.Inflate(-PenMargin, -PenMargin);
Pen pen = new Pen(Color.Red, PenWidth);
e.Graphics.DrawRectangle(pen, r);
}
To prevent traces (suggested by Wyck):
private void Form1_Resize(object sender, EventArgs e)
{
Invalidate();
}
Handle the Resize event and call Invalidate in the handler. Create a Pen of the desired color and width and set its Alignment to Inset. Handle the Paint event and in the handler call DrawRectangle passing in the ClientRectangle of the form.
Here is an example.
const float borderWidth = 8.0f;
Pen borderPen = new Pen(Color.Red, borderWidth) { Alignment = System.Drawing.Drawing2D.PenAlignment.Inset };
public Form2()
{
InitializeComponent();
this.Paint += Form2_Paint;
this.Resize += Form2_Resize;
}
private void Form2_Resize(object sender, EventArgs e)
{
Invalidate();
}
private void Form2_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(borderPen, this.ClientRectangle);
}
Apply the following fixes to the code:
Set ResizeRedraw property of the form to true. It sets the underlying style for the form so by each resize it sends the paint message and you don't need to handle Resize event.
Use DrawRectangle and draw using wide pen. So you don't need to fill multiple rectangles.
Set the PenAlignment to Inset. So you don't need to calculate the location of rectangle.
Do dispose the pen when you don't need it.
Example
public Form1()
{
InitializeComponent();
ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var pen = new Pen(Color.Red, PenWidth))
{
pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
e.Graphics.DrawRectangle(pen, ClientRectangle);
}
}
i have used this on my current project. when ever you resize the form, it will automatically resize all the object inside your form
i have class named clsResize and i call this on the form load.
1st you have to initialize the class inside the form then create 2 new method.
see example below
public partial class frmNewForm : Form
{
clsResize _form_resize;
public string selectedProd;
public frmNewForm()
{
InitializeComponent();
_form_resize = new clsResize(this);
this.Load += _Load;
this.Resize += _Resize;
}
private void _Load(object sender, EventArgs e)
{
_form_resize._get_initial_size();
}
private void _Resize(object sender, EventArgs e)
{
_form_resize._resize();
}
}
and here is the class that i used.
public class clsResize
{
List<System.Drawing.Rectangle> _arr_control_storage = new List<System.Drawing.Rectangle>();
private bool showRowHeader = false;
public clsResize(Form _form_)
{
form = _form_; //the calling form
_formSize = _form_.ClientSize; //Save initial form size
_fontsize = _form_.Font.Size; //Font size
}
private float _fontsize { get; set; }
private System.Drawing.SizeF _formSize {get;set; }
private Form form { get; set; }
public void _get_initial_size() //get initial size//
{
var _controls = _get_all_controls(form);//call the enumerator
foreach (Control control in _controls) //Loop through the controls
{
_arr_control_storage.Add(control.Bounds); //saves control bounds/dimension
//If you have datagridview
if (control.GetType() == typeof(DataGridView))
_dgv_Column_Adjust(((DataGridView)control), showRowHeader);
}
}
public void _resize() //Set the resize
{
double _form_ratio_width = (double)form.ClientSize.Width /(double)_formSize.Width; //ratio could be greater or less than 1
double _form_ratio_height = (double)form.ClientSize.Height / (double)_formSize.Height; // this one too
var _controls = _get_all_controls(form); //reenumerate the control collection
int _pos = -1;//do not change this value unless you know what you are doing
try
{
foreach (Control control in _controls)
{
// do some math calc
_pos += 1;//increment by 1;
System.Drawing.Size _controlSize = new System.Drawing.Size((int)(_arr_control_storage[_pos].Width * _form_ratio_width),
(int)(_arr_control_storage[_pos].Height * _form_ratio_height)); //use for sizing
System.Drawing.Point _controlposition = new System.Drawing.Point((int)
(_arr_control_storage[_pos].X * _form_ratio_width), (int)(_arr_control_storage[_pos].Y * _form_ratio_height));//use for location
//set bounds
control.Bounds = new System.Drawing.Rectangle(_controlposition, _controlSize); //Put together
//Assuming you have a datagridview inside a form()
//if you want to show the row header, replace the false statement of
//showRowHeader on top/public declaration to true;
if (control.GetType() == typeof(DataGridView))
_dgv_Column_Adjust(((DataGridView)control), showRowHeader);
//Font AutoSize
control.Font = new System.Drawing.Font(form.Font.FontFamily,
(float)(((Convert.ToDouble(_fontsize) * _form_ratio_width) / 2) +
((Convert.ToDouble(_fontsize) * _form_ratio_height) / 2)));
}
}
catch(Exception e)
{
MessageBox.Show(e.Message);
return;
}
}
private void _dgv_Column_Adjust(DataGridView dgv, bool _showRowHeader) //if you have Datagridview
//and want to resize the column base on its dimension.
{
int intRowHeader = 0;
const int Hscrollbarwidth = 5;
if (_showRowHeader)
intRowHeader = dgv.RowHeadersWidth;
else
dgv.RowHeadersVisible = false;
for (int i = 0; i < dgv.ColumnCount; i++)
{
if (dgv.Dock == DockStyle.Fill) //in case the datagridview is docked
dgv.Columns[i].Width = ((dgv.Width - intRowHeader) / dgv.ColumnCount);
else
dgv.Columns[i].Width = ((dgv.Width - intRowHeader - Hscrollbarwidth) / dgv.ColumnCount);
}
}
private static IEnumerable<Control> _get_all_controls(Control c)
{
return c.Controls.Cast<Control>().SelectMany(item =>
_get_all_controls(item)).Concat(c.Controls.Cast<Control>()).Where(control =>
control.Name != string.Empty);
}
}
I recently started "learning" C#. Currently i am doing a some sort of a game for school project. I want to draw a circle on a form. I added a time every new circle is drawn every 1000 ms on a random place in form. But when i start my form nothing really happens.
namespace Vezba_4
{
public partial class Form1 : Form
{
// attempt is when you try to "poke" the circle
bool attempt = false;
int xc, yc, Br = 0, Brkr = 0;
Random R = new Random();
public Form1()
{
InitializeComponent();
timer1.Start();
}
// Br is the number of circles that player has successfully "poked". And Brkr is a total number of circles that have appeared on the game screen. the
private void timer1_Tick(object sender, EventArgs e)
{
Refresh();
SolidBrush cetka = new SolidBrush(Color.Red);
Graphics g = CreateGraphics();
xc = R.Next(15, ClientRectangle.Width - 15);
yc = R.Next(15, ClientRectangle.Height - 15);
g.FillEllipse(cetka, xc - 15, yc - 15, 30, 30);
Brkr++;
Text = Br + "FROM" + Brkr;
attempt = false;
g.Dispose();
cetka.Dispose();
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (attempt == false)
{
if ((e.X - xc) * (e.X - xc) + (e.Y - yc) * (e.Y - yc) <= 225) Br++;
Text = Br + " FROM " + Brkr++;
}
attempt = true;
}
What is in the InitializeComponent method generated in the designer Form1.Designer.cs?
Is the event handler for the timer tick there?
//
// timer1
//
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
Edit:
For the mousedown would have to confirm that the handler is there in Form.Designer.cs as well:
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown);
Here's the properties of the timer I used, I dont have a timer.Start() anyway, it's all just your code with the Enabled property set to true, and the interval 1000. [I noticed when I copied nothing happened, but when I set Enabled to true it started to appear.
You should draw your circle in Form1_Paint. Because it will be drawn only when Paint event fired, and when fired, it looks for Form1_Paint.
public partial class Form1 : Form
{
bool attempt = false;
int xc, yc, Br = 0, Brkr = 0;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (attempt == false)
{
if ((e.X - xc) * (e.X - xc) + (e.Y - yc) * (e.Y - yc) <= 225) Br++;
Text = Br + " FROM " + Brkr++;
}
attempt = true;
}
public void Paaint()
{
SolidBrush cetka = new SolidBrush(Color.Red);
Graphics g = CreateGraphics();
xc = R.Next(15, ClientRectangle.Width - 15);
yc = R.Next(15, ClientRectangle.Height - 15);
g.FillEllipse(cetka, xc - 15, yc - 15, 30, 30);
Brkr++;
label1.Text = Br + "FROM" + Brkr;
attempt = false;
g.Dispose();
cetka.Dispose();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Paaint();
}
private void timer1_Tick(object sender, EventArgs e)
{
Invalidate();
}
Random R = new Random();
public Form1()
{
InitializeComponent();
}
}
I have a problem in using DataGridView with DataGridViewComboBoxColumn to let user to select an image from a list of images. Following the discussions in the Question titled "Custom draw of DatagridViewComboBoxColumn" ref Link. I also face the problem as the image is only drawn when the cell is in edit mode. The selected image will disappear when I click somewhere outside the combobox cell! I have implemented the CellPainting event to redraw the image but still cannot solve the problem. I tested the DataGridViewComboBoxColumn with following codes:
public Form1()
{
InitializeComponent();
.....
imageList.Images.Add(Properties.Resources.icon_priority_low);
imageList.Images.Add(Properties.Resources.icon_priority_medium);
.....
}
private void Form1_Load(object sender, EventArgs e)
{
.....
DataGridViewComboBoxCell dgvcbc = (DataGridViewComboBoxCell)newDataGridView1.Rows[0].Cells[1];
dgvcbc.Items.Add("test0");
dgvcbc.Items.Add("test1");
.....
}
private void newDataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is ComboBox)
{
ComboBox theCB = (ComboBox)e.Control;
theCB.DrawMode = DrawMode.OwnerDrawFixed;
try
{
theCB.DrawItem -= combobox1_DrawItem;
}
catch { }
theCB.DrawItem += combobox1_DrawItem;
}
}
private void combobox1_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush br = SystemBrushes.WindowText;
Brush brBack;
Rectangle rDraw;
bool bSelected = e.State == DrawItemState.Selected;
bool bValue = e.State == DrawItemState.ComboBoxEdit;
if ((e.Index < 0) || (columnIndex != 1))
return;
rDraw = e.Bounds;
rDraw.Inflate(-1, -1);
int x, y;
x = e.Bounds.Left + 25;
y = e.Bounds.Top + 1;
int midX = (int)(e.Bounds.Width / 2) + e.Bounds.Left;
// Show image and ignore text.
g.DrawImage(imageList.Images[e.Index], new Rectangle(midX - 6, y + 2, 12, 12));
}
private void newDataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (columnIndex != 1)
return;
Graphics g = e.Graphics;
Rectangle rDraw = newDataGridView1.GetCellDisplayRectangle(columnIndex, rowIndex, true);
e.PaintBackground(e.ClipBounds, true);
e.PaintContent(e.ClipBounds);
using (Brush backColorBrush = new SolidBrush(e.CellStyle.BackColor))
{
int y = rDraw.Y + 1;
int midX = (int)(rDraw.Width / 2) + rDraw.X;
g.DrawImage(imageList.Images[0], new Rectangle(midX - 6, y + 2, 12, 12));
e.PaintContent(e.ClipBounds);
e.Handled = true;
}
}
}
The cell will show "test0" instead of the Images[0] if I click on other cells of the DataGridView. Would you please help to solve this problem. Thanks a lot.
The last call to PaintContent() erases your drawn image.
You must paint the cell (but not the foreground) before you draw the image. It would look like this :
private void newDataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (columnIndex != 1)
return;
Graphics g = e.Graphics;
Rectangle rDraw = newDataGridView1.GetCellDisplayRectangle(columnIndex, rowIndex, true);
e.Paint(e.CellBounds, e.PaintParts & ~DataGridViewPaintParts.ContentForeground);
int y = rDraw.Y + 1;
int midX = (int)(rDraw.Width / 2) + rDraw.X;
g.DrawImage(imageList.Images[0], new Rectangle(midX - 6, y + 2, 12, 12));
e.Handled = true;
}
I'm implementing an application which want to draw lines in the panel. But the panel must be auto scrolled as it size can be expand at run time. The panel paint method I have used is as below.When I run the program it draws lines, but when I scroll down the panel the lines get crashes.How can I avoid that?
private void panel1_Paint(object sender, PaintEventArgs e)
{
this.DoubleBuffered = true;
Pen P = new Pen(Color.Red);
for (int i = 0; i < 10; i++) {
e.Graphics.DrawLine(P, (new Point(i * 40, 0)), (new Point(i * 40, 60 * 40)));
}
for (int i = 0; i < 60; i++)
{
e.Graphics.DrawLine(P, (new Point(0, i *40)), (new Point(10 * 40, i * 40)));
}
}
I'll assume that "get crashes" doesn't actually mean that your code crashes. You'll need to offset the drawing by the scroll amount. That's easy to do:
private void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
// etc
//...
}