473,322 Members | 1,494 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

Pens are tricky, hard to assign (Colors too) inside of paint handler

Just an observation: pens for drawing lines in Win Forms are tricky
when assignment is inside the paint handler.

inside of the Paint handler, but not inside a "using" brace (that is,
outside of "using { Pen mypen = new Pen(Color.Black, 1)) {}), which I
think makes a difference:

I find the following assignment does not work:

//myPenTest instantiated in the normal constructor, as was baseline,
both of Pen class

myPenTest = myobject.tPen; //does not work to assign
properties of myobject to myPenTest
myPenTest.Color = myobject.tPen.Color; //does not work
either

both Pens retain their own Color property. Perhaps Color is hard to
set, or perhaps since it's outside a 'using' bracket the myPenTest is
somehow local. But adding this line (in Paint) did not help:
myPenTest = new Pen(Color.Salmon); //does not help

All is not lost, and in fact this 'failure' is trivial, since color
property is maintained by the pens (albeit not assignable), hence the
myobject.tPen.Color property was successfully used in Paint
handler:

using (Pen pen = new Pen(myobject.tPen.Color, 1))
{
g.DrawLine(pen, XY0, XY1); //works fine, uses
tPen.Color
}

Just an observation. If anybody has seen this before I'd be curious as
to why, but not a big deal.

RL
Aug 19 '08 #1
9 2324
raylopez99 <ra********@yahoo.comwrote:
Just an observation: pens for drawing lines in Win Forms are tricky
when assignment is inside the paint handler.

inside of the Paint handler, but not inside a "using" brace (that is,
outside of "using { Pen mypen = new Pen(Color.Black, 1)) {}), which I
think makes a difference:

I find the following assignment does not work:

//myPenTest instantiated in the normal constructor, as was baseline,
both of Pen class

myPenTest = myobject.tPen; //does not work to assign
properties of myobject to myPenTest
That should be fine.
myPenTest.Color = myobject.tPen.Color; //does not work
either
This will work in some cases, but as the docs say, it will throw an
ArgumentException if you're using one of the predefined pens.
both Pens retain their own Color property. Perhaps Color is hard to
set, or perhaps since it's outside a 'using' bracket the myPenTest is
somehow local. But adding this line (in Paint) did not help:
myPenTest = new Pen(Color.Salmon); //does not help
Could you show a short but complete program which demonstrates the
problem? Here's a very short app which demonstrates simple assignment,
changing the colour of a pen (p2 changes colour from black to red) and
the form which you've had working:

using System;
using System.Drawing;
using System.Windows.Forms;

class PenTest : Form
{
Pen pen;

public PenTest(Pen pen)
{
this.pen = pen;
Size = new Size(200, 200);
}

static void Main()
{
Application.Run(new PenTest(Pens.Red));
}

protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;

Pen p1 = pen;
g.DrawLine(p1, 0, 20, 100, 20);

Pen p2 = new Pen(Color.Black);
p2.Color = Color.Green;
g.DrawLine(p2, 0, 40, 100, 40);

using (Pen p3 = new Pen(Color.Blue, 1))
{
g.DrawLine(p3, 0, 60, 100, 60);
}
}
}

The result (on my box at least!) is a form with three lines - red, then
green, then blue.

I'm sure with an appropriate failing example, we can sort out the
problem you're having.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Aug 19 '08 #2
OK, I tried various things and I think I figured it out.

Sorry no code, too complicated to try and cut and paste, but here's
what I think is happening:

the runtime error is clearly with the 'using pen {}' code. It only
happens when I resize the form (it works fine to show lines if the
form is never resized, and it's not null since I checked for the
condition: != null, which never occurs for myobject.tPen), because
when I resize the form I run three functions, part of a node manager
(the node manager has a list of lines), the three functions do not use
'new', but only take a scalar (the size of the client screen,
this.ClientSize). However, the myobject.tPen member variable is part
of the node manager. Perhaps, though I can't be sure, when you run
these three functions twice in a row (once in the constructor for the
form, and once upon resizing--this has to occur twice at least once,
upon startup of the form; and these three functions are necessary when
resizing the window because I want to redraw the lines so proportion
is maintained between the lines--I trust you know this trick) somehow
in the background the member myobject.tPen is instantiated again. In
which case, during OnPaint, you will clearly get (for a millisecond,
but enough) garbage collection and the old Pen myobject.tPen will go
out of scope, hence the exception.

Another possibility: Pen is somehow int while myobject.tPen uses
float, but I don't think so (the documentation for Pen is sketchy
IMO).

