Paint Event Problem

I have a Windows application that overrides the Paint method to change the presentation of the form. Basically, it paints a red border around the edge of the form. I also have a couple of panels that fill up the form. One is docked to the left and the other fills the remaining space. Each of these panels also has an override to the paint event. The overrides are in the Form1 class.

The problem: The project solution compiles and runs just fine on my laptop. However, when I copy the entire solution to my desktop computer, the application will run, but the two panels do not update their display! I have placed breakpoints in the respective paint methods to find out that they are, indeed, being called. What I don't understand is why the screen doesn't show the update.

For the record, the panel's default background color is 'Gray'. The paint methods are used to draw a diagonal linear gradient.

Even if I just copy the runtime compiled version from the laptop to the desktop it exhibits the same behavior. The interesting thing is that the desktop version was the 'source' version two weeks ago. I copied it to my laptop for a business trip. Now that I'm back, I want to continue where I left off. This display issue appears to be the only problem. Does anyone have any ideas

Thanks,

Bob




Answer this question

Paint Event Problem

  • PeterdeLeng

    Hi bob,

    I think the best we can do rightnow is to look at your Paint event handler; probably we can spot it from there. Can you post the codes where you paint your panels Also, are you handling double-buffering manually on your paintings

    -chris

  • cjshrader

    Tallin,

    It's difficult to say why your code misbehaves. You might be experiencing the same thing as myself. It would help if you either simplified your example or provided all necessary source code. Your paint routines appear to fetch data and information from different objects of your creation that are not provided in source. The difficulty may lie with them. One cannot be sure.

    One comment you made surprised me. You indicated that you replaced a paint override with an event. It is recommended that you use the override if you must paint within your own custom class. The paint event occurs after the main paint function is called.

    My problem exists because I'm trying to use an existing object (namely a Panel instance) to draw on it using the paint event.

    Bob



  • ManishBirla

    The problems I have seen posted with regard to painting panels have mostly to do with not using the Paint event properly. A Panel object can be painted just like any other control. I have a custom control derived from Panel that works quite well. I'd even start using it, if I could change the existing Panel object instance types without restructuring everything through the IDE.

    Thanks for the suggestion though...

    Bob



  • TimNeale

    I have the same problem here :)

    I have 4 custom ui components and only one is being refreshed. They are double-buffered. When i invalidate, only one is being refreshed on some computers (everything ok on my computer) -- when i refresh, one of those 2 computers will hang (my app, not the whole computer) and another will just not paint anything. Also -- in some cases, they will not paint even other elements, which have not overriden paint event.

    // i use c# express, have played with it for a few days.



  • killem

    I doubt we'll find anything in the code directly. As I said earlier, it runs fine on my laptop and other systems.

    The following is the paint event method invoked for one of the panels.

    private void pnlShipLeft_Paint(object sender, PaintEventArgs e)

    {

    Control cnt = sender as Control;

    DrawBackground(e.Graphics, cnt);

    // display the logo at the top....

    Graphics g = e.Graphics;

    try {

    Bitmap img = new Bitmap(this.GetType(), "Resources.n7std.png");

    if (img != null) {

    g.DrawImage(img, new Point(6,14));

    }

    }

    catch { }

    }

    This is the DrawBackground method being called. (It has not yet been optimized for better resource management...)

    private void DrawBackground(Graphics g, Control cnt)

    {

    if (g != null && cnt != null) {

    Point pnt;

    pnt = cnt.PointToScreen(new Point(0, 0));

    pnt = this.PointToClient(pnt);

    LinearGradientBrush b = new LinearGradientBrush(

    new Rectangle(- pnt.X, -pnt.Y, this.Width, this.Height),

    Color.White, Color.Black, LinearGradientMode.BackwardDiagonal);

    float[] relativeIntensities = { 0.2f, 0.3f, 0.0f, 0.0f, 0.4f,

    0.7f, 0.8f, 1.0f, 0.7f, 0.5f, 0.2f };

    float[] relativePositions = { 0.0f, 0.1f, 0.2f, 0.24f, 0.4f, 0.7f,

    0.75f, 0.78f, 0.83f, 0.95f, 1.0f };

    //Create a Blend object and assign it to linGrBrush.

    Blend blend = new Blend();

    blend.Factors = relativeIntensities;

    blend.Positions = relativePositions;

    b.Blend = blend;

    g.FillRectangle(b, new Rectangle(0, 0, cnt.Width, cnt.Height));

    }

    }

    The purpose behind the DrawBackground() method is to draw a single gradient across multiple panels so that the panels all appear to be continuous. I will eventually move the brush, blend, and blend data arrays into the form so they will only be created/allocated a single time. This function is called by many panels.

    Thanks,

    Bob



  • VidarL

    Chris,

    Thanks for the suggestion. It didn't make any difference though. As I said before, the Paint event handler IS being called, but for some reason the output isn't getting to the screen. No exceptions are being fired either. What bums me out about this is that the problem isn't localized to just two panels. I use this technique throughout my application to draw application logos in panels that form banners across the tops of all dialogs. Also, other panels in other forms draw a gradient background as well. None of these seem to work. The odd thing is that this seems to occur just for this project. That's what has me so confused.

    Thanks again for trying.

    Bob



  • TheBeck

    Try to attach handler to your panel's SizeChanged event, and from that handler invalidate your panel.

    -chris

  • beach_bum

    I'm moving this thread over to the Windows Forms forum to give it best chance of getting answered.


  • rockman88

    Bob,

    At first -- Tallinn is city where i live, not my name :) I repaired my signature now (Estonia is country).

    Could you download my example, install and run on your problematic computer so that you can check if it works there -- if we do have the same prob

    I will put override back -- anyway i think that there should be property for turning on custom paint, like there is in delphi, for example, so that i could use event.

    Other code it uses:
    * GetParam and SetParam just change the color of one part of gradient. Those are robust and simple functions, which are tested and work.

     

    Other code (dont mention it's inefficiency -- i try at first find out, how to make paint event itself efficient, after that i will think about how to make this thing faster by removing all those EyeColor calls and so on -- currently i want it to be both simple and fast to be able to change this EyeColor painting from one place -- anyway, EyeColor class is completely working and returns current selected gradients to display. I think that this draw function is also working, as that's simple and robust, too. About painting in C# -- i havent catched the point yet ...at least it must be so if this thing does not work :D hopefully it's not MS bug there):

    PS. Base of the following is downloaded from somewhere, so it should be not only working, but also tested.

    public static bool Draw(Bitmap b)

    {

    // GDI+ still lies to us - the return format is BGR, NOT RGB.

    BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),

    ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

    int stride = bmData.Stride;

    System.IntPtr Scan0 = bmData.Scan0;

    EyeColor ThatColor = new EyeColor(EyeColor.GetMainColor());

    int blue, green, red;

    unsafe

    {

    byte* p = (byte*)(void*)Scan0;

    int nOffset = stride - b.Width * 3;

    int Hl, Wl;

    Hl = b.Height;

    Wl = b.Width;

    for (int y = 0; y < Hl; ++y)

    {

    ThatColor.SetParam(0, y, Hl);

    for (int x = 0; x < Wl; ++x)

    {

    ThatColor.SetParam(1, x, Wl);

    blue = p[0]; // those 3 lines from here are crap, but i havent deleted them :)

    green = p[1];

    red = p[2];

    ThatColor.ToRGB();

    p[0] = (byte)ThatColor.Blue;

    p[1] = (byte)ThatColor.Green;

    p[2] = (byte)ThatColor.Red;

    p += 3;

    }

    p += nOffset;

    }

    }

    b.UnlockBits(bmData);

    return true;

    }



  • JesusChris

    I tried your code on my machine (desktop with VS2005) and it is working fine. And looking at your code, I can't find any reason why it won't work on your desktop machine.


    -chris

  • Johnny D

    I have seen a number of posts that talk about problems with painting panels. I have a feeling that maybe painting panels doesnt work exactly the same as painting most other controls. After all, Panel was designed mostly to be a logical container, not a drawing surface. Have you tried using another control to paint your logos, like Label or PictureBox
  • Garg

    http://www.arutlused.net/EyeColor2.zip contains executables (installer) of my application. On some computers, only 1st linear gradient is updated -- and even those standard ui components will be not updated.

    Depending on if i do invalidate or update, it will not update on first case and will hang on second case. I tried to replace override with event (since i had automatically added code deleted from that event), but it doent change anything.

    Also, when i'm already here -- maybe someone has some good articles in favorites, which talk about fast 2D graphics in C# without DX or OGL I havent yet got time to go through this .NET documentation (i guess that it may be as big as WinApi docs) or even C# reference, so those docs should be for somewhat dumb user ;) Even just list of classes/namespaces, which would be usable, would be helpful (as this automatic popup suggester has built-in and short help with it).

    Paint function of one code part (1d gradient):

    private void LineChooser_Paint(object sender, PaintEventArgs e)

    {

    e.Graphics.Clear(Color.White);

    Pen PenHold;

    EyeColor ThatColor = new EyeColor(EyeColor.GetMainColor());

    int CurrentPosition = ThatColor.GetParam(ParamName, Width);

    for (int a = 0; a < Width; a++)

    {

    ThatColor.SetParam(ParamName, a, Width);

    e.Graphics.DrawLine(PenHold = new Pen(ThatColor.GetRGB()),

    a, 0,

    a, Height - 1);

    if (a == CurrentPosition)

    e.Graphics.DrawLine(PenHold = new Pen(ThatColor.VisibleColor()),

    a, 0,

    a, Height - 1);

    PenHold.Dispose();

    }

    }

     

    And another (2d gradient) -- this one uses function "Draw", which updates all pixels of BtImg in unsafe mode:

    private void BoxChooser_Paint(object sender, PaintEventArgs e)

    {

    Bitmap BtImg = new Bitmap(Width, Height);

    Draw(BtImg);

    e.Graphics.DrawImage(BtImg, 0, 0);

    EyeColor ThatColor = new EyeColor(EyeColor.GetMainColor());

    int xs = ThatColor.GetParam(1, Height);

    int ys = ThatColor.GetParam(0, Width);

    Pen PenHold = new Pen(ThatColor.VisibleColor());

    e.Graphics.DrawLine(PenHold,

    xs - 2, ys - 2,

    xs - 2, ys + 2);

    e.Graphics.DrawLine(PenHold,

    xs - 2, ys + 2,

    xs + 2, ys + 2);

    e.Graphics.DrawLine(PenHold,

    xs + 2, ys + 2,

    xs + 2, ys - 2);

    e.Graphics.DrawLine(PenHold,

    xs + 2, ys - 2,

    xs - 2, ys - 2);

    PenHold.Dispose();

    }



  • Coreth

    EyeColor is my color class. It contains color in other than RGB format. I give explanations to it's functions so that u can read my code:

    EyeColor ThatColor = new EyeColor(EyeColor.GetMainColor()); // ThatColor will contain copy of color currently selected by user. GetMainColor is static function.

    ThatColor.SetParam(0, y, Hl); // Param number 0 (there are 0, 1, 2 -- red-green, yellow-blue, white-black params) will be set to y. Hl is height of control -- to make it simple, value of y will be divided by it.

    ThatColor.ToRGB(); // RGB values of color will be calculated.

    p[0] = (byte)ThatColor.Blue; // RGB value, Blue, is used here.



  • masuday

    That's exactly the problem I'm having! I know that the code should work. The code is even being called. What I just don't 'get' is WHY it doesn't update the display.

    Out of frustration, I removed all VS2005 and the .Net components from my system and reinstalled them. No joy.

    I also installed an updated video driver for my ATI X800 video card (not that I expected it to be a problem), and got no joy.

    Since I am still modifying and developing, I copied the project back to my laptop. It runs fine there!

    My main concern, as you might imagine, is that a customer's machine may have the same behavior as my development machine, for no apparent reason.

    Bob



  • Paint Event Problem