|
I recommend overlaying the semitransparent mask over the base image (either in OnPaint on the picture box or by placing another object over the top). Then all you have to redraw is the mask.
Creating graphics objects is slow, which is why you should typically do it in OnPaint. In fact, in this case, you should do that, and your mouse move handler should only call Invalidate.
|
|
|
|
|
One other thing to bear in mind. The managed version of GDI+ is slow in comparison to the unmanaged version. You pay a price for the simplicity, and that price is speed.
|
|
|
|
|
Chesnokov Yuriy wrote: Why the picture box update is very slow if I keep drawing on every mouse move event?
Because the MouseMove events fire at high frequency (allowing you to track well assuming your handler is fast), possibly 50Hz or higher (which is too high for the human eye to notice), because Graphics objects are expensive, and finally because PictureBoxes are stupid (I wouldn't be surprised if the fact you change the image just causes another mouse move event).
You want to run such things continuously? I would experiment with keeping the two Graphics and the Bitmap around as class members, i.e. not create new objects at all, just keep using them over and over.
Luc Pattyn [My Articles] Nil Volentibus Arduum
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Please use <PRE> tags for code snippets, they improve readability. CP Vanity has been updated to V2.3
|
|
|
|
|
I need to implement rubber band like ROI selection in the image as in paint editor
Чесноков
|
|
|
|
|
What I understand is that you are trying to darken a rectangle within a image, and that rectangle must be refreshed as long as the mouse is moving. Am I right?
If this is what you want to do, the problem is that you are creating too many new Graphics and Bitmap objects in a very short time (and these are expensive objects), and updating the Image property a lot of times as well. The best way to do it is to subscribe to the Paint event of the control and code everything in this event handler, so you will receive a Graphics object as a parameter. In the next example there is only a PictureBox in the Form, called pct :
public partial class Form1 : Form
{
bool drawRect = false;
Rectangle r = new Rectangle();
Brush br = new SolidBrush(Color.FromArgb(50, Color.Red));
public Form1()
{
InitializeComponent();
}
private void pct_Paint(object sender, PaintEventArgs e)
{
if (drawRect)
e.Graphics.FillRectangle(br, r);
}
private void pct_MouseDown(object sender, MouseEventArgs e)
{
drawRect = true;
r.X = e.X;
r.Y = e.Y;
}
private void pct_MouseMove(object sender, MouseEventArgs e)
{
r.Width = e.X - r.X;
r.Height = e.Y - r.Y;
Refresh();
}
private void pct_MouseUp(object sender, MouseEventArgs e)
{
drawRect = false;
Refresh();
}
}
I've made it quick. You would have to modify it in order to draw the rectangle if the mouse moves to a lower X and/or lower Y coordinate.
|
|
|
|
|
No, I need to darken the area outside rectangle.
Consider ROI region. ROI remains clear and the area outside it is darked.
I tried preinitialization of graphics and bitmaps and found that the problem part taking much of the time is:
...
roi_g.FillRectangle(new SolidBrush(Color.FromArgb(64, 0, 0, 0)), new Rectangle(0, 0, FrameWithRoi.Width, FrameWithRoi.Height));
roi_g.FillRectangle(new SolidBrush(Color.Red), rect);
region.MakeTransparent(Color.Red);
g.DrawImage(region, 0, 0);
...
Despite prinitialization it takes about 150ms
Чесноков
|
|
|
|
|
Well, then, draw four rectangles around the area you want to keep clear. Just change the Paint event handler I posted before this way:
private void pct_Paint(object sender, PaintEventArgs e)
{
if (drawRect)
{
e.Graphics.FillRectangle(br, 0, 0, pct.Width, r.Y);
e.Graphics.FillRectangle(br, 0, r.Y, r.X, pct.Height);
e.Graphics.FillRectangle(br, r.X, r.Y + r.Height, pct.Width, pct.Height);
e.Graphics.FillRectangle(br, r.X + r.Width, r.Y, pct.Width, r.Height);
}
}
This will work pretty well. Do you also want to save the image after you have darkened the area?
|
|
|
|
|
Hi
How can load an image with geotiff format in the .Net application?
And, how can read the coordination(x,y) of each point at geotiff?
thanks in advance
Best Regards,
Reza Shojaee
|
|
|
|
|
You're going to need a third party library to read GeoTiff files because they are non-standard, and the metadata inside them is not supported by the default readers. There are a number of libraries available such as libtiff.net[^] but you're probably going to be better off with GDAL[^].
|
|
|
|
|
Hi is in the following example is possible to add method Create() directly in the abstract class
instead of in each derived class (basically the methos do the same: return inizialide class of its type).
Something like this, that it doesn't works:
abstract class b
{
public b Create()
{
{ return new b(); } // but can not understand the derived class type
}
}
Hope to be clear
Thanks for your time
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace general
{
class Program
{
static void Main(string[] args)
{
D1 myClass = new D1();
D1 newClass = myClass.Create();
}
}
abstract class b
{
}
class D1:b
{
public double KM ;
public D1() { KM = 1.0; }
public D1 Create() { return new D1(); }
}
class D2 : b
{
public double KM ;
public D2() { KM = 2.0; }
public D2 Create() { return new D2(); }
}
}
<div class="signature">
<div class="modified">modified on Wednesday, June 1, 2011 3:15 AM</div></div>
|
|
|
|
|
abstract class b
{
public dynamic Create()
{
return Activator.CreateInstance(this.GetType());
}
}
"You get that on the big jobs."
|
|
|
|
|
Thanks a lot
It works . The only constrain is that you need VS10 to use "dymanic". Is there an old workaround?
|
|
|
|
|
I don't think you need dynamic here. You know what type the object will be: it will be a b .
public virtual b Create() { return (b)Activator.CreateInstance(GetType()); }
It's probably best to make this method virtual so that subclasses can do something different if they need to.
This is quite an unusual thing to want to do unless you are trying to copy an object:
void SomeFunction(b instance){
b copy = instance.Create();
instance.CopyTo(copy);
}
... as it requires you to have an instance of the object to create the new one from.
|
|
|
|
|
Thanks a lot! So suppose I do the following,
abstract class b
{
public virtual b Create() { return (b)Activator.CreateInstance(GetType()); }
}
I'm not able to use method of the derived class?
class Program
{
static void Main(string[] args)
{
D1 myClass = new D1();
D1 newClass = myClass.Create();
Console.WriteLine(newClass.KM);
b myClassAb = new D1();
b newClassAb = myClassAb.Create();
Console.WriteLine(newClassAb.KM);
}
}
|
|
|
|
|
That's correct (unless you cast it). That's kind of an unavoidable consequence of putting any method on the base class. Typically in an abstract class hierarchy, the base class will define (either concrete or abstract) most of the public interface, so you can do most things through the base.
If you know that you are working with D1, after all, you can just create a new instance with new D1() . The dynamic Create method is only needed when you want a new instance of the same type as another object, and you don't know what type that is, so you wouldn't be able to call class-specific functionality on it anyway.
|
|
|
|
|
Thank you for your clear answer.
So:
b myClassAb = new D1();
b newClassAb = myClassAb.Create();
even if newClassAb is a D1 type, I cannot use D1 methods unless cast it.
So no way to avoid to write the same piece of code in each derived class even if they basically do the same thing, if I want to use all methods of derived class. Is it?
class D1:b
{
..
public D1 Create() { return new D1(); }
}
class D2 : b
{
..
public D2 Create() { return new D2(); }
}
|
|
|
|
|
You can use generics like this:
abstract class b<T> where T: b, new()
{
...
public T Create() { return new T(); }
}
class D1 : b<D1>
{
...
}
class D2 : b<D2>
{
...
}
So, you can do:
D1 myClassD1 = new D1();
D1 newClassD1 = D1.Create();
But, you can't do anymore:
b myClassAb = new D1;
D1 newClassAb = myClassAb.Create();
because you'd have to specify the generic type for class b.
|
|
|
|
|
Now you can't call Create on an arbitrary b instance, which renders it pointless.
|
|
|
|
|
I said that at the end of my post.
I agree you are losing many advatages of polymorphism, but, at least, you can reuse the Create login in multple classes.
|
|
|
|
|
There's a very simple way, if you know you want a D1: call new D1() not myD1Instance.Create() .
I'm guessing this is a simplified example, because it simply doesn't make sense to do things this way in most cases. What is your actual problem?
Accepting for the moment that you need a Create method at all: If you know that an instance of b is actually a D1 (for example within the D1 class itself) then you can cast the result of Create safely. Casting is not necessarily bad (it's safer than the use of dynamic, I would say). For example, in some similar code to what I have at the moment for cloning objects in an inheritance tree:
class b {
private int someField;
public b Copy() {
b newB = Create();
CopyTo(newB);
return newB;
}
protected virtual void CopyTo(b newB){
newB.someField = someField;
}
class D1 : b {
private double derivedField;
protected override void CopyTo(b newD1){
D1 target = (D1)newD1;
target.derivedField = derivedField;
}
}
Outside the class tree, it's unlikely that you know for sure at compile time which of the classes you have an instance of (otherwise you wouldn't need the abstract base class at all), so you can normally only cast the result inside the class, or using if(my is D1) type tests. And if you find yourself writing those you probably just found somewhere that an abstract method should be provided on the base class.
|
|
|
|
|
Actually, you don't need Visual Studio at all. What you are meaning to say is "this requires .NET 4.0"
Luc Pattyn [My Articles] Nil Volentibus Arduum
The quality and detail of your question reflects on the effectiveness of the help you are likely to get. Please use <PRE> tags for code snippets, they improve readability. CP Vanity has been updated to V2.3
|
|
|
|
|
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace general
{
class Program
{
static void Main(string[] args)
{
D1 myClass = new D1();
D1 newClass = myClass.Create();
//this is what I would like
b myClassAb = new D1();
b newClassAb = myClassAb.Create<D1>();
newClass.KM = 1.23;
}
}
abstract class b
{
//work in this way !!!
public T Create<T>() where T:new() { return new T(); }
}
class D1 : b
{
public double KM;
public D1() { KM = 1.0; }
// public D1 Create() { return new D1(); }
}
class D2 : b
{
public double KM;
public D2() { KM = 2.0; }
// public D2 Create() { return new D2(); }
}
}
here is one solution using generics
modified on Wednesday, June 1, 2011 9:53 AM
|
|
|
|
|
Sorry probably I did not explain very well the problem. I need to have avaiable methods in newClassAb
//this is what I would like
b myClassAb = new D1();
b newClassAb = myClassAb.Create<D1>();
//This is what I need to see K from newClassAb
Console.WriteLine(newClassAb.K)>//but I can't see .K avaiable
Thanks for your time
modified on Wednesday, June 1, 2011 7:32 AM
|
|
|
|
|
what is K is it KM well i can see KM
try it once more because there was some error in my code
|
|
|
|