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);
}
}
Related
I would like to design a chess board and drag over pieces (shown in pictureBox Controls) all child of the main board (pictureBox1).
Problem I encounter is the transparency is only set to the Parent pictureBox1.
Which shows this effect: The square is showing.
private void CommonPiece_Mouse_Move(object sender, MouseEventArgs e)
{
if (Piece_Selected)
{
int MousePositionX = pictureBox1.PointToClient(Cursor.Position).X;
int MousePositionY = pictureBox1.PointToClient(Cursor.Position).Y;
(sender as PictureBox).Left = MousePositionX - 35;
(sender as PictureBox).Top = MousePositionY - 25;
}
}
What would be a good way to go about it?
There are several solutions for this problem. The one in the following screen recording, is based on drawing png images as movable shapes; it uses the idea that I've explained in How to drag and move shapes in C#. Basically there's only one control -the drawing surface, and all the other stuff are movable drawings.
You can use any image for the pieces by passing an Image to the ImageShape
You can modify the size of the Pieces by setting Height of the shape
It supports snapping to the grid
You can customize the texture, easily by setting the BackgroundImage of the drawing surface
You can change the grid size, by setting GridSize property of the drawing surface
You can change the Color of White and Grid grids, by assigning the color to WhiteColor and BlackColor
It's of course a quick example showing how to draw movable objects, including png images keeping their transparency. You know how to improve it :)
Drawing and moving shapes - Chess pieces
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
public interface IShape
{
bool HitTest(Point p);
void Draw(Graphics g);
void Move(int dx, int dy);
Point Location { get; set; }
}
public class ImageShape : IShape
{
public int Height { get; set; } = 100;
public Point Location { get; set; }
private Image _image;
public ImageShape(Image image)
{
_image = image;
}
public void Draw(Graphics g)
{
var r = new Rectangle(Location, new Size(Height, Height));
r.Inflate(-5, -5);
g.DrawImage(_image, r);
}
public bool HitTest(Point p)
{
return new Rectangle(Location, new Size(Height, Height)).Contains(p);
}
public void Move(int dx, int dy)
{
Location = new Point(Location.X + dx, Location.Y + dy);
}
}
public class DrawingSurface : Control
{
public List<IShape> Shapes { get; private set; }
public int GridSize { get; set; } = 100;
public Color WhiteColor = Color.FromArgb(200, Color.White);
public Color BlackColor = Color.FromArgb(120, Color.Black);
IShape selectedShape;
bool moving;
Point previousPoint = Point.Empty;
public DrawingSurface()
{
DoubleBuffered = true;
ResizeRedraw = true;
Shapes = new List<IShape>();
}
protected override void OnMouseDown(MouseEventArgs e)
{
for (var i = Shapes.Count - 1; i >= 0; i--)
if (Shapes[i].HitTest(e.Location))
{
selectedShape = Shapes[i];
break;
}
if (selectedShape != null)
{
moving = true;
previousPoint = e.Location;
Invalidate();
}
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (moving)
{
var dx = e.X - previousPoint.X;
var dy = e.Y - previousPoint.Y;
selectedShape.Move(dx, dy);
previousPoint = e.Location;
this.Invalidate();
}
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (moving)
{
int i = (e.X / GridSize) * GridSize;
int j = (e.Y / GridSize) * GridSize;
selectedShape.Location = new Point(i, j);
selectedShape = null;
moving = false;
this.Invalidate();
}
base.OnMouseUp(e);
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.InterpolationMode = InterpolationMode.High;
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.CompositingQuality = CompositingQuality.HighQuality;
foreach (var shape in Shapes.Except(new[] { selectedShape }))
shape.Draw(g);
if (selectedShape != null)
selectedShape.Draw(g);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
var g = e.Graphics;
using (var w = new SolidBrush(WhiteColor))
using (var b = new SolidBrush(BlackColor))
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
g.FillRectangle((i + j) % 2 == 0 ? b : w,
i * GridSize, j * GridSize, GridSize, GridSize);
}
}
To add pieces:
private void Form1_Load(object sender, EventArgs e)
{
this.drawingSurface1.Shapes.Add(new ImageShape(
Properties.Resources.KingWhite) { Location = new Point(0, 0) });
this.drawingSurface1.Shapes.Add(
new ImageShape(Properties.Resources.kingBlack) { Location = new Point(0, 100) });
}
Here's an example that makes the PictureBox Non-Rectangular. The PB will literally not exist where the transparent areas were:
using System.Runtime.InteropServices;
namespace CS_Scratch_WindowsFormsApp2
{
public partial class Form1 : Form
{
public const int HT_CAPTION = 0x2;
public const int WM_NCLBUTTONDOWN = 0xA1;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
public Form1()
{
InitializeComponent();
pbChessPiece.MouseMove += PbChessPiece_MouseMove;
}
private void PbChessPiece_MouseMove(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
if (!DesignMode && e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(pb.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)pbChessPiece.Image;
Region rgn = new Region();
rgn.Union(new Rectangle(0, 0, bmp.Width, bmp.Height));
for(int x=0; x<bmp.Width; x++)
{
for(int y=0; y<bmp.Height; y++)
{
if (bmp.GetPixel(x, y).A == 0)
{
rgn.Exclude(new Rectangle(x, y, 1, 1));
}
}
}
pbChessPiece.Region = rgn;
}
}
}
Example run:
I did something similar, but I did not use Drag & Drop events
On MouseDown I assumed a drag operation started, I've opened a translucent unfocused window on top of the drop area, and started drawing dragged image on that form. Since the form is translucent it can show images with transparency on top of everything. I did not use images, but instead draw rectangles where users could drop. If my memory serves me correct, MouseMove events are forwarded to the dragged component, the original chess piece in your case, or the opened but unfocused form, so I can easily track the location. On MouseUp event I wrapped everything.
Since you can draw the image on the new form you can tilt image chess piece image to the left or right for a nice touch.
I developed a very strict forms designer application using this technique.
You can use the panel instead of using the pictureBox and display the image in the background of the controls. Remember that your images must be "png" and the surrounding of the image must be completely transparent. Also, the background color of the controls of the panels Set by events so that it becomes transparent during drag and returns to the cell color after drag and drop.
Good luck.
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.
I'm trying to add a control to my Panel. At mouseDown on the panel the point is saved and at mouseUp the point is saved. But at panel mouseUp nothing is drawn. How to solve it?
Ellipse class:
class Ellipse : Control
{
private int x;
private int y;
private int width;
private int height;
public Ellipse(int x, int y, int width, int height)
{
setY(y);
setX(x);
setWidth(width);
setHeight(height);
}
public int getX() { return x;}
public int getY() { return y; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public void setX(int newx) { x = newx; }
public void setY(int newy) { y = newy; }
public void setWidth(int newwidth) { width = newwidth; }
public void setHeight(int newheight) { height = newheight; }
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Call methods of the System.Drawing.Graphics object.
// Declare and instantiate a new pen.
System.Drawing.Pen myPen = new System.Drawing.Pen(Color.Aqua);
// Draw an aqua rectangle in the rectangle represented by the control.
e.Graphics.FillEllipse(Brushes.Black,x,y,width,height);
}
}
Form1 class
private void panel_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
x = e.X;
y = e.Y;
}
private void panel_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
xe = e.X;
ye = e.Y;
Item item;
Enum.TryParse<Item>(menuComboBoxShape.ComboBox.SelectedValue.ToString(), out item);
switch (item)
{
case Item.Pencil:
using (Graphics g = panel.CreateGraphics())
using (var pen = new Pen(System.Drawing.Color.Black)) //Create the pen used to draw the line (using statement makes sure the pen is disposed)
{
g.DrawLine(pen,new Point(x, y), new Point(xe, ye));
}
break;
case Item.Rectangle:
break;
case Item.Ellipse:
Ellipse el = new Ellipse(x,y,xe-x,ye-y);
panel.Controls.Add(el);
break;
default:
break;
}
}
You are inheriting your Ellipse class from Control, but in fact you're not using it as a control - you're not adding it in Controls collection of form, so in fact it is invisible, inactive and not receiving any events from form.
Also painting the control from outer code looks like a bad design. Control should paint itself, and you should set it bounds from outer code.
Here is snippet to drive you to the right way:
class Ellipse : Control
{
Point mDown { get; set; }
public Ellipse()
{
MouseDown += shape_MouseDown;
MouseMove += shape_MouseMove;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillEllipse(Brushes.Black, this.Bounds);
}
private void shape_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
}
private void shape_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
}
}
}
And in the form you should create it like:
el = new Ellipse();
el.Bounds = new Rectangle(0, 0, 100, 100);
Controls.Add(el);
Update
Based on your updated code, I can see a couple of issues:
You actually don't need x, y, width, height properties of your Ellipse class and according getter/setter methods, since it's Control, and it has its own Location and Width, Height public properties.
You are drawing your ellipse incorrectly. Assuming it should fill all the area, painting should be e.Graphics.FillEllipse(Brushes.Black,0,0,Width,Height) (here I assuming using Control.Width instead of your width and so on). Otherwise you're additionally shifting your painted ellipse.
Code in panel_MouseUp concerning ellipse creation should be something like
var el = new Ellipse();
panel.Controls.Add(el);
el.Location = new Point(x, y);
el.Width = (xe - x);
el.Height = (ye - y);
Or, if it should be one single ellipse (right now you're creating new one each time) - create this one outside of mouseUp handler and inside of handler just change it's size and location.
I have a PictureBox as UserControl. I added this User Control on the main form. Now I have to press a button and create a line on the user control. On my project, every time I press this button, I want to send to user control parameters of two PointF(x and y) and draw a new line, in addition to the existent one. I have so far the Paint event when picturebox is loaded.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Pen graphPen = new Pen(Color.Red, 2);
PointF pt1D = new PointF();
PointF pt2D = new PointF();
pt1D.X = 0;
pt1D.Y = 10;
pt2D.X = 10;
pt2D.Y = 10;
e.Graphics.DrawLine(graphPen, pt1D, pt2D);
}
Assuming that you want to draw the line on the click of the button, here's a modified version of your code:
List<PointF> points = new List<PointF>();
Pen graphPen = new Pen(Color.Red, 2);
private void btnDrawLines_Click(object sender, EventArgs e)
{
Graphics g = picBox.CreateGraphics();
PointF pt1D = new PointF();
PointF pt2D = new PointF();
pt1D.X = 0;
pt1D.Y = 10;
pt2D.X = 10;
pt2D.Y = 10;
g.DrawLine(graphPen, pt1D, pt2D);
points.Add(pt1D);
points.Add(pt2D);
}
private void picBox_Paint(object sender, PaintEventArgs e)
{
for (int i = 0; i < points.Count; i+=2)
e.Graphics.DrawLine(graphPen, points[i], points[i + 1]);
}
Note that you can get a Graphics object through the PictureBox class's CreateGraphics() method which is the same as the e.Graphics object in the Paint event handler.
If you are adding lines to be drawn, the you probably want a little Line class:
public class Line {
public Point Point1 { get; set; }
public Point Point2 { get; set; }
public Line(Point point1, Point point2) {
this.Point1 = point1;
this.Point2 = point2;
}
}
And then you can just add these "lines" to a list:
private List<Line> _Lines = new List<Line>();
and add to them and tell the control to update it's drawing:
_Lines.Add(new Line(new Point(10, 10), new Point(42, 42)));
_Lines.Add(new Line(new Point(20, 40), new Point(20, 60)));
pictureBox1.Invalidate()
then in your drawing:
private void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.Clear(Color.White);
foreach (Line l in _Lines) {
e.Graphics.DrawLine(Pens.Red, l.Point1, l.Point2);
}
}
I am developing a windows mobile application in which I want to show popup box containing DataGrid control of showing particular details when user clicks on a button in a form.
I am using ShowDialog() method but it is working.
Can anyone suggest me how to implement this?
Thanks in advance.
If I understand correctly your question, my solution was to create a custom popup class.
public class Popup : Control
{
private class Const
{
public const int Height = 100;
public static Color BarFrameColor = SystemColors.ControlDark;
public static Color BarShadowColor = Color.Black;
public static Color BackColor = SystemColors.Info;
public static Color ForeColor = SystemColors.InfoText;
}
// [ gdi objects ]
private Bitmap m_bmp;
private Pen m_penShadow, m_penFrame;
private Panel panel;
private VScrollBar vScrollBar;
private Label lblText;
private bool scrolling;
public string Text
{
get
{
return lblText.Text;
}
set
{
lblText.Text = value;
}
}
public bool Scrolling
{
get
{
return this.scrolling;
}
set
{
this.scrolling = value;
}
}
public Popup()
{
this.Hide();
this.ForeColor = Const.ForeColor;
this.BackColor = Const.BackColor;
this.Height = Const.Height;
this.panel = new Panel();
this.panel.BackColor = Const.BackColor;
this.panel.Location = new Point(2, 2);
this.vScrollBar = new VScrollBar();
this.vScrollBar.ValueChanged += new EventHandler(vScrollBar_ValueChanged);
this.lblText = new Label();
this.lblText.Location = new Point(0, 0);
this.lblText.Text = "";
this.panel.Controls.Add(lblText);
this.Controls.Add(vScrollBar);
this.Controls.Add(panel);
CreateGdiObjects();
this.Scrolling = false;
}
private void CreateGdiObjects()
{
// [ gdi objects ]
this.m_penShadow = new Pen(Const.BarShadowColor);
this.m_penFrame = new Pen(Const.BarFrameColor);
}
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
// [ calculate layout ]
this.Left = 0;
if (this.Parent != null)
{
this.Width = this.Parent.Width;
this.Top = this.Parent.Height - this.Height;
}
if (this.Scrolling)
{
this.vScrollBar.Size = new Size(12, this.Height - 4);
this.vScrollBar.Location = new Point(this.Width - 2 - this.vScrollBar.Width, 2);
this.panel.Size = new Size(this.Width - 4 - this.vScrollBar.Width, this.Height - 4);
this.vScrollBar.Minimum = this.panel.Top;
this.vScrollBar.Maximum = this.panel.Height;
this.vScrollBar.Visible = true;
this.lblText.Size = new Size(this.panel.Width, this.Height * 3);
}
else
{
this.panel.Size = new Size(this.Width - 4, this.Height - 4);
this.vScrollBar.Visible = false;
this.lblText.Size = this.panel.Size;
}
this.BringToFront();
}
protected override void OnPaint(PaintEventArgs e)
{
// [ draw progress on memory bitmap ]
CreateMemoryBitmap();
Graphics g = Graphics.FromImage(this.m_bmp);
DrawControl(g);
// [ blit to screen ]
e.Graphics.DrawImage(this.m_bmp, 0, 0);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// [ don't pass to base since we paint everything, avoid flashing ]
}
private void CreateMemoryBitmap()
{
// [ see if need to create bitmap ]
if (this.m_bmp == null || this.m_bmp.Width != this.Width || this.m_bmp.Height != this.Height)
this.m_bmp = new Bitmap(this.Width, this.Height);
}
private void DrawControl(Graphics g)
{
g.Clear(this.BackColor);
Rectangle rc = new Rectangle(0, 0, this.Width - 1, this.Height - 1);
g.DrawRectangle(this.m_penShadow, rc);
rc.Inflate(-1, -1);
g.DrawRectangle(this.m_penFrame, rc);
}
private void vScrollBar_ValueChanged(object sender, System.EventArgs e)
{
this.lblText.Top = -this.vScrollBar.Value;
}
}