Drawing characters to form at timer tick - c#

I am trying to draw a character on the screen every 500 milliseconds but they won't appear on the screen
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
PictureBox pb;
Bitmap surface;
Graphics device;
Timer timer;
int num = 0;
string text = "This is a test";
char[] textChar;
Font font = new Font("Black Ops One", 20, FontStyle.Regular, GraphicsUnit.Pixel);
private void Form4_Load(object sender, EventArgs e)
{
//picture box
pb = new PictureBox();
pb.Parent = this;
pb.Dock = DockStyle.Fill;
pb.BackColor = Color.Black;
//create graphics device
surface = new Bitmap(this.Size.Width, this.Size.Height);
pb.Image = surface;
device = Graphics.FromImage(surface);
//set up timer
timer = new Timer();
timer.Interval = 500;
timer.Enabled = true;
timer.Tick += new System.EventHandler(TimerTick);
//mis
textChar = text.ToCharArray();
}
public void TimerTick(object sender, EventArgs e)
{
DrawText();
if (num > textChar.Length - 1)
{
timer.Enabled = false;
MessageBox.Show("have hit the end");
}
}
public void DrawText()
{
device.DrawString(textChar[num].ToString(), font, Brushes.Red, 10, 10 + num * 22)
num++;
}
}
I hope to have the form at the end have the string on the form, but have the characters come up one by one. The form won't show any of the text. It only shows a black background.

You need to make the bitmap the image of the picture box pb.Image = surface.
public void DrawText()
{
device.DrawString(textChar[num].ToString(), font, Brushes.Red, 10, 10 + num * 22)
num++;
pb.Image = surface;
}

Related

Label printer not printing correctly starts from the begining instead of the end

I have the following code, but its printing from the start of the label and trying to print forward when it should start from the end of the label and print forward.. I have an image below for reference, I have looked on stackoverflow for similar questions but no luck. Thank you for your time and efforts to help me.
using System;
using System.Drawing;
using System.Drawing.Printing;
using Gtk;
public partial class MainWindow : Gtk.Window
{
public MainWindow() : base(Gtk.WindowType.Toplevel)
{
Build();
}
protected void OnDeleteEvent(object sender, DeleteEventArgs a)
{
Application.Quit();
a.RetVal = true;
}
public void Print()
{
using (PrintDocument pd = new PrintDocument())
{
var width = 2.44 * 100;
var height = 100;
var s = new System.Drawing.Printing.PaperSize("Custom", (int)width, (int)height);
pd.DefaultPageSettings.PaperSize = s;
pd.DefaultPageSettings.Landscape = true;
pd.DocumentName = "Label";
pd.OriginAtMargins = true;
pd.PrintPage += Pd_PrintPage;
pd.Print();
}
}
private void Pd_PrintPage(object sender, PrintPageEventArgs e)
{
Font drawFont = new Font("Arial", 60);
SolidBrush drawBrush = new SolidBrush(Color.Black);
StringFormat drawFormat = new StringFormat();
e.HasMorePages = false;
e.Graphics.DrawString(LabelPreview.Buffer.Text, drawFont, drawBrush, 0, 0, drawFormat);
}
protected void OnButton1Released(object sender, EventArgs e)
{
Print();
}
}
Here is the image
Please try to add pd.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0); after pd.OriginAtMargins = true;.
The default value of pd.DefaultPageSettings.Margins is 1-inch margins on all sides.

Use a KeyDown inside a Timer_Tick Event

