Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Making parts of a panel transparent

Making parts of a panel transparent

Scheduled Pinned Locked Moved C#
helpquestion
5 Posts 2 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    G Ringbom
    wrote on last edited by
    #1

    I was having an idea of a program I want to make. I was just sitting and thinking about it and came up with an idea to a solution where I would use lots of small panels on top of large panel (canvas). The problem is that these small panels arent necessarily completely used. Maybe only parts of them are used. They can also be on top of each other. When they are on top of each other it wont look good if the top panel overdraws panels belowin parts that arent actually used. So is there a way to say that a part of a panel is supposed to be transparent so that things belo are shown instead of the empy panel?

    H 1 Reply Last reply
    0
    • G G Ringbom

      I was having an idea of a program I want to make. I was just sitting and thinking about it and came up with an idea to a solution where I would use lots of small panels on top of large panel (canvas). The problem is that these small panels arent necessarily completely used. Maybe only parts of them are used. They can also be on top of each other. When they are on top of each other it wont look good if the top panel overdraws panels belowin parts that arent actually used. So is there a way to say that a part of a panel is supposed to be transparent so that things belo are shown instead of the empy panel?

      H Offline
      H Offline
      Heath Stewart
      wrote on last edited by
      #2

      Using multiple panels contained within another panel has another problem: unnecessary overhead. Each is a control with its own window handle, window procedure, and more - all consuming memory and ticking away at the number of possible window handles allocated by the OS. There are a couple ways you could do this. The easiest way is - for Windows 2000 and newer - to use layered Windows. This is what the Opacity property of a Form uses. In this case, however, you'll need to code something yourself, which I'll get to in a moment. The other way is supported on any Windows platforms (perhaps other platforms, too) that supports the .NET Framework. You exclude a region of your control from painting. This is known as clipping. Anything below it is sent a WM_PAINT message to redraw that portion of itself. This can be expensive (in terms of resources), which is why layered Windows are nice (but only supported on Windows 2000 and newer). The first way requires that you P/Invoke SetLayeredWindowAttributes and - upon creation of your control (override OnHandleCreated, and be sure to call base.OnHandleCreated) - you pass it the Handle property, the color of your transparent color, and LWA_COLORKEY (0x1) to tell the function to use your color, not an alpa value (which is what the Form.Opacity property actually uses). Then you assign an image as your BackgroundImage for your Panel that contains the color you want to mask out. See the example below, where Example.jpg is just an image with white that I mask out:

      using System;
      using System.Drawing;
      using System.IO;
      using System.Runtime.InteropServices;
      using System.Windows.Forms;
       
      class Example : Form
      {
      Example()
      {
      SetStyle(ControlStyles.AllPaintingInWmPaint
      | ControlStyles.ResizeRedraw, true);
       
      using (Image bg = Image.FromStream(
      GetType().Assembly.GetManifestResourceStream("Example.jpg")))
      {
      BackgroundImage = (Image)bg.Clone();
      Size = bg.Size;
      }
       
      FormBorderStyle = FormBorderStyle.None;
      }
       
      void SetTransparentColor(Color c)
      {
      int key = ColorTranslator.ToWin32(c);
      SetLayeredWindowAttributes(Handle, key, 0, LWA_COLORKEY);
      }
       
      protected override System.Windows.Forms.CreateParams CreateParams
      {
      get
      {
      System.Windows.Forms.CreateParams cp = base.CreateParams;
      cp.ExStyle = WS_EX_L

      G 1 Reply Last reply
      0
      • H Heath Stewart

        Using multiple panels contained within another panel has another problem: unnecessary overhead. Each is a control with its own window handle, window procedure, and more - all consuming memory and ticking away at the number of possible window handles allocated by the OS. There are a couple ways you could do this. The easiest way is - for Windows 2000 and newer - to use layered Windows. This is what the Opacity property of a Form uses. In this case, however, you'll need to code something yourself, which I'll get to in a moment. The other way is supported on any Windows platforms (perhaps other platforms, too) that supports the .NET Framework. You exclude a region of your control from painting. This is known as clipping. Anything below it is sent a WM_PAINT message to redraw that portion of itself. This can be expensive (in terms of resources), which is why layered Windows are nice (but only supported on Windows 2000 and newer). The first way requires that you P/Invoke SetLayeredWindowAttributes and - upon creation of your control (override OnHandleCreated, and be sure to call base.OnHandleCreated) - you pass it the Handle property, the color of your transparent color, and LWA_COLORKEY (0x1) to tell the function to use your color, not an alpa value (which is what the Form.Opacity property actually uses). Then you assign an image as your BackgroundImage for your Panel that contains the color you want to mask out. See the example below, where Example.jpg is just an image with white that I mask out:

        using System;
        using System.Drawing;
        using System.IO;
        using System.Runtime.InteropServices;
        using System.Windows.Forms;
         
        class Example : Form
        {
        Example()
        {
        SetStyle(ControlStyles.AllPaintingInWmPaint
        | ControlStyles.ResizeRedraw, true);
         
        using (Image bg = Image.FromStream(
        GetType().Assembly.GetManifestResourceStream("Example.jpg")))
        {
        BackgroundImage = (Image)bg.Clone();
        Size = bg.Size;
        }
         
        FormBorderStyle = FormBorderStyle.None;
        }
         
        void SetTransparentColor(Color c)
        {
        int key = ColorTranslator.ToWin32(c);
        SetLayeredWindowAttributes(Handle, key, 0, LWA_COLORKEY);
        }
         
        protected override System.Windows.Forms.CreateParams CreateParams
        {
        get
        {
        System.Windows.Forms.CreateParams cp = base.CreateParams;
        cp.ExStyle = WS_EX_L

        G Offline
        G Offline
        G Ringbom
        wrote on last edited by
        #3

        Wow! That is one long and very useful reply. Many thanks! So basically, both methods you mentioned above is better than the solution I proposed I guess from your reply. I dont want to limit the solution to just Win 2000 and above so I guess your second solution is the way I need to go. You mentioned that both my solution and your second solution was in many ways expensive. Is it correct to say that my proposed solution was expensive in terms of memory and window handle usage, and your second solution was expensive in terms of execution speed? One more question is that when I was playing with the code of your second solution I notices that if I removed the line t.Dock = DockStyle.Fill; or set the docking to None in Main the tringle isnt visible. Why is this? In your example the triangle fills the complete area, but I wanted a smaller triangle in the middle, so I thought that docking felt incorrect. Do you have to dock a control to make it visible in the main window or is there another way? One more thing I noticed is that when I run the code above, the triangle responds to clicks outside the triangle itself. If I understood you correctly, you said it would not respond to those clicks.

        H 1 Reply Last reply
        0
        • G G Ringbom

          Wow! That is one long and very useful reply. Many thanks! So basically, both methods you mentioned above is better than the solution I proposed I guess from your reply. I dont want to limit the solution to just Win 2000 and above so I guess your second solution is the way I need to go. You mentioned that both my solution and your second solution was in many ways expensive. Is it correct to say that my proposed solution was expensive in terms of memory and window handle usage, and your second solution was expensive in terms of execution speed? One more question is that when I was playing with the code of your second solution I notices that if I removed the line t.Dock = DockStyle.Fill; or set the docking to None in Main the tringle isnt visible. Why is this? In your example the triangle fills the complete area, but I wanted a smaller triangle in the middle, so I thought that docking felt incorrect. Do you have to dock a control to make it visible in the main window or is there another way? One more thing I noticed is that when I run the code above, the triangle responds to clicks outside the triangle itself. If I understood you correctly, you said it would not respond to those clicks.

          H Offline
          H Offline
          Heath Stewart
          wrote on last edited by
          #4

          When I say "expensive" I mean in terms of resources, and not necessarily anything you can control. When you use clipping regions the windows underneath your control are sent a WM_PAINT message by the system and must draw themselves. When you start moving your application around like a crazy man there's a lot of painting going on. And many third-party controls, unfortunately, don't paint only what needs to be painted (or at least a suitable sub-region) but the whole control (this can lead to flickering or slow refresh times, even with double buffering). G.Ringbom wrote: or set the docking to None in Main the tringle isnt visible. Why is this? Because I set no default size for the control when I extended it. Give the control a set size (something I didn't do since I was docking it anyway) and you should see the control. G.Ringbom wrote: One more thing I noticed is that when I run the code above, the triangle responds to clicks outside the triangle itself. If I understood you correctly, you said it would not respond to those clicks. Either I wrote it wrong (sorry) or you mis-interpreted. With clipping regions the mouse messages are still sent to the control because the control (a window, actually) still occupies a rectangular region. When you set the clipping region for a Graphics object, however, it only defines the region not to paint. The control is still there. If I said otherwise I do apologize (the site is running way too slow right now for me to want to go back and check). Layered windows can produce non-rectangular windows, however. Mouse messages are allowed to pass through to the underlying window. I think your best approach is to use both. Use clipping regions when the current platform is not Win2K or newer, and layered windows when the current platform is Win2K or newer. You can determine the OS easily by using Environment.OSVersion. If you search for previous comments, I believe I posted an example once using this approach - at least for part of the code necessary for such a control. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]

          G 1 Reply Last reply
          0
          • H Heath Stewart

            When I say "expensive" I mean in terms of resources, and not necessarily anything you can control. When you use clipping regions the windows underneath your control are sent a WM_PAINT message by the system and must draw themselves. When you start moving your application around like a crazy man there's a lot of painting going on. And many third-party controls, unfortunately, don't paint only what needs to be painted (or at least a suitable sub-region) but the whole control (this can lead to flickering or slow refresh times, even with double buffering). G.Ringbom wrote: or set the docking to None in Main the tringle isnt visible. Why is this? Because I set no default size for the control when I extended it. Give the control a set size (something I didn't do since I was docking it anyway) and you should see the control. G.Ringbom wrote: One more thing I noticed is that when I run the code above, the triangle responds to clicks outside the triangle itself. If I understood you correctly, you said it would not respond to those clicks. Either I wrote it wrong (sorry) or you mis-interpreted. With clipping regions the mouse messages are still sent to the control because the control (a window, actually) still occupies a rectangular region. When you set the clipping region for a Graphics object, however, it only defines the region not to paint. The control is still there. If I said otherwise I do apologize (the site is running way too slow right now for me to want to go back and check). Layered windows can produce non-rectangular windows, however. Mouse messages are allowed to pass through to the underlying window. I think your best approach is to use both. Use clipping regions when the current platform is not Win2K or newer, and layered windows when the current platform is Win2K or newer. You can determine the OS easily by using Environment.OSVersion. If you search for previous comments, I believe I posted an example once using this approach - at least for part of the code necessary for such a control. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]

            G Offline
            G Offline
            G Ringbom
            wrote on last edited by
            #5

            Now that I read it again, I saw that it was me who misinterpreted. Anyway. Thanks for your replies. It really helped me out.

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups