I want programmatically put an image into the form which is not active.
Image myImage = new Image();
gfx = Form.ActiveForm.CreateGraphics();
gfx.DrawImage(myImage, 0,0);
It's will be working perfectly only if the form is active, but it's make no sense when the form is not active, just returns me an error:
In an instance of an object reference not set to an object.
how to handle the form which is not active in my application and put a picture to it?
upd 1
I did instance, and turned on DoubleBuffered property (true) but nothing happens:
Form1 form = new Form1();
gfx = form.CreateGraphics();
gfx.DrawImage(bmp, 0, 0);
upd 2 More Source, it's my added class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Printing;
namespace testimg
{
class doimg
{
public void picture()
{
// some staffs to get a picture, so it's in bmp object now.
gfx = this. // watch picture below
gfx.DrawImage(bmp, 0, 0);
// I tried to use PictureBox, but it's the same issue (I can't handle it on a form)
PictureBox pb = new PictureBox();
pb.CreateGraphics();
pb.DrawToBitmap(bmp,pb.ClientRectangle);
}
}
}
and a picture for the Arif Eqbal solution: no graph methods for this (pic)
upd 3
The full source what I have (timer is on a 10 sec)
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace testimg
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
doimg pic = new doimg();
pic.picture();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
}
}
doimg.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Printing;
namespace testimg
{
class doimg
{
public void picture()
{
// some staffs to get a picture, so it's in bmp object now.
Bitmap bmp = new Bitmap(200, 200, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics gfx = Graphics.FromImage(bmp);
gfx = Form1.ActiveForm.CreateGraphics(); // works well with active form
gfx.DrawImage(bmp, 0, 0);
}
}
}
and whole archive with project http://www.filedropper.com/testimg
as you can see all running well while the program is active. Still need help.
On your Form2, try to set it up like this:
public partial class Form2 : Form {
public Image MyImage { get; set; }
public Form2() {
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e) {
if (MyImage != null) {
e.Graphics.DrawImage(MyImage, 0, 0);
}
base.OnPaint(e);
}
}
Then from your active form, you can call the other form to draw itself:
public partial class Form1 : Form {
Form2 f2 = new Form2();
public Form1() {
InitializeComponent();
f2.Show();
}
private void button1_Click(object sender, EventArgs e) {
f2.MyImage = myImage;
f2.Invalidate();
}
}
Part of the problem is that when you are setting your bitmap the Form is not updating, expecially if it is minimized or doesn't have focus. You also have the issue that since it is not being set in the Paint Event Handler you have no retention of the Image. Try something like this, Note the Invalidate call and the Timer was set for 10,000 ms. This is a variation of #LarsTech's answer if you are working with multiple Forms his is the way to go.
public partial class Form1 : Form
{
Bitmap myImage;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
myImage = new Bitmap("Your Image Name Here");
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (myImage != null)
e.Graphics.DrawImage(myImage,0,0);
}
}
Modifed my Example to work with the OP's structure:
My original example does work when the form does not have focus. Your main problem with the error is using Form1.ActiveForm when it is not the active form, it will return null which is causing your error. Use the Forms Paint Event and Invalidate the Form to insure that the Image is painted.
Form1.cs
namespace testimg
{
public partial class Form1 : Form
{
Bitmap myImage;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
myImage = doimg.picture();
Invalidate();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (myImage != null)
e.Graphics.DrawImage(myImage,0,0);
}
}
}
doimg.cs
namespace testimg
{
static class doimg
{
static Color[] clr = new Color[] { Color.Red, Color.Blue, Color.Black, Color.Violet, Color.Wheat };
static int count = 0;
static public Bitmap picture()
{
// some staffs to get a picture, so it's in bmp object now.
Bitmap bmp = new Bitmap(200, 200, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// Added some drawing to bitmap to test functionality
Graphics gfx = Graphics.FromImage(bmp);
gfx.FillEllipse(new SolidBrush(clr[count]),new Rectangle(0,0,199,199));
gfx.Dispose();
if (count >= 4)
count = 0;
else
count += 1;
return bmp;
}
}
}
You have to create an instance of your form.. regardless of whether it's visible and active.
Example:
Image myImage = new Image(); // load image
MyForm form = new MyForm();
gfx = form.CreateGraphics();
gfx.DrawImage(myImage, 0, 0);
Then you will be able to call form.Show() when you want to show the form.
(Note, you'll probably also have to set DoubleBackBuffer on the form to true.
I think I can make a sense of it...is it that your code to Get the instance of the form and draw on it run on a timer? And your application has just one form? And you run into issues when the Application is not Active?
If Yes then replace the line
Form.ActiveForm.CreateGraphics();
with
this.CreateGraphics();
Form.ActiveForm gives the reference of the currently Active Form for the Application, if you write this code on say a Button click you are bound to get the name of the Form on which the Button was clicked. However, if the code is on a timer it might give the instance of the Active form or Null if the entire application is not Active.
As you have mentioned in one of the comments that you do not have any other form, it appears that your application has just one form and this code is running on the only form in the app so this.CreateGraphics should suffice. However, if your application has more than one form then Form.ActiveForm is a legitimate code but you need to take care of the scenario when no form is active i.e. the application itself is not active.
EDIT:
I think you need to pass the instance of the Form on which you want to draw to this class. Make a properry and set the property value to the instance of the form, you might pass it in the constructor as well...using Form.ActiveForm was not a bad idea here but for 2 reasons, tomorrow if you had more than one form in your app it will draw randomly on whicheever is active, second as in your current case if the app is not active you will not get hold of the instance...since you have only one form in your app I suppose you would be creating the instance of this Class on the form so may be you can add a property
public Form ParentForm { get; set; }
in the class and set it as
myClassObject.ParentForm = this;
on the form when you create an instance of this class and then say
ParentForm.CreateGraphics
in the class
Related
I am trying to get an input values from user for drawing a Circle ( for this I use Radius input) and a Rectangle ( Edge1 and Edge2 ) inputs. I want to pass these textboxt values on another form to draw them.
How can I move these values to another form in properties section or any solution ideas?
Forms are in the same project by the way.
I defined an interface and implement processes about calculations. My code is below and worked, thank you for responds.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assignment2
{
class CircleShape : Shape, IShape
{
public int radius;
public CircleShape(int radius)
{
this.radius = radius;
}
public double CalculateArea()
{
return Math.PI * radius * radius;
}
public double CalculatePerimeter()
{
return 2 * Math.PI * radius;
}
}
}
One way is to just have a method on your second form that returns any needed details
using (DrawForm drawForm = new DrawForm ())
{
drawForm.ShowDialog(); //will wait for the form to close before continuing
var userResults = drawForm.GetResults(); //returns whatever you need the form to return
return userResults;
}
The above logic only works if the second form is a popup form of sorts. If you want both forms to be persistent, then it's a bit different. You might want to ensure both forms have access to each other. When you create the drawform be sure to save a reference to it. and in the constructor for your drawform add an argument to include the main form.
DrawForm drawForm = new DrawForm(this);//now the forms can talk to each other
in your drawing form when the user hits 'go'
mainForm.TriggerFinishedDrawing(drawingObject);
There are several ways to achieve this sort of behaviour, you just need to decide what sort of flow makes the most sense in your use case
A simple way to pass data from a form to another one is that you can use Application.OpenForms Property.
First, define a TextBox property to access the TextBox instance in Form1.
// Form1.cs
public TextBox TB
{
get { return textBox1; }
set { textBox1 = value; }
}
Then call Application.OpenForms to get Form1 instance.
// Form2.cs
Form1 fr = (Form1)Application.OpenForms["Form1"];
if (fr != null)
{
Form1 f1 = (Form1)fr;
// get text form Form1.textbox1
MessageBox.Show(f1.TB.Text);
}
If Form2 is opened by clicking the button in Form1 and pass the value when Form2 shown, you can achieve it via constructor.
// Form1.cs
private void btnOpenForm2_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2(textBox1.Text);
f2.Show();
}
// From2.cs
string textformForm1;
public Form2(string str)
{
InitializeComponent();
textformForm1 = str;
}
private void btnShowText_Click(object sender, EventArgs e)
{
MessageBox.Show(textformForm1);
}
Similarly, you can also use public properties.
// Form1.cs
private void btnOpenForm2_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.TextformForm1 = textBox1.Text;
f2.Show();
}
// Form2.cs
public string TextformForm1 { get; set; }
private void btnShowText_Click(object sender, EventArgs e)
{
MessageBox.Show(TextformForm1);
}
I want to call a function like Spawn() in this case, but without losing values from it after calling it (for example, I want entityPicture to still be available after I call Spawn(), so I can use it later on MainWindow_KeyDown() function). Same with X and other variables like that.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace EpicGame
{
public partial class MainWindow : Form
{
public MainWindow()
{
InitializeComponent();
}
public void MainWindow_Load(object sender, EventArgs e)
{
int EntityCount = 0;
Background.ImageLocation = "Background.jpg";
Background.SizeMode = PictureBoxSizeMode.AutoSize;
Spawn(600, 600, EntityCount, "Player 1.png"); EntityCount++;
}
// Controls
public void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.D) MoveRight();
entityPicture.Location = new Point(X, Y);
}
// Movement
public void MoveRight()
{
X++;
}
// Entity spawning
public void Spawn(int X, int Y, int ID, string Path)
{
PictureBox entityPicture = new PictureBox();
Image Entity = Image.FromFile(Path);
entityPicture.Image = Entity;
entityPicture.SizeMode = PictureBoxSizeMode.AutoSize;
entityPicture.Location = new Point(X, Y);
entityPicture.BackColor = Color.Transparent;
Controls.Add(entityPicture);
entityPicture.BringToFront();
}
private void Background_Click(object sender, EventArgs e)
{
}
}
}
You can declare it public in the form class like:
public partial class MainWindow : Form
{
PictureBox entityPicture = new PictureBox();
}
I don't know the type of entityPicture so just used PictureBox as example, you use the correct type.
Your root issue is one of scope. Have a look at this video, it walks through your exact issue: https://www.youtube.com/watch?v=NemPMKTxM7w
You can technically move entityPicture to the top of the class, however given this appears to be a WinForms window, I would add the PictureBox via the designer so it's only declared once. If you declare it at the class level and reinitialize it in Spawn (i.e. = new PictureBox()) repeatedly, you're going to create a memory leak.
I have two forms. In first I have button forwarding me to second form and hiding the first one with this.Hide();
It looks like this:
Form1Streamer f1 = new Form1Streamer();
f1.Left = this.Left;
f1.Top = this.Top;
f1.Size = this.Size;
f1.Show();
this.Hide();
checkBox1.Checked = false;
It also takes it's position but it's not about it.
In second form I have a button which should after clicking Go back to the hidden form and make it visible again, but I can find no solution how to access it's properity.
I have some ideas but don't really know how to tag it. Any help appreciated.
You need to pass the reference of the first form to the second form in order to call any method of first form. Here is a simple Example that will demonstrate.
Below is my first form class
using System;
using System.Windows.Forms;
namespace Test_Desktop
{
public partial class FirstForm : Form
{
public FirstForm()
{
InitializeComponent();
}
private void showSecondFormButton_Click(object sender, EventArgs e)
{
SecondForm secondform = new SecondForm(this); //Passing the reference of current form i.e. first form
secondform.Show();
this.Hide();
}
}
}
And here is my second form class
using System;
using System.Windows.Forms;
namespace Test_Desktop
{
public partial class SecondForm : Form
{
private FirstForm firstForm = null;
public SecondForm()
{
InitializeComponent();
}
///
/// Overriding constructor
///
public SecondForm(FirstForm firstForm)
{
InitializeComponent();
this.firstForm = firstForm;
}
private void showFirstFormButton_Click(object sender, EventArgs e)
{
if(firstForm!=null)
{
firstForm.Show();
//
//Do some processing
//
this.Dispose();
}
}
}
}
You need the reference of hidden form in the second form. For that, change the constructor of Second form like this
public Form1Streamer(Form firstform)
{
InitilizeComponent();
this.firstForm=firstform;
}
private FirstForm firstForm;
Now you can show the First Form using reference firstForm
In first form, you need to change this code
Form1Streamer f1 = new Form1Streamer();
to
Form1Streamer f1 = new Form1Streamer(this);
I am using a ToolStrip with a number of ToolStripButtons.
What I would like is to be able to flash one of the buttons to get the user's attention.
For example, if they have made changes to information and need to click the Save button.
If this were a normal button I could do this using a Timer and periodically changing the BackColor however this doesn't work with a ToolStrip.
I could create a Renderer subclass and assign it to the ToolStrip but this appears to only get used in specific situations - i.e. it's event driven.
Does anyone have any ideas?
Well, just use a custom renderer so you can change the color of the button's background. With a timer that blinks it. Add a new class to your project and paste this code:
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Windows.Forms;
class BlinkingButtonRenderer : ToolStripProfessionalRenderer {
public BlinkingButtonRenderer(ToolStrip strip) {
this.strip = strip;
this.strip.Renderer = this;
this.strip.Disposed += new EventHandler(strip_Disposed);
this.blinkTimer = new Timer { Interval = 500 };
this.blinkTimer.Tick += delegate { blink = !blink; strip.Invalidate(); };
}
public void BlinkButton(ToolStripButton button, bool enable) {
if (!enable) blinkButtons.Remove(button);
else blinkButtons.Add(button);
blinkTimer.Enabled = blinkButtons.Count > 0;
strip.Invalidate();
}
protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e) {
var btn = e.Item as ToolStripButton;
if (blink && btn != null && blinkButtons.Contains(btn)) {
Rectangle bounds = new Rectangle(Point.Empty, e.Item.Size);
e.Graphics.FillRectangle(Brushes.Black, bounds);
}
else base.OnRenderButtonBackground(e);
}
private void strip_Disposed(object sender, EventArgs e) {
blinkTimer.Dispose();
}
private List<ToolStripItem> blinkButtons = new List<ToolStripItem>();
private bool blink;
private Timer blinkTimer;
private ToolStrip strip;
}
Sample usage in a form with a Toolstrip containing a button:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
blinker = new BlinkingButtonRenderer(toolStrip1);
}
private void toolStripButton1_Click(object sender, EventArgs e) {
blink = !blink;
blinker.BlinkButton(toolStripButton1, blink);
}
private bool blink;
private BlinkingButtonRenderer blinker;
}
I'm trying to build a multithreaded game where I have a separate thread for painting on the form which is not the main thread. this brings us to thread-safe technics which I've read many articls about, but I'm not really sure I got it correctly.
my problem is that I have a structure where every data object is painting it self on the form so I didn't figure out how to implement it.
this is a snippet of my working mono-thread code:
public partial class Form1 : Form
{
GameEngine Engine;
public Form1()
{
InitializeComponent();
Engine = new GameEngine();
}
protected override void OnPaint(PaintEventArgs e)
{
Engine.Draw(e.Graphics);
}
}
class GameEngine
{
Maze Map;
List<Player> Players;
public void Draw(Graphics graphics)
{
Map.Draw(graphics);
foreach (var p in Players)
{
p.Draw(graphics);
}
}
}
so please can anyone give me a hint or a link to good article helping me to learn how to separate the drawing on an another thread?.
[Edit]
I managed to implement what I intended to do
and this is how I coded it
protected override void OnPaint(PaintEventArgs e)
{
formGraphics = e.Graphics;
DisplayThread = new Thread(new ThreadStart(Draw));
DisplayThread.Start();
}
private void Draw()
{
if (this.InvokeRequired)
{
this.Invoke(new DrawDelegate(this.Draw));
}
else
{
Engine.Draw(formGraphics);
}
}
but I got an ArgumentException : Parameter is not valid
would you please point to the error in that code
I think you will need to draw to a Bitmap, then in the OnPaint Method, draw that bitmap to the window. I will demonstrate in a moment.
As Hans pointed out, in the OnPaint method you are setting
formGraphics = e.Graphics;
but at the end of the method e.Graphics is disposed, so you can't use it anymore, if your code got to
Engine.Draw(formGraphics);
you would get an exception.
So basically you need to have a global
Bitmap buffer = new Bitmap(this.Width, this.Height)
in your asynced thread you would invoke your drawing to that Bitmap you can use
Graphics g=Graphics.FromBitmap(buffer);//
To get a graphics object, but remember you have to
g.Dispose()
it or wrap it in a
using (Graphics g=Graphics.FromBitmap(buffer))
{
//do something here
}
I am going to play with it for a few moments and see if I can get you a working sample
EDIT Here's your working sample.
I started a new form and tossed a button on it. I changed the mainform backgroundimagelayout to none.
I think you need to be using .net 4.0 or better, if not using this, let me know I can change it to match your version... I think.
//you need this line to use the tasks
using System.Threading.Tasks;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Draw()
{
Bitmap buffer;
buffer = new Bitmap(this.Width, this.Height);
//start an async task
Task.Factory.StartNew( () =>
{
using (Graphics g =Graphics.FromImage(buffer))
{
g.DrawRectangle(Pens.Red, 0, 0, 200, 400);
//do your drawing routines here
}
//invoke an action against the main thread to draw the buffer to the background image of the main form.
this.Invoke( new Action(() =>
{
this.BackgroundImage = buffer;
}));
});
}
private void button1_Click(object sender, EventArgs e)
{
//clicking this button starts the async draw method
Draw();
}
}
}