Me and my buddy have been working on this magnifier application and we cannot make it work the way we want it.
The way we would like it to work:
Open app.
Move mouse to area you want magnified.
Hit enter.
Magnifying window moves to (offset) location of mouse and keeps updating that window for that specific location.
Hit enter again to move window to new cursor location.
Right now once i hit enter, the window follows the mouse because it goes into a for loop where it grabs "Cursor.Position". I've tried to save the Cursor.Position value at the "OnkeyDown" event and use it inside the timer loop but that won't work since it "does not exist in current context".
Can anyone see how i can do this?
Thanks in advance!
/Morten
/* O-button zooms out
* I-button zooms in
* Esc-button exits app
* Enter moves magnifying window to new location (doesn't work)
*/
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Magnifier
{
public partial class Form1 : Form
{
Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
PictureBox pictureBox1 = new PictureBox();
int zoom = 3; //zoom level
public bool NewZoomLocation = false;
public Form1()
{
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
Controls.Add(pictureBox1);
FormBorderStyle = FormBorderStyle.None;
Timer timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{ var position = Cursor.Position;
int xlocation = position.X;
int ylocation = position.Y;
{
try
{
var graphics = Graphics.FromImage(printscreen as Image);
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
GC.Collect(); // Force the garbage collector (deals with memory leak)
if (NewZoomLocation == true)
{
var lensbmp = new Bitmap(50, 50); //Bitmap for Zoom window
var i = 0;
var j = 0;
for (int row = xlocation - 25; row < xlocation + 25; row++)
{
j = 0;
for (int column = ylocation - 25; column < ylocation + 25; column++)
{
lensbmp.SetPixel(i, j, printscreen.GetPixel(row, column));
j++;
}
i++;
}
this.pictureBox1.Image = new Bitmap(lensbmp, lensbmp.Width * zoom, lensbmp.Height * zoom);
Size = pictureBox1.Image.Size;
Left = xlocation - 45 * (zoom); //Horisontal position of final zoom window
Top = ylocation + 30; //Vertical position of final zoom window
TopMost = true;
}
}
catch //(Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyValue == 73) // I-button to zoom in
zoom++;
else if (e.KeyValue == 79) // O-button to zoom in
zoom--;
else if (e.KeyValue == 27) // Esc-button to exit
{
Close();
Dispose();
}
else if (e.KeyValue == 13) // Enter-button to choose zoon area
{
NewZoomLocation = true;
}
base.OnKeyDown(e);
}
}
}
I'm not really sure what you want to achieve here, however this should get you in a better place.
First thing first. The use of GC.Collect its because you are trying to plug a memory leak, if you ever create an image, dispose of it.
Given some globals
private readonly PictureBox pictureBox1 = new PictureBox();
private Bitmap _lastBmp = new Bitmap(300, 300);
private Point _position;
public bool NewZoomLocation;
private int zoom = 3; //zoom level
Constructor
public Form1()
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
Controls.Add(pictureBox1);
FormBorderStyle = FormBorderStyle.None;
KeyPreview = true;
Size = _lastBmp.Size;
TopMost = true;
var timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Start();
}
Cleanup
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_lastBmp.Dispose();
_lastBmp = null;
}
Keydown
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
base.OnPreviewKeyDown(e);
switch (e.KeyCode)
{
case Keys.Enter:
NewZoomLocation = true;
_position = Cursor.Position;
break;
case Keys.Up:
zoom++;
break;
case Keys.Down:
zoom--;
break;
case Keys.Escape:
Close();
break;
}
}
Timer
private void timer_Tick(object sender, EventArgs e)
{
if (NewZoomLocation)
{
var w = _lastBmp.Size.Width / zoom;
var h = _lastBmp.Size.Height / zoom;
var x = _position.X - w / 2;
var y = _position.Y - h / 2;
var size = new Size(w, h);
using (var screen = new Bitmap(size.Width, size.Height))
{
using (var g = Graphics.FromImage(screen))
{
g.CopyFromScreen(new Point(x, y), Point.Empty, size);
}
// resize
using (var g = Graphics.FromImage(_lastBmp))
{
g.DrawImage(screen, new Rectangle(new Point(), _lastBmp.Size), new Rectangle(0, 0, w, h), GraphicsUnit.Pixel);
}
}
pictureBox1.Image = _lastBmp;
}
}
There is a lot more that can be done with this, however it should get you started. There is no memory leak anymore, it only grabs a screen shot of what it needs so will be faster.
Good luck

Second timer.Start() isn't being triggered by first timer tick

