I have an app with 2 forms. Form1 have the pictureBox and buttons, Form2 has a code that, when i call the form:
private void button1_Click(object sender, EventArgs e)
{
new Form2().Show();
}
it turns is a Zoom Lens, that i can use in Form1 pictureBox.
Problem is, when Form2(lens) is runing and i click ESC to close the form2, it closes but keep increasing consuming memory. Even the errors that form2(lens) has is triggering, like move mouse too far at the border, even after call close to form2.
Here is the code to the Lens form2:
PictureBox pictureBox1 = new PictureBox(); // Have a picture box
int zoom = 1; // Variable for zoom value
public Form1()
{
pictureBox1.Dock = DockStyle.Fill; // Occupy the full area of the form
pictureBox1.BorderStyle = BorderStyle.FixedSingle; // Have a single border of clear representation
Controls.Add(pictureBox1); // Add the control to the form
FormBorderStyle = FormBorderStyle.None; // Make the form borderless to make it as lens look
Timer timer = new Timer(); // Have a timer for frequent update
timer.Interval = 100; // Set the interval for the timer
timer.Tick += timer_Tick; // Hool the event to perform desire action
timer.Start(); //Start the timer
printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // Have a bitmap to store the image of the screen
}
void timer_Tick(object sender, EventArgs e)
{
var graphics = Graphics.FromImage(printscreen as Image); // Get the image of the captured screen
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size); // Get the copy of screen
var position = Cursor.Position; // Get the position of cursor
var lensbmp = new Bitmap(50, 50); // Have a bitmap for lens
var i = 0; // Variable for row count
var j = 0; // Variable for column count
for (int row = position.X - 25; row < position.X + 25; row++) // Indicates row number
{
j = 0; // Set column value '0' for new column
for (int column = position.Y - 25; column < position.Y + 25; column++) // Indicate column number
{
lensbmp.SetPixel(i, j, printscreen.GetPixel(row, column)); // Place current region pixel to lens bitmap
j++; // Increase row count
}
i++; // Increase column count
}
this.pictureBox1.Image = new Bitmap(lensbmp, lensbmp.Width * zoom, lensbmp.Height * zoom); // Assign lens bitmap with zoom level to the picture box
Size = pictureBox1.Image.Size; // Assign optimal value to the form
Left = position.X + 20; // Place form nearer to cursor X value
Top = position.Y + 20; // Place form nearer to cursor Y value
TopMost = true; // Keep the form top level
}
// Override OnKeyDown for zoom in and zoom out actions
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyValue == 73) // Set "i" as the key for Zoom In.
zoom++; // Increase zoom by 1 item greater
else if (e.KeyValue == 79) // Set "o" as the key for Zoom Out
zoom--; // Decrease zoom by 1 item smaller
else if (e.KeyValue == 27) // Set "Esc" to close the magnifier
{
Close(); // Close the form
Dispose(); // Dispose the form
}
base.OnKeyDown(e);
}
Is that a way to close this form2 and stop all methods while form1 keep runing? It keep increasing memory consume like 1mb for sec.
You have a dangerous timer because it isn't declared at the form scope, so it can still keep running.
Declare it at the form level instead:
PictureBox pictureBox1 = new PictureBox();
int zoom = 1;
Timer timer = new Timer();
public Form1()
{
pictureBox1.Dock = DockStyle.Fill; // Occupy the full area of the form
pictureBox1.BorderStyle = BorderStyle.FixedSingle; // Have a single border of clear representation
Controls.Add(pictureBox1); // Add the control to the form
FormBorderStyle = FormBorderStyle.None; // Make the form borderless to make it as lens look
timer.Interval = 100; // Set the interval for the timer
timer.Tick += timer_Tick; // Hool the event to perform desire action
timer.Start(); //Start the timer
printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // Have a bitmap to store the image of the screen
}
Also, make sure you dispose of your image and graphic objects, too, when they aren't being used anymore.
Related
I want to make a moving label seem nicer and smoother than just reappearing the whole thing to the left after it has all gone out of panel width .For example label 'Hello' , as soon as 'lo' goes out of bounds in the right I want it to reappear on the left. Is there any possible solution to this ?
Here's the code I have for the label now .
private void timer2_Tick(object sender, EventArgs e)
{
label5.Location = new Point(label5.Location.X + 3, label5.Location.Y);
if (label5.Location.X > this.Width)
{
label5.Location = new Point(0 - label5.Width, label5.Location.Y);
}
}
Try this, using a Label (here, named lblMarquee and a System.Windows.Forms.Timer).
The scrolling time is regulated by both the Timer.Interval and a float Field (marqueeStep).
The Timer.Tick event just calls lblMarquee.Invalidate(), causing the Label control to repaint itself.
When the scrolling text, in relation to its current position, goes beyond the limits of the Label.ClientRectangle, the section of the text which is not visible anymore is painted at start of the Label.ClientArea:
System.Windows.Forms.Timer marqueeTimer = new System.Windows.Forms.Timer();
string marqueeText = string.Empty;
float marqueePosition = 0f;
float marqueeStep = 4f;
private void form1_Load(object sender, EventArgs e)
{
marqueeText = lblMarquee.Text;
lblMarquee.Text = string.Empty;
marqueeTimer.Tick += (s, ev) => { this.lblMarquee.Invalidate(); };
marqueeTimer.Interval = 100;
marqueeTimer.Start();
}
private void lblMarquee_Paint(object sender, PaintEventArgs e)
{
var marquee = sender as Label;
SizeF stringSize = e.Graphics.MeasureString(marqueeText, marquee.Font, -1, marqueeFormat);
PointF stringLocation = new PointF(marqueePosition, (marquee.Height - stringSize.Height) / 2);
stringLength = marquee.ClientRectangle.Width - stringLocation.X;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
e.Graphics.DrawString(marqueeText, marquee.Font, Brushes.Black, stringLocation, marqueeFormat);
if (marqueePosition >= marquee.ClientRectangle.Width) marqueePosition = 0f;
if (stringSize.Width + stringLocation.X > marquee.ClientRectangle.Width) {
PointF partialStringPos = new PointF(-stringLength, (marquee.Height - stringSize.Height) / 2);
e.Graphics.DrawString(marqueeText, marquee.Font, Brushes.Black, partialStringPos, marqueeFormat);
}
marqueePosition += marqueeStep;
}
A couple of other implementations you might find useful:
How to follow the end of a text in a TextBox with no NoWrap
How to draw a string on two not adjacent areas
You need to have two label controls to do this, but it's not really that difficult. First, create a backup label and set it's properties to look like label5:
// A backup label for our scrolling label5
private Label label5_backup;
private void Form1_Load(object sender, EventArgs e)
{
label5.Text = "This is a scrolling label!";
// Set label5_backup to look like label5
label5_backup = new Label
{
Size = label5.Size,
Text = label5.Text,
Top = label5.Top,
Visible = false
};
Controls.Add(label5_backup);
timer2.Interval = 1;
timer2.Start();
}
Then, in the Tick event, as soon as our label5 starts to leave the client rectangle, set our backup label to the proper distance from the left of the form so that it starts to appear on the other side. And as soon as label5 is completely off the form, set it's location to match the backup label and then hide the backup label again.
Note that you can just set the Left property instead of creating a new Location point each time, which simplifies the code a little:
private void timer2_Tick(object sender, EventArgs e)
{
label5.Left++;
// If label5 starts to go off the right, show our backup on the left side of the form
if (label5.Right > ClientRectangle.Width)
{
label5_backup.Left = label5.Right - ClientRectangle.Width - label5.Width;
label5_backup.Visible = true;
}
// If label5 is all the way off the form now, set it's location to match the backup
if (label5.Left > ClientRectangle.Width)
{
label5.Location = label5_backup.Location;
label5_backup.Visible = false;
}
}
Also, if you want to make the scrolling smoother, only increment the Left by 1 each time and reduce the timer2.Interval to a third of what it was before (unless it's already at 1).
I'm trying to make a breakout game for an assignment in windows form and I've made games before, but I've just not used winforms before. I've found things that are supposed to help like OnPaint() (which you're supposed to override), DoubleBuffered andInvalidate`. But I'm just struggling applying it to my code
Here's what I have:
int xSpeed, ySpeed;
Graphics display;
Brush brush;
Rectangle ballRect;
public Form1()
{
InitializeComponent();
timer1.Enabled = true;
timer1.Interval = 1;
xSpeed = 5;
ySpeed = 5;
ballRect = new Rectangle(10, 10, 20, 20);
display = this.CreateGraphics();
brush = new SolidBrush(Color.Red);
}
private void timer1_Tick(object sender, EventArgs e)
{
DoubleBuffered = true;
ballRect.X += xSpeed;
ballRect.Y += ySpeed;
if (ballRect.X >= 469)
xSpeed = -xSpeed;
if (ballRect.Y >= 457)
ySpeed = -ySpeed;
if (ballRect.X <= 0)
xSpeed = -xSpeed;
if (ballRect.Y <= 0)
ySpeed = -ySpeed;
display.Clear(Color.White);
display.FillEllipse(brush, ballRect);
}
I'm drawing the ball in Update method (timer1_tick), but I feel like I shouldn't be.
Thanks :)
You can create your custom Control or Form and:
In constructor Set styles for flicker free painting OptimizedDoubleBuffer, UserPaint, AllPaintingInWmPaint
In constructor Set style for redraw if the size changes ResizeRedraw
In Tick event just update position of ball and then Invalidate the control
override OnPaint method of your control and put the paint logic there
Also you should use properties for speed or ball size, to be able to invalidate the control if those values changed. (I didn't implement properties in below code.) Also you can increase the interval a little.
For example:
public partial class CustomControl1 : Control
{
public CustomControl1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
timer1.Enabled = true;
timer1.Interval = 1;
xSpeed = 5;
ySpeed = 5;
ballRect = new Rectangle(10, 10, 20, 20);
brush = new SolidBrush(Color.Red);
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.FillEllipse(brush, ballRect);
}
int xSpeed, ySpeed;
Brush brush;
Rectangle ballRect;
private void timer1_Tick(object sender, EventArgs e)
{
ballRect.X += xSpeed;
ballRect.Y += ySpeed;
if (ballRect.X + ballRect.Width >= this.Width)
xSpeed = -xSpeed;
if (ballRect.Y + ballRect.Height >= this.Height)
ySpeed = -ySpeed;
if (ballRect.X <= 0)
xSpeed = -xSpeed;
if (ballRect.Y <= 0)
ySpeed = -ySpeed;
this.Invalidate();
}
}
The flickering is happening because you are drawing directly to the display. First you clear the display, which the user will see for a split second, then you draw a circle over it, which is only displayed for a short time before the process repeats. That "overdrawing" is where the flicker is coming from.
One method to get rid of it is to do all your drawing to a memory bitmap and, once complete, move the entire bitmap to the display.
Once other issue I see with your code is that you create a Graphics instance in the constructor and keep it around for the life of the program. That's a pattern that you should avoid. Instead you should create a new Graphics object, preferably in a using statement for each "frame". That will make sure that everything is getting cleaned up properly.
I'm working on C# windows form. I have an array of picturebox, displayed on the form. The array has the size of 13, and they're all side by side. How can I make it so that when I click on a picturebox, it is moved up by let's say +20 on y.
My code to make the picture boxes. The pb1 and p1 are declared above
void print_Deck(int x, int y, double[] a){
double n;
for (int i = 0; i < 13; i++)
{
pb1[i] = new PictureBox();
// pb1[1].Image = Properties.Resources.img1;
pb1[i].Visible = true;
pb1[i].Location = new Point(0, 0);
this.Size = new Size(800, 600);
pb1[i].Size = new Size(46, 65);
pb1[i].SizeMode = PictureBoxSizeMode.StretchImage;
pb1[i].Location = new Point(x, y);
n= a[i];
im = face(n);
pb1[i].Image = im;
this.Controls.Add(pb1[i]);
x = x + 20;
}
}
You can try adding Click event on your Picturebox then you can try this code on the Click function.
You can manipulate the location by using Top propery.
Picturebox.Top -= 20; // move the picture box upward
or
Picturebox.Top += 20; // move the picture box downward
or use the .Location = New Point(X,Y)
Picturebox.Location = new Point(Picturebox.Location.X, Picturebox.Location.Y + 20);
Here's how you add the EventHandler to your picturebox.
Picturebox.Click += new System.EventHandler(this.Picturebox_ClickFunction);
then create a fucntion with the name Picturebox_ClickFunction
private void Picturebox_ClickFunction(object sender, EventArgs e)
{
PictureBox pb1 = (PictureBox)sender; // you need to cast(convert) the sende to a picturebox object so you can access the picturebox properties
}
then you can use the code I provided above.
You can try PictureBox.Top property with Anchor property
or use PictureBox.Location.
You could register the PictureBox's 'Click' event to adjust the 'Margin' property by the required amount
At the top of Form1 i did:
private IntPtr ID;
private int counter = 0;
In the constructor i did:
ID = this.Handle;
timer2.Enabled = true;
Then in timer2 tick event i did:
private void timer2_Tick(object sender, EventArgs e)
{
if (counter <= Screen.PrimaryScreen.Bounds.Right)
MoveWindow(ID, counter++, 0, this.Width, this.Height, true);
else
counter = 0;
}
But the form start to move from the top left corner at 0,0 to the right.
I want the form will start to move from the center of the screen to the left untill it hit the left border/bound and stop and stay there.
How can i do it ?
I found now how to make it to move to the left and stop on the left border/bound:
private void timer2_Tick(object sender, EventArgs e)
{
if (counter >= Screen.PrimaryScreen.Bounds.Left)
MoveWindow(ID, counter--, 0, this.Width, this.Height, true);
else
counter = 0;
}
But how do i make that it will start to move from the middle/center of the screen ?
I did in the designer change the property: StartPosition to CenterScreen
But the form start to move from the top left corner 0,0
There is a better solution for you, just use the protected method CenterToScreen() like this:
this.CenterToScreen();
This is the answer.
x = Screen.PrimaryScreen.Bounds.Bottom - this.Width * 2;
y = Screen.PrimaryScreen.Bounds.Bottom - this.Height * 2;
counter = x;
Then in the timer tick event:
private void timer2_Tick(object sender, EventArgs e)
{
if (counter >= Screen.PrimaryScreen.Bounds.Left)
MoveWindow(ID, counter--, y, this.Width, this.Height, true);
else
counter = 0;
}
Before it the counter-- was set to 0. And instead y it was 0 too.
So it's 0,0 this is the location.
Now counter and y start location is the middle of the screen.
Thanks.
You could set the StartPosition property of your main WinForm to CenterScreen:
Form1.StartPosition = FormStartPosition.CenterScreen;
Then if you want it to appear somehow on a different position relative to this screen center, you can play with the Top and Left properties to add or subtract the required number of pixels.
if you need to know the screen bounds:
System.Windows.Forms.Screen.PrimaryScreen.Bounds
or, taking into account the task bar:
System.Windows.Forms.Screen.PrimaryScreen.WorkingArea
...or some variant
I didn't find a way in C# for creating a button which will support opacity - instead of just appearing when show method is called, to have the ability to slowly fade it into view.
I created my own button and I would like to know what you think of the implementation.
Basically, I created a Windows Form, which supports opacity property and handled all the corner cases regarding "adding" a form to another form, specifically:
- location changed event
- the owner form lost focus
The form consist of a label, which represents the button's text and that's all.
The form constructor gets the text for the label, the desired size of the button and the speed (based on an Enum) for the button appear.
In the form load method the label is being located in the middle of the button
when the label or the form itself clicked a simple graphic is performed and an event is raised to whoever catches it.
My Code:
Created a Form - named buttonForm
Constructor
InitializeComponent();
this.Owner = owner;
_buttonText = buttonText;
_buttonSize = buttonSize;
_usedSpeedOpacity = SelectSpeedOpacity(showSpeed);
A method to illustrate click command - being called when the user clicks on the form and on the label itself:
this.Location = new Point(this.Location.X + 1, this.Location.Y);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
Thread.Sleep(50);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Location = new Point(this.Location.X - 1, this.Location.Y);
if (Button_Clicked != null)
{
Button_Clicked();
}
form load - locating the label in the middle of the control etc
labelButtonText.Text = _buttonText;
this.Size = _buttonSize;
double remainning = this.Width - labelButtonText.Size.Width;
Point labelNewLocation = new Point(
(int)(remainning / 2),
(int)(this.Height / 2 - this.Font.Height / 2));
labelButtonText.Location = labelNewLocation;
FadeShow (and FadeHide the same)
int tempCounter = 0;
Opacity = 0;
Show();
while (tempCounter <= 1000)
{
if (Opacity == 1.0)
{
break;
}
if (tempCounter % 10 == 0)
{
Opacity += _usedSpeedOpacity;
}
Refresh();
tempCounter++;
}
this.Visible = true;
this.BringToFront();
Update location method so when the parent form moves i call this method
this.Location = new Point(
this.Location.X - (ParentFormLocation.X - newLocation.X),
this.Location.Y - (ParentFormLocation.Y - newLocation.Y));
ParentFormLocation = newLocation;
An event of my button_click
Thanks in advance,
Oz.
I did something similar with a windows form that changed its height. The way I did it was to implement a timer within the code so every half a second the opacity changed.
While the below is not a 100% correct answer without your code its difficult to show you.
void timer_Tick(object sender, EventArgs e)
{
if (btnName.Opacity < 100)
{
btnName.Opacity++;
timer2.Stop();
timer2.Interval = 5000;
timer2.Start();
} else {
timer2.Stop();
}
}