My problem is : I have 2 Panels (panel1,panel2) where panel1.Size = new Size(200, 200); and Panel2.Size = new Size(600, 600); where both panel's have within a CustomControl which can get Dragged and change it Possition (szbControl1 ,szbControl2) .
My Question is ,how can i set szbControl2.Location properly (proportionally)based on szbControl1.Location where szbControl1 parent is panel1 and szbControl2 parent is panel2 ,like if i move the szbControl1 at bottom also szbControl2 should be at bottom.
So far i tried this :
private void sizeAbleCTR2_LocationChanged(object sender, EventArgs e)
{
int smallX = (sizeAbleCTR2.Location.X * panel1.Size.Width) / 100;
int smallY = (sizeAbleCTR2.Location.Y * panel1.Size.Height) / 100;
int largeX = (smallX * panel2.Width) / 100;
int largeY = (smallY * panel2.Height) / 100;
sizeAbleCTR1.Location = new Point(largeX,largeY);
}
like using the Percentage but it's not working .
The code you provided does not take into account the size of the szbControls. The ratio of the (location/the differences of the sizes) should be equal.
private void sizeAbleCTR2_LocationChanged(object sender, EventArgs e)
{
float srcHeightDiff = panel2.Height - sizeAbleCTR2.Height;
float dstHeightDiff = panel1.Height - sizeAbleCTR1.Height;
int locY = (int)(dstHeightDiff * (sizeAbleCTR2.Location.Y / srcHeightDiff));
float srcWidthDiff = panel2.Width - sizeAbleCTR2.Width;
float dstWidthDiff = panel1.Width - sizeAbleCTR1.Width;
int locX = (float)(dstWidthDiff * (sizeAbleCTR2.Location.X / srcWidthDiff));
sizeAbleCTR1.Location = new Point(locX, locY);
}
Related
I am trying to create a paddle using a label which must be done programmatically to a brick breaker game and my aim is so that no matter what desktop computer with different screen sizes I'm using, the paddle will always be in the bottom center of the screen but for some reason the paddle(label) is not showing. This is the code I'm using:
Screen userScreen = Screen.PrimaryScreen;
int screenWidth = userScreen.WorkingArea.Width;
int screenHeight = userScreen.WorkingArea.Height;
this.Width = screenWidth;
this.Height = screenHeight;
Label lblPaddle = new Label();
lblPaddle.BackColor = Color.White;
lblPaddle.BorderStyle = BorderStyle.FixedSingle;
//lblPaddle.Left = (this.ClientSize.Width - lblPaddle.Width) / 2;
//lblPaddle.Top = (this.ClientSize.Height - lblPaddle.Height) / 2;
//lblPaddle.Size = this.ClientSize;
int lblPaddleWidth = (int)(screenWidth * 0.15);
int lblPaddleHeight = lblPaddle.Height;
int lblPaddleXCoord = (screenWidth / 2) - (lblPaddleWidth / 2);
int lblPaddleYCoord = screenHeight - lblPaddleHeight - (int)(screenHeight * 0.1);
lblPaddle.SetBounds(lblPaddleXCoord, lblPaddleYCoord, lblPaddleWidth, lblPaddleHeight);
this.Controls.Add(lblPaddle);
The part where there are comments were different approaches I attempted in order to try and make it work.
Why is it not showing?
I have absolutely no problems with your code when called like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitLabel();
}
private void InitLabel()
{
Screen userScreen = Screen.PrimaryScreen;
int screenWidth = userScreen.WorkingArea.Width;
int screenHeight = userScreen.WorkingArea.Height;
this.Width = screenWidth;
this.Height = screenHeight;
// I added the following 2 lines because the form was below the task bar
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(0,0);
Label lblPaddle = new Label();
lblPaddle.Name = "lblPaddle";
lblPaddle.BackColor = Color.White;
lblPaddle.BorderStyle = BorderStyle.FixedSingle;
int lblPaddleWidth = (int)(screenWidth * 0.15);
int lblPaddleHeight = lblPaddle.Height;
int lblPaddleXCoord = (screenWidth / 2) - (lblPaddleWidth / 2);
int lblPaddleYCoord = screenHeight - lblPaddleHeight - (int)(screenHeight * 0.1);
lblPaddle.SetBounds(lblPaddleXCoord, lblPaddleYCoord, lblPaddleWidth, lblPaddleHeight);
this.Controls.Add(lblPaddle);
}
}
It ends up looking like this:
EDIT: If you're planning to do anything with it, I suggest giving it a name. I added it above.
For some odd reason this was not working. I spoke with a lecturer at my school and she also could not figure out what the problem was. Perhaps it was a bug of some sort. The only way I managed to resolve this was by creating another form and create another paddle and then I copied the code from the form I created to the original and it worked. Neither me nor the lecturer could figure out what the problem was. It was just plain weird since the code was basically the same.
I'm using WinForms. In my form i have a picturebox that i want to zoom in and out using the track bar. My picturebox is set to zoom-mode. I want the image and picturebox to be proportion height/width when i drag the bar. How can i accomplish this?
private void Open_btn_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
Image bmp;
bmp = new Bitmap(openFileDialog1.FileName);
if (bmp == null)
{
MessageBox.Show("Loading image failed", "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
}
else
{
pictureBox1.Image = bmp;
openFileDialog1.Dispose();
}
}
}
private void zoomSlider_Scroll(object sender, EventArgs e)
{
if(TrackBar1.Value == 1)
{
pictureBox1.Height += 50;
pictureBox1.Width += 50;
}
if(TrackBar1.Value == 2)
{
pictureBox1.Height += 100;
pictureBox1.Width += 100;
}
if(TrackBar1.Value == 3)
{
pictureBox1.Height += 200;
pictureBox1.Width += 200;
}
//This is not exactly what i had in mind...
}
When the form is originally created you have to save the size
Form1 : Form
{
private Size _pictOriginalSize;
Form1()
{
InitialiseComponent();
_pictOriginalSize = pictureBox1.Size;
zoomSlider.Minimum = 0;
zoomSldier.Maximum = 1000;
...
}
Now you know what it's unzoomed size was.
Next you will need to you will need to convert the value of the slider into into a scale factor.
private void zoomSlider_Scroll(object sender, EventArgs e)
{
const double MaxScale = 5.0; // The scale factor when the is at it's max
double scale = Math.Pow(MaxScale, TrackBar1.Value / TrackBar1.Maximum);
Size newSize = new Size((int) (_pictOrignalSize.Width * scale),
(int) (_pictOrignalSize.Height * scale));
pictureBox.Size = newSize;
}
I am using the Math.Pow function to convert the scale from 1 to 5 on an exponential scale - you may want to use a different technique you could consider
having the slider have values 1 to 5 and the Value simply becomes the scale: scale = zoomSlider.Value - but this only gives you a resoultion of 1.
having the slider have values 1 to 5000 and do a double division double scale = zoomSlider.Value / 1000.0; This gives you a 1000 different resolutions.
NB: I am using 5 as an example only - you can use any value for the max scale factor.
I'm using the following code as just a test for how I might use a custom progress bar in the future - it actually isn't a progress bar at all, but rather a picturebox that the code draws a rectangle on, and then fills up based on a timer.
The problem is, I'm reaching 100% before the box is filled. I've tinkered around, but not been able to locate the issue. What am I doing wrong? See code below, and imgur screenshot of the behavior on my system.
Thanks.
public partial class frmLoading : Form
{
System.Windows.Forms.Timer tLoading = new System.Windows.Forms.Timer();
Double pbLoadingUnit;
int pbLoadingWIDTH, pbLoadingHEIGHT, pbLoadingComplete;
Bitmap bmpLoading;
Graphics gLoading;
private void frmLoading_Load(object sender, EventArgs e)
{
pbLoadingWIDTH = pictureLoading.Width;
pbLoadingHEIGHT = pictureLoading.Height;
pbLoadingUnit = pbLoadingWIDTH / 100;
pbLoadingComplete = 0;
bmpLoading = new Bitmap(pbLoadingWIDTH, pbLoadingHEIGHT);
tLoading.Interval = 32;
tLoading.Tick += new EventHandler(this.tLoading_Tick);
tLoading.Start();
}
private void tLoading_Tick(object sender, EventArgs e)
{
gLoading = Graphics.FromImage(bmpLoading);
gLoading.Clear(Color.DarkSlateGray);
gLoading.FillRectangle(Brushes.DodgerBlue, new Rectangle(0, 0, (int)(pbLoadingComplete * pbLoadingUnit), pbLoadingHEIGHT));
gLoading.DrawString(pbLoadingComplete + "%", new Font("Segoe UI Semibold", pbLoadingHEIGHT / 2), Brushes.White, new PointF(pbLoadingWIDTH / 2 - pbLoadingHEIGHT, pbLoadingHEIGHT / 10));
pictureLoading.Image = bmpLoading;
pbLoadingComplete++;
if (pbLoadingComplete > 100)
{
gLoading.Dispose();
tLoading.Stop();
}
}
You should change this
pbLoadingUnit = pbLoadingWIDTH / 100;
to this
pbLoadingUnit = Convert.ToDouble(pbLoadingWIDTH) / 100;
I assume your picture width is not a multiple of a hundred.
With your old code, your pbLoadingUnit will be generate as integer since you divide integer to integer.
You may use this too :
double div = 100;
pbLoadingUnit = pbLoadingWIDTH / div;
OR
pbLoadingUnit = pbLoadingWIDTH / Convert.ToDouble(100);
The point is, you should get the double value of pbLoadingUnit.
For more information about numeric casting, you may see this link dotnetperls.com/numeric-casts
Try to put the following lines in OnResize() event of the frmLoading:
pbLoadingWIDTH = pictureLoading.Width;
pbLoadingHEIGHT = pictureLoading.Height;
pbLoadingUnit = pbLoadingWIDTH / 100;
Chances are you're getting the initial size of the pictureLoading during Load()... and not the actual width when it shows up and displayed in your form.
Also let tloading.Start() happens when you already get the appropriate size of you pictureLoading object.
you have to add this variable int pbmodal;
then calculate MOD of the unit
on form load add
pbmodal = pbLoadingWIDTH % 100;
when the completed is 100% add the modal.
Difference of division
`if (pbLoadingComplete > 100)
{
gLoading.FillRectangle(Brushes.DodgerBlue, new Rectangle(0, 0, (int)(pbLoadingComplete * pbLoadingUnit) + pbmodal, pbLoadingHEIGHT));
gLoading.DrawString(pbLoadingComplete-1 + "%", new Font("Segoe UI Semibold", pbLoadingHEIGHT / 2), Brushes.White, new PointF(pbLoadingWIDTH / 2 - pbLoadingHEIGHT, pbLoadingHEIGHT / 10));
pictureLoading.Image = bmpLoading;
}`
I'm trying to draw out pictureboxes during runtime as I can do right from the toolbox. That is, set the location at the mouselocation, resize it as I hold down the button and drag it across the form. All that I've accomplished in the code. But as I start the draw the second picturebox the first one disappears, I want to keep adding more pictureboxes to the form, if I remove the MouseMove event and move PictureBox pb1 = new PictureBox(); down to the MouseDown event it lets me add more buttons, but then I can't resize them obviously.
int cellSize = 10;
int numOfCells = 500;
PictureBox pb1 = new PictureBox();
int Mx, My;
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
}
public void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
Point p = new Point(e.X, e.Y);
Mx = p.X;
My = p.Y;
int xSnap = (Mx / cellSize) * cellSize;
int ySnap = (My / cellSize) * cellSize;
pb1.BackColor = (Color.Red);
if (e.Button == MouseButtons.Left)
{
pb1.Size = new Size(xSnap - pb1.Left, ySnap - pb1.Top);
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Point p = new Point(e.X, e.Y);
Mx = p.X;
My = p.Y;
int xSnap = (Mx / cellSize) * cellSize;
int ySnap = (My / cellSize) * cellSize;
pb1.Location = new Point(xSnap, ySnap);
pictureBox1.Controls.Add(pb1);
}
You're always re-using the same PictureBox instance.
You need to create a new instance every time you want to add a new one, by writing new PictureBox().
I am creating a panel and then adding some labels/buttons to it to form a grid. The issue is that if I add more than say 25x25 items to the panel, there is a terrible performance hit. I can resize the form ok but when I scroll the panel to see all the labels the program lags, the labels/buttons tear or flicker, and sometimes it can make the program unresponsive. I have tried adding the controls to a "DoubleBufferedPanel" that I created. This seems to have no effect. What else could I do? Sorry for such a large code listing. I didn't want to waste anyone's time.
namespace GridTest
{
public partial class Form1 : Form
{
private const int COUNT = 50;
private const int SIZE = 50;
private Button[,] buttons = new Button[COUNT, COUNT];
private GridPanel pnlGrid;
public Form1()
{
InitializeComponent();
pnlGrid = new GridPanel();
pnlGrid.AutoScroll = true;
pnlGrid.Dock = DockStyle.Fill;
pnlGrid.BackColor = Color.Black;
this.Controls.Add(pnlGrid);
}
private void Form1_Load(object sender, EventArgs e)
{
int x = 0;
int y = 0;
int offset = 1;
for (int i = 0; i < COUNT; i++)
{
for (int j = 0; j < COUNT; j++)
{
buttons[i, j] = new Button();
buttons[i, j].Size = new Size(SIZE, SIZE);
buttons[i, j].Location = new Point(x, y);
buttons[i, j].BackColor = Color.White;
pnlGrid.Controls.Add(buttons[i, j]);
x = x + SIZE + offset;
}
x = 0;
y = y + SIZE + offset;
}
}
}
}
Also, the GridPanel class:
namespace GridTest
{
public class GridPanel : Panel
{
public GridPanel()
: base()
{
this.DoubleBuffered = true;
this.ResizeRedraw = false;
}
}
}
If you must add controls at run time, based on some dynamic or changing value, you might want to consider creating an image on the fly, and capturing mouse click events on its picturebox. This would be much quicker and only have one control to draw rather than hundreds. You would lose some button functionality such as the click animation and other automatic properties and events; but you could recreate most of those in the generation of the image.
This is a technique I use to offer users the ability to turn on and off individual devices among a pool of thousands, when the location in a 2-dimensional space matters. If the arrangement of the buttons is unimportant, you might be better offering a list of items in a listview or combobox, or as other answers suggest, a datagridview with button columns.
EDIT:
An example showing how to add a graphic with virtual buttons. Very basic implementation, but hopefully you will get the idea:
First, some initial variables as preferences:
int GraphicWidth = 300;
int GraphicHeight = 100;
int ButtonWidth = 60;
int ButtonHeight = 20;
Font ButtonFont = new Font("Arial", 10F);
Pen ButtonBorderColor = new Pen(Color.Black);
Brush ButtonTextColor = new SolidBrush(Color.Black);
Generating the image:
Bitmap ControlImage = new Bitmap(GraphicWidth, GraphicHeight);
using (Graphics g = Graphics.FromImage(ControlImage))
{
g.Clear(Color.White);
for (int x = 0; x < GraphicWidth; x += ButtonWidth)
for (int y = 0; y < GraphicHeight; y += ButtonHeight)
{
g.DrawRectangle(ButtonBorderColor, x, y, ButtonWidth, ButtonHeight);
string ButtonLabel = ((GraphicWidth / ButtonWidth) * (y / ButtonHeight) + x / ButtonWidth).ToString();
SizeF ButtonLabelSize = g.MeasureString(ButtonLabel, ButtonFont);
g.DrawString(ButtonLabel, ButtonFont, ButtonTextColor, x + (ButtonWidth/2) - (ButtonLabelSize.Width / 2), y + (ButtonHeight/2)-(ButtonLabelSize.Height / 2));
}
}
pictureBox1.Image = ControlImage;
And responding to the Click event of the pictureBox:
// Determine which "button" was clicked
MouseEventArgs em = (MouseEventArgs)e;
Point ClickLocation = new Point(em.X, em.Y);
int ButtonNumber = (GraphicWidth / ButtonWidth) * (ClickLocation.Y / ButtonHeight) + (ClickLocation.X / ButtonWidth);
MessageBox.Show(ButtonNumber.ToString());
I think you won't be able to prevent flickering having 625 buttons (btw, windows) on the panel. If such layout is mandatory for you, try to use the DataGridView, bind it to a fake data source containing the required number of columns and rows and create DataGridViewButtonColumns in it. This should work much more better then your current result ...