So I have a small logo in the lower right corner of a Form that I want to fade in and out at a preset speed, about 6 seconds per fade. I have tried a few different methods but I can never get the picture to fade back in again once the first timer has finished. Here's my code for the the 2 timers and their respective tick methods.
EDIT The declarations for the timers included now.
Timer fade = new Timer();
Timer fade2 = new Timer();
fade.Interval = (200);
fade.Tick += new EventHandler(fade_Tick);
fade2.Interval = (200);
fade2.Tick += new EventHandler(fade_Tick_Two);
fade.Start();
private void fade_Tick(object sender, EventArgs e)
{
if (alpha < 255)
{
image = picboxPic.Image;
using (Graphics g = Graphics.FromImage(image))
{
Pen pen = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width);
g.DrawLine(pen, -1, -1, image.Width, image.Height);
g.Save();
}
picboxPic.Image = image;
this.Invalidate();
alpha++;
}
else
{
fade.Stop();
fade2.Start();
}
}
private void fade_Tick_Two(object sender, EventArgs e)
{
if (alpha > 0)
{
image = picboxPic.Image;
using (Graphics g = Graphics.FromImage(image))
{
Pen pen = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width);
g.DrawLine(pen, -1, -1, image.Width, image.Height);
g.Save();
}
picboxPic.Image = image;
this.Invalidate();
alpha--;
}
else
{
fade2.Stop();
fade.Start();
}
}
Any ideas as to why the second timer won't start? I've used breakpoints and the alpha level does reach 255 but then it doesn't trigger the second Tick event.
The method described in the link I quoted works for me:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
test();
}
System.Timers.Timer fade = new System.Timers.Timer(50);
System.Timers.Timer fade2 = new System.Timers.Timer(50);
Image originalImage = Image.FromFile(#"D:\kevin\Pictures\odds&Sods\kitchener.jpg");
int alpha = 100;
void test()
{
fade.Elapsed +=new System.Timers.ElapsedEventHandler(fade_Tick);
fade2.Elapsed+=new System.Timers.ElapsedEventHandler(fade_Tick_Two);
fade.Start();
}
delegate void timerDelegate(object sender, EventArgs e);
private void fade_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new timerDelegate(fade_Tick), sender, e);
return;
}
if (alpha >= 0)
{
picboxPic.Image = SetImgOpacity(originalImage, alphaToOpacity(alpha));
picboxPic.Invalidate();
alpha--;
}
if (alpha < 0)
{
alpha = 0;
fade.Stop();
fade2.Start();
}
}
private void fade_Tick_Two(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new timerDelegate(fade_Tick_Two), sender, e);
return;
}
if (alpha <= 100)
{
picboxPic.Image = SetImgOpacity(originalImage, alphaToOpacity(alpha));
picboxPic.Invalidate();
alpha++;
}
if (alpha > 100)
{
alpha = 100;
fade2.Stop();
fade.Start();
}
}
float alphaToOpacity(int alpha)
{
if (alpha == 0)
return 0.0f;
return (float)alpha / 100.0f;
}
//Setting the opacity of the image
public static Image SetImgOpacity(Image imgPic, float imgOpac)
{
Bitmap bmpPic = new Bitmap(imgPic.Width, imgPic.Height);
Graphics gfxPic = Graphics.FromImage(bmpPic);
ColorMatrix cmxPic = new ColorMatrix();
cmxPic.Matrix33 = imgOpac;
ImageAttributes iaPic = new ImageAttributes();
iaPic.SetColorMatrix(cmxPic, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
gfxPic.DrawImage(imgPic, new Rectangle(0, 0, bmpPic.Width, bmpPic.Height), 0, 0, imgPic.Width, imgPic.Height, GraphicsUnit.Pixel, iaPic);
gfxPic.Dispose();
return bmpPic;
}
}
The code is a bit crude and you will need to take care of the dispose when you close the form, but it fades up and and down and the rest can easily be taken care of - I also made it quicker for testing 'cos life's short :-)

C# WPF Thread accessed from a thread other than the