I tried this below trick but it failed to compile ("Cannot assign to
'pen' because it is a 'using variable'") (had it compiled I'm
confident it would have solved the problem!)

using (Pen pen = new Pen(Color.AliceBlue)) //note: manually insert new
pen Info since seems member variable myobject.tPen from
LineNodeManager cause runtime exception
{
pen.Width = 1.0f;
//trick: //pen = myobject.tPen; //Cannot assign to 'pen'
because it is a 'using variable'
g.DrawLine(pen, myPoint.StartXY, myPoint.EndXY);
}
//BTW the above code works as a fix to the problem, since Pen pen is
being used, not myobject.tPen, but my proposed 'trick' was to see if I
could sneak in the latter member variable in the back door, but I
could not).

Another possibility: I use (and correct me if I'm wrong) a helper
function that is stored in "myobject" to draw these lines. In other
words: MyNodeManagerClass myobjectMgr = new MyNodeManagerClass();
then, a member function of this class:

public void DisplayLine(PaintEventArgs e)
{
Graphics g = e.Graphics;

// etc etc
}

then, from Form1 Paint event handler I call this as follows, without
any 'override' keyword:

private void Form3_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;

myobjectMgr.DisplayLine(e);

// other similar 'helper' graphics methods here
// done to cut down on visual clutter, and also prevent name collision
}

Is this bad style? Let me know if you think this is 'bad style'.
Note Graphics g = e.Graphics is displayed twice, but I don't think
that's a problem.

In short, I solved my problem simply by replacing myobject.tPen with a
newly instantiated Pen, as shown above. The program works fine and
everything is great, even though I don't understand my error. This is
what I was alluding to in an earlier post--you have to either know C#
from the 'compiler' or IL engine level or at a deep level (which may
explain why, upon resizing, perhaps behind the scenes somehow the
member variable pen 'myobject.tPen' is in fact going out of scope),
or, you can learn though experience certain entry points or
'templates' that work, and then use these templates/entry points to
write code that works. Below is an example of this from my personal
diary, to make this point*. (please keep in mind I'm explaining how a
noob like me thinks, not recommending you adopt this yourself, as
clearly you and others here prefer a deeper understanding of the
language).

Hope that make sense and thanks for your reply.

RL

