Laden...

Darstellung von windowseigenen Controls ändern

Erstellt von Floste vor 15 Jahren Letzter Beitrag vor 15 Jahren 7.540 Views
Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 15 Jahren
Darstellung von windowseigenen Controls ändern

Beschreibung:

Es ist garnicht so einfach, die Darstellung von einem Control zu verändern, dass vom Betriebssystem gezeinet (z.B. Prgressbars) wird, ohne alles selbst zeichnen zu müssen, und dabei auchnoch das Flackern zu verhindern.
Der folgende Code weist das Betriebssystem an, das Control nicht direkt, sondern zuerst auf eine Bitmap zu zeichnen, die man dann nach belieben bearbeiten kann, bevor man sie anzeigt:


using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace DiverseTests
{
    class OwnProgressBar:ProgressBar
    {
        //----erlaubt es auf belibigen windowseigenen Controls zu zeichnen(außer auf Textboxen)----------

        //Interop Krams:
        [DllImport("user32.dll")]
        static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint);

        [StructLayout(LayoutKind.Sequential)]
        struct PAINTSTRUCT
        {
            public IntPtr hdc;
            public bool fErase;
            public RECT rcPaint;
            public bool fRestore;
            public bool fIncUpdate;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
            public byte[] rgbReserved;
        }

        [Serializable, StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;

            public Rectangle ToRectangle()
            { return Rectangle.FromLTRB(Left, Top, Right, Bottom); }
            public static implicit operator Rectangle(RECT rect)
            {
                return rect.ToRectangle();
            }
        }

        [DllImport("user32.dll")]
        static extern bool EndPaint(IntPtr hWnd, [In] ref PAINTSTRUCT lpPaint);

        const int WM_PAINT = 15;
        const int WM_ERASEBKGND = 20;
        Bitmap buffer;
        protected override void WndProc(ref Message m)
        {
            switch(m.Msg)
            {
                case WM_ERASEBKGND:
                case WM_PAINT:
                    //Buffer vorbereiten:
                    if (buffer == null)
                    {
                        buffer = new Bitmap(Width, Height);
                    }
                    if (buffer.Width != Width || buffer.Height != Height)
                    {
                        buffer.Dispose();//!!!
                        buffer = new Bitmap(Width, Height);
                    }
                    //Hdc besorgen:
                    IntPtr hdc = m.WParam;
                    PAINTSTRUCT ps=new PAINTSTRUCT();
                    bool callEndPaint = false ;
                    Rectangle drawingRegion;
                    if (hdc == IntPtr.Zero)
                    {
                        hdc = BeginPaint(Handle, out ps);
                        callEndPaint = true;
                        drawingRegion=ps.rcPaint;
                    }
                    else
                    {
                        drawingRegion=ClientRectangle;
                    }
                    if (hdc == IntPtr.Zero)
                    { return; }
                    //auf Buffer zeichnen:
                    using (Graphics ownGx = Graphics.FromImage(buffer))
                    {
                        IntPtr ownHdc=ownGx.GetHdc();
                        Message newM = new Message();
                        newM.Msg=m.Msg;
                        newM.HWnd = Handle;
                        newM.WParam=ownHdc;
                        newM.LParam=m.LParam;
                        DefWndProc(ref newM);
                        ownGx.ReleaseHdc(ownHdc);
                        //man kann hier den Buffer beliebig manipulieren.
                        if (m.Msg == WM_PAINT) OnPaint(new PaintEventArgs(ownGx, drawingRegion));
                        else OnPaintBackground(new PaintEventArgs(ownGx, drawingRegion));
                    }
                    //Buffer zeichnen:
                    if(m.Msg==WM_PAINT)
                    {
                        using (Graphics gx = Graphics.FromHdc(hdc))
                        {
                            gx.DrawImage(buffer, drawingRegion);
                        }
                    }
                    //Aufräumen:
                    if (callEndPaint)
                    { EndPaint(Handle, ref ps); }
                    m.Result = IntPtr.Zero;
                    return;
                default:
                    base.WndProc(ref m);
                    return;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            SizeF TextSize=e.Graphics.MeasureString(Text, Font);
            e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), (Width - TextSize.Width) / 2, (Height - TextSize.Height) / 2);
        }

        [EditorBrowsable(EditorBrowsableState.Always)]
        [Browsable(true)]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }


        [EditorBrowsable(EditorBrowsableState.Always)]
        [Browsable(true)]
        public override Font Font
        {
            get
            {
                return base.Font;
            }
            set
            {
                base.Font = value;
            }
        }
    }
}

Schlagwörter: <Bitte Schlagwörter, unter denen das Snippet über die Suche gefunden werden soll, hier eintragen>

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 15 Jahren

weils so schön ist hier noch ein screenshot:

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

1.820 Beiträge seit 2005
vor 15 Jahren

Hallo floste!

Sehr schönes Snippet.
Hab' allerdings auch eine Frage: Warum überschreibst du Text und Font?

Nobody is perfect. I'm sad, i'm not nobody 🙁

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo tom-essen,

um die Anzeige der Properties im Designer, die in der Oberklasse ProgressBar ausgeschaltet wurde, wieder einzuschalten:

[EditorBrowsable(EditorBrowsableState.Always)]  
[Browsable(true)]  

herbivore

3.511 Beiträge seit 2005
vor 15 Jahren

Es wäre vielleicht ganz hilfreich, wenn du die Integers im WndProc mit Konstanten bennenen könntest. Ich weis zwar, was 15 und 20 für eine Windows Nachricht ist, aber andere vielleicht nicht 😃

BTW: 15 = WM_PAINT, 20 = WM_ERASEBKGND

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

946 Beiträge seit 2008
vor 15 Jahren

Hallo 🙂

Um einfach nur eine prozentuale Anzeige zu erreichen, welche den Fortschritt anzeigt ist es geschickter, wenn das die ProgressBar selber zeichnet.

Für diesen Fall habe ich eine kleine Umänderung vom Snippet gemacht, damit das die ProgressBar von "Haus aus" kann.
Die grösste Änderung ist die, dass ich den Code nach meinem Geschmack umgeändert habe.

Um die Prozente anzuzeigen muss man nur noch

 progressStateBar.StateView = ProgressStateBar.ProgressState.Percent;

machen. Geht auch im Designer

Damit das Layout nicht gesprengt wird, hänge ich die Klasse an.

946 Beiträge seit 2008
vor 15 Jahren

Und auch noch ein Bild

mfg
SeeQuark