I'm trying to create a WPF application that takes a video and screenshots it every second while playing.
Code
public Form2(string url)
{
InitializeComponent();
axWindowsMediaPlayer1.URL = url;
new Thread(delegate(){
CheckFrame();
}).Start();
}
private void CheckFrame()
{
for (int i = 0; i < 100; i++)
{
Bitmap screenshot = new Bitmap(axWindowsMediaPlayer1.Bounds.Width, axWindowsMediaPlayer1.Bounds.Height);
Graphics g = Graphics.FromImage(screenshot);
g.CopyFromScreen(axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).X,
axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).Y, 0, 0, axWindowsMediaPlayer1.Bounds.Size);
pictureBox1.BackgroundImage = screenshot;
System.Threading.Thread.Sleep(1000);
}
}
When using the x y values of the media player itself I get the error
Additional information: Cross-thread operation not valid: Control 'axWindowsMediaPlayer1'
accessed from a thread other than the thread it was created on.
When using 0 as X/Y values so just 0px and 0px from the form point of view,it runs fine
In this case you can use Timer:
Timer tm = new Timer();
public Form2(string url)
{
InitializeComponent();
axWindowsMediaPlayer1.URL = url;
tm.Interval = 1000;
tm.Tick += tm_Tick;
tm.Start();
}
int i = -1;
void tm_Tick(object sender, EventArgs e)
{
if (++i < 100)
{
Bitmap screenshot = new Bitmap(axWindowsMediaPlayer1.Bounds.Width, axWindowsMediaPlayer1.Bounds.Height);
Graphics g = Graphics.FromImage(screenshot);
g.CopyFromScreen(axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).X,
axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).Y, 0, 0, axWindowsMediaPlayer1.Bounds.Size);
pictureBox1.BackgroundImage = screenshot;
}
else
{
i = -1;
tm.Stop();
}
}
Note: To take screenshot with your method, axWindowsMediaPlayer1 must visible on the screen.

winForm invalidate(rectangle)

I'd like to draw animation where the airplane crossing form from leftside to the right.
public partial class Form1 : Form
{
Bitmap sky, plane, background;
int currentX, currentY;
Random rndHeight;
Rectangle planeRect;
Graphics g;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
sky = new Bitmap("sky.jpg");
plane = new Bitmap("plane1.png");
int planeWidth = plane.Width; int planeHeight = plane.Height;
}
catch (Exception) { MessageBox.Show("No files!"); }
this.ClientSize = new System.Drawing.Size(sky.Width, sky.Height);
this.FormBorderStyle = FormBorderStyle.FixedSingle;
background = new Bitmap(sky);
g = Graphics.FromImage(background);
rndHeight = new Random();
currentX = -plane.Width; currentY = rndHeight.Next(0, this.Height);
this.BackgroundImage = background;
timer1.Interval = 1;
timer1.Enabled = true;
timer1.Start();
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImage(sky, 0, 0);
e.Graphics.DrawImage(plane, planeRect);
}
private void timer1_Tick(object sender, EventArgs e)
{
g.DrawImage(sky, 0, 0);
planeRect.X = currentX; planeRect.Y = currentY; planeRect.Width = plane.Width; planeRect.Height = plane.Height;
g.DrawImage(plane, planeRect);
Rectangle myNewPlane = new Rectangle(planeRect.X - 10, planeRect.Y - 10, planeRect.Width + 20, planeRect.Height + 20);
this.Invalidate(myNewPlane);
if (currentX >= this.Width) currentX = -plane.Width; else currentX += 2;
currentY += rndHeight.Next(-2, 2);
}
}
This code works, but the Rectangle of plane flickers with the frequency of timer1.Interval. My question is: how can I avoid these flickers?
p.s.: background image resolution 1024x768; plane - 160x87. plane is transparent
You fix this by setting the DoubleBuffering style for your Form to remove the flicker, e.g.
DoubleBuffered = true;
You probably want to set a few more control styles as well for automatic double-buffering (after InitializeComponents)
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,true);
More information about automatic and manual double-buffering is on MSDN here

Categories