* saw common error in String.ToUpper() function (cannot use by itself,
since C# strings are immutable, but rather must use with another
instantiated string; e.g. string mystring = “sss”;
mystring.ToUpper(); //will not work to convert 'sss' to uppercase,
but : string upperString = new string(); string upperString =
mystring.ToUpper(); //will work, as will: mystring =
mystring.ToUpper(); // in this last case, the ‘old’ string is
technically discarded, with the ‘new’ uppercase string substituted, so
string still immutable.
Aug 19 '08 #3
raylopez99 <ra********@yahoo.comwrote:
OK, I tried various things and I think I figured it out.

Sorry no code, too complicated to try and cut and paste, but here's
what I think is happening:
It would really, *really* help to see some full code, I'm afraid. It
can (and should be!) a very cut down version, with only enough code to
trigger the problem - but without that I can't be confident in what's
wrong.
the runtime error is clearly with the 'using pen {}' code.
What runtime error were you getting?
It only
happens when I resize the form (it works fine to show lines if the
form is never resized, and it's not null since I checked for the
condition: != null, which never occurs for myobject.tPen), because
when I resize the form I run three functions, part of a node manager
(the node manager has a list of lines), the three functions do not use
'new', but only take a scalar (the size of the client screen,
this.ClientSize). However, the myobject.tPen member variable is part
of the node manager. Perhaps, though I can't be sure, when you run
these three functions twice in a row (once in the constructor for the
form, and once upon resizing--this has to occur twice at least once,
upon startup of the form; and these three functions are necessary when
resizing the window because I want to redraw the lines so proportion
is maintained between the lines--I trust you know this trick) somehow
in the background the member myobject.tPen is instantiated again. In
which case, during OnPaint, you will clearly get (for a millisecond,
but enough) garbage collection and the old Pen myobject.tPen will go
out of scope, hence the exception.
Without knowing what exception you're getting, it's hard to comment on
how feasible that is. However, if you've got a reference to the pen
within OnPaint, it shouldn't be garbage collected.
Another possibility: Pen is somehow int while myobject.tPen uses
float, but I don't think so (the documentation for Pen is sketchy
IMO).
Which part of the pen? How would they be different?
I tried this below trick but it failed to compile ("Cannot assign to
'pen' because it is a 'using variable'") (had it compiled I'm
confident it would have solved the problem!)
I don't see why you'd want to initialize a variable and then ignore its
value. I see no reason to think that would be any better than any other
assignment.
using (Pen pen = new Pen(Color.AliceBlue)) //note: manually insert new
pen Info since seems member variable myobject.tPen from
LineNodeManager cause runtime exception
{
pen.Width = 1.0f;
//trick: //pen = myobject.tPen; //Cannot assign to 'pen'
because it is a 'using variable'
g.DrawLine(pen, myPoint.StartXY, myPoint.EndXY);
}
//BTW the above code works as a fix to the problem, since Pen pen is
being used, not myobject.tPen, but my proposed 'trick' was to see if I
could sneak in the latter member variable in the back door, but I
could not).
You really shouldn't need to. Unless you're disposing of the pen
somewhere else, you should be fine to just copy the reference.
Another possibility: I use (and correct me if I'm wrong) a helper
function that is stored in "myobject" to draw these lines. In other
words: MyNodeManagerClass myobjectMgr = new MyNodeManagerClass();
then, a member function of this class:

public void DisplayLine(PaintEventArgs e)
{
Graphics g = e.Graphics;

// etc etc
}

then, from Form1 Paint event handler I call this as follows, without
any 'override' keyword:

private void Form3_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;

myobjectMgr.DisplayLine(e);

// other similar 'helper' graphics methods here
// done to cut down on visual clutter, and also prevent name collision
}

Is this bad style? Let me know if you think this is 'bad style'.
No, I don't think so - although I'd make DisplayLine take a Graphics as
the parameter rather than PaintEventArgs.
Note Graphics g = e.Graphics is displayed twice, but I don't think
that's a problem.
It's pointless, but not a problem.
In short, I solved my problem simply by replacing myobject.tPen with a
newly instantiated Pen, as shown above. The program works fine and
everything is great, even though I don't understand my error. This is
what I was alluding to in an earlier post--you have to either know C#
from the 'compiler' or IL engine level or at a deep level (which may
explain why, upon resizing, perhaps behind the scenes somehow the
member variable pen 'myobject.tPen' is in fact going out of scope),
or, you can learn though experience certain entry points or
'templates' that work, and then use these templates/entry points to
write code that works.
The trouble is that without understanding why it doesn't work, you
won't know what's wrong next time. It could well be that you'll be in a
*similar* situation, but your workaround may not work because the exact
cause is different. In addition, you're quite possibly bending your
design out of shape to work around a problem which can be solved in a
*much* simpler way.

I very much doubt that it really requires a particularly deep knowledge
of C# (and certainly not IL) - but without seeing the code which is
failing, we can't tell.
Below is an example of this from my personal
diary, to make this point*. (please keep in mind I'm explaining how a
noob like me thinks, not recommending you adopt this yourself, as
clearly you and others here prefer a deeper understanding of the
language).

Hope that make sense and thanks for your reply.

* saw common error in String.ToUpper() function (cannot use by itself,
since C# strings are immutable, but rather must use with another
instantiated string; e.g. string mystring = =3Fsss=3F;
mystring.ToUpper(); //will not work to convert 'sss' to uppercase,
More accurately, it will convert 'sss' to upper case as a new string -
which you then ignore.
but : string upperString = new string(); string upperString =
mystring.ToUpper(); //will work
I don't think you meant the first part of that, but the rest is fine.
as will: mystring = mystring.ToUpper();
Yup.
// in this last case, the =3Fold=3F string is
technically discarded, with the =3Fnew=3F uppercase string substituted, so
string still immutable.
It depends on exactly what you mean by "discarded" - the variable now
refers to a different string, certainly.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Aug 19 '08 #4
Thanks for your help. I consider this thread closed since I found a
workaround. Pen is not a problem. I will save uploading code for some
real serious problem; this is not one of them. Programming is not
that well documented IMO--it's trial and error--I'm sure VS2008 is
full of bugs waiting to be discovered. This bug/error is not a
serious problem for me, and I've got bigger fish to fry. I'm happy
for example to have learned a few weeks ago that doing a 'foreach' is
faster in many situations than doing a delegate/event call to
subscriber classes/member variables from a publisher class/variable.
This is precisely the situation in this program, which again uses
"resize" to redraw lines. A line is two points, and if a screen is
resized these two points become different points (relative to the
larger or smaller screen), so, what to do? Use 'foreach' and go
through a collection, updating the points (which is what I'm working
on tonight) or use a publisher-subscriber model? Based on a
discussion a few weeks ago I concluded the former is faster (if you
have fewer than a couple of hundred lines/nodes, as is the case
here). That's why this forum is invaluable--for stuff like that, not
debugging trivial stuff like this thread--so I don't want to waste
your time, you've done enough for me. BTW your book is not that bad,
LOL, but it has to be taken in small doses IMO for it to sink in.

Good night,

RL

Jon Skeet [ C# MVP ] wrote:
raylopez99 <ra********@yahoo.comwrote:
OK, I tried various things and I think I figured it out.
Aug 19 '08 #5
Could not resist getting in one more Parthian shot: here is the
compiler error
System.ArgumentException: Parameter is not valid.
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawLine(Pen pen, Single x1, Single y1,
Single x2, Single y2)
at System.Drawing.Graphics.DrawLine(Pen pen, PointF pt1, PointF
pt2)
It's quite possible that somehow, despite my double checking (and
again this is a moot point now that I've solved the problem by
rewriting some code), that it's a simple 'cast' problem where a point
is float and another point is Single (int?), nothing more serious than
that.

But it's moot.

RL
Aug 19 '08 #6
raylopez99 <ra********@yahoo.comwrote:
Could not resist getting in one more Parthian shot: here is the
compiler error
Just to be pedantic, more for the sake of future posts than anything
else, that's an exception which occurred at execution time. Compiler
errors occur at compile time.
System.ArgumentException: Parameter is not valid.
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawLine(Pen pen, Single x1, Single y1,
Single x2, Single y2)
at System.Drawing.Graphics.DrawLine(Pen pen, PointF pt1, PointF
pt2)

It's quite possible that somehow, despite my double checking (and
again this is a moot point now that I've solved the problem by
rewriting some code), that it's a simple 'cast' problem where a point
is float and another point is Single (int?), nothing more serious than
that.

But it's moot.
I don't think it's anything like that, but without being able to
reproduce it I guess we'll never know :)

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Aug 19 '08 #7
Jon Skeet [C# MVP] wrote:
raylopez99 <ra********@yahoo.comwrote:
>OK, I tried various things and I think I figured it out.

Sorry no code, too complicated to try and cut and paste, but here's
what I think is happening:

It would really, *really* help to see some full code, I'm afraid. It
can (and should be!) a very cut down version, with only enough code to
trigger the problem - but without that I can't be confident in what's
wrong.
>the runtime error is clearly with the 'using pen {}' code.

What runtime error were you getting?
I'm guessing this is the failing code:

class F:Form
{
Pen p = new Pen(Colors.Red);

override void OnPaint(PaintEventArgs pea)
{
//...
using (p) {
}
// ...
}
}

The solution is of course to eliminate the using block, and Dispose the Pen
in F.Dispose(bool disposing) and only if disposing is set.
Aug 28 '08 #8
On Aug 28, 12:42*pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>
The solution is of course to eliminate the using block, and Dispose the Pen
in F.Dispose(bool disposing) and only if disposing is set.
Thanks, that's pretty slick detective work.

Truth be told, I don't know what I did wrong, nor will I ever find out
since I did a workaround, but what you just alerted me to is the fact
that 'using' is not 'fail safe'. I assumed that 'using' cannot do you
wrong, in that if it's not needed it's just not used, but you alert me
to the fact this might not be the case. For IO operations Albahari
says 'using (Filestream fs = new Filestream ("myfile.txt",
FileMode.Open) { //} is equivalent to:

FileStream fs = new FileStream ("myFile.txt", FileMode.Open);
try { //} finally { if (fs != null) fs.Dispose();}

As you probably know.

Strangely though, I find that even with using I often have to wrap it
with a try/catch block (probably because I'm doing something wrong).

RL

Aug 29 '08 #9
raylopez99 wrote:
On Aug 28, 12:42 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
>>
The solution is of course to eliminate the using block, and Dispose
the Pen in F.Dispose(bool disposing) and only if disposing is set.

Thanks, that's pretty slick detective work.

Truth be told, I don't know what I did wrong, nor will I ever find out
since I did a workaround, but what you just alerted me to is the fact
that 'using' is not 'fail safe'. I assumed that 'using' cannot do you
wrong, in that if it's not needed it's just not used, but you alert me
to the fact this might not be the case. For IO operations Albahari
says 'using (Filestream fs = new Filestream ("myfile.txt",
FileMode.Open) { //} is equivalent to:

FileStream fs = new FileStream ("myFile.txt", FileMode.Open);
try { //} finally { if (fs != null) fs.Dispose();}

As you probably know.
Yes, and it's the correct thing to do if and only if the result of the
initializer-expression in the using block is a new object. If there's any
way (caching, explicit copy of reference like I showed, etc) of multiple
references to the same object, you then get multiple calls to Dispose on the
same object, use after Dispose, and so forth.
>
Strangely though, I find that even with using I often have to wrap it
with a try/catch block (probably because I'm doing something wrong).
Well, it's because using adds a finally block, not a catch. So the resource
is disposed automatically, but the exception is still handed onward --
because disposing the resources didn't fix the exceptional condition, it
would be wrong to discard the exception.
>
RL

Sep 3 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Schuntermann Joerg \(IFAT IT MFG COC MES MAC\) | last post by:
This sounds like a trivial task: I'd like to change the default color settings for certain system elements (e.g. Control, Meu, Window) inside a C# program programatically during program...
1
by: news.microsoft.com | last post by:
When I add to a listview, can the text I have be of different colors? For example, I want to add these two lines to my list view: "This is my program" "This is my other program" Can I add...
2
by: Joep | last post by:
L.S., I am using the picture box's paint event to load an image if not yet loaded. The picture box is one of many that together occupy the area of a panel. Not all boxes are visible so not all...
7
by: Schorschi | last post by:
I know there is a way to do this, but I don't know how. Via a custom event? I have some code that I only want to run during a paint event. I could build a form instance that has the code and...
2
by: John | last post by:
I created a number of pictureboxes in a panel, and want to draw lines in those pictureboxes but I cannot. Please see the following code and make corrections. Thanks. Private Sub...
2
by: Tyreec | last post by:
Hi all, I am having an issue when trying to draw a simple line. I have created a Windows Application and created a Paint method atrached to the event Paint. Inside I create a Pen and draw a...
5
by: =?Utf-8?B?SmVzcGVyLCBEZW5tYXJr?= | last post by:
Hi, On a usercontrol I've put a set of radiobuttons within a groupbox. These radiobuttons have visual style enables, i.e. they turn orange when hovering over them and green when pushed. ...
14
by: raylopez99 | last post by:
KeyDown won't work KeyPress fails KeyDown not seen inspired by a poster here:http://tinyurl.com/62d97l I found some interesting stuff, which I reproduce below for newbies like me. The main...
7
by: howardk | last post by:
I'm writing some code that loads a number of images, using the standard mechanism of assigning a src url to a newly constructed Image object, thus invoking the image-load operation. On a successful...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.