Link to home
Start Free TrialLog in
Avatar of paing0d
paing0d

asked on

VB.NET Changing Toolbar GUI

Hey all,

I've been wondering to change the Toolbar GUI (or in general every control GUI). Dunno if what I say is correct but I want to change the appearance of the Toolbar :). I've came very far in this all but I've still not found what I actually want. If you watch controls correctly you see a small black line beside it. Especially when you got a MDI Form on it with a flat Toolbar (docked left). So I have been wondering if it isn't possible to just remake the whole Toolbar GUI, so also the 3d border you see. I've made the following with all I've seen on the internet.

Filename: Toolbar.vb

Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Text
Imports System.Windows.Forms

Public Class CustomToolbar
    Inherits System.Windows.Forms.ToolBar

    Public Sub New()
        Me.SetStyle(ControlStyles.UserPaint, True)
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
        ControlPaint.DrawBorder3D(e.Graphics, e.ClipRectangle, Border3DStyle.Flat)
    End Sub
End Class


If you run this code you will see a nice flat border inside the Toolbar. What I want is to only see this Border and not the black lines from the normal Toolbar. I've already tried to set the left -1, top-1 but that's not working. Then the border is gone :/ (At least the left and top border.)

I've already made a way around it tho but I rather see it in the control then the solution I have now:
I made a picturebox over the black line in a specific color with width 2. So then the black line is gone and it looks quiet good but I don't think it's a nice way to do it right?

So I wonder if you can completely rewrite the Paint() / OnPaint() sub or something like that. Like forms. They have 3d borders that I can't change. I'd like to see those flat too ;). Can someone give me a clue? The appearance->flat doesn't do what I want ;p. Same as FormBorderStyle.

Thanks in advance,
 Tony
Avatar of paing0d
paing0d

ASKER

Does anybody know if it's possible or not? Since I haven't seen a single reaction yet :/
Avatar of paing0d

ASKER

It has something to do with this I guess:

    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim cParams As CreateParams
            cParams = MyBase.CreateParams

            cParams.ExStyle = cParams.ExStyle Or 512
            cParams.Style = cParams.Style Or 8388608

            Return cParams
        End Get
    End Property

This will make a sunken Toolbar. Know I just need to find out how to make it transparant or invisible :p
It's all in the WinUser.h but I don't know how to convert it to integers yet :/ or even better... use it as it
is written there, like: #define WS_BORDER           0x00800000L
Paing0d is correct, u have to override createparams for this...

NetPointer
Avatar of paing0d

ASKER

I tried to do it but I don't know what constants I need to use. Can someone help me with that? Since I know it's all in the WinUser.h.

I need to know how to use the vars in WinUser.h. Any clue? Even if you make custom controls they got a black line if they are docked to the left. I really need more help with this all. I found lots and I know I'm almost there :)
private const CONSTANTFROMWINUSER = HEXVALUE

u define it like this and then use it in your createparams...

HTH
NetPointer
Avatar of paing0d

ASKER

can you give an example plz?

This is in the WinUser.h
#define WS_BORDER           0x00800000L

Would it be something like this?
private const WS_BORDER= 0x00800000L (this doesn't work)

since I believe 0x00800000L are bits and its not a hex value.
How to convert the bits to hex? Maybe some other solution? :)
Here is one example:
try this for yr solution: Const x As Integer = &H800000

Public Class NumTextbox
    Inherits TextBox
    Const ES_NUMBER As Integer = &H2000

    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim param As System.Windows.Forms.CreateParams
            param = MyBase.CreateParams
            param.Style = param.Style Or ES_NUMBER
            Return param
        End Get
    End Property
End Class
Avatar of paing0d

ASKER

so basicly:

#define BF_LEFT         0x0001
#define BF_TOP          0x0002
#define BF_RIGHT        0x0004
#define BF_BOTTOM       0x0008

becomes:
Const BF_LEFT As Integer = &H1
Const BF_TOP As Integer = &H2
Const BF_RIGHT As Integer = &H4
Const BF_BOTTOM As Integer = &H8

is that correct?

Still need to find out what constants I need to use to make the blackline dissapear ;p
You will hear more soon I hope :x
Avatar of paing0d

ASKER

Still need help :( Dunno what to do :/
Hey, where u had stuck?

elaborate and I will try to help u..

what u mean by blackline?

Regards,
NetPointer
Avatar of paing0d

ASKER

Make the following:
- MDI Form
- Toolbar docked left at MDI Form
- MDI Child Form

In the mdiform_load you make a new instance of the MDI Child Form. If you maximize the MDI Child Form (inside the MDI Form) then you see at the right of the toolbar and left of the MDI Child Form a black line. So if you see it like I see it you see a thick black line :). I want that line to dissapear, but I don't know how, since I need to use vars I think that give me the possibility to do it but which ones? Also I can't change everything in the Toolbar GUI. If you modify the Toolbar GUI there are certain regions I can't modify, and that is the border (about 2px at left, 2px at top, 2px at right and 2px at bottom). That's the only thing I need to know. How to totally 'remake' the Toolbar (or in general every control) GUI. Since I can't 'totally' remake it. Still regions I can't modify.
Avatar of paing0d

ASKER

Nobody knows how to make the control GUI's I want? :(
Avatar of paing0d

ASKER

I know it's possible since the .NET studio has it. It's all flat even the borders (so they must have rewritten the GUI right?). Can nobody put me on the right track again? I really like to know how to make it all flat in general, and I like to make it my self too (so getting components from other developers isn't really an option for me.) If I can make it totally flat then I believe I can totally rewrite the component's GUI? Maybe I'm confused and just talking things that don't make sense but then please tell me so I know how to get on the right track again.

Thanks in advance,
Tony
this question is very interesting. i'm sorry but i can't help you, i'm also monitoring this question cause i want to know it too.
maybe consider a reposting of this question, old question are often ignored.

bye

the edge
Avatar of paing0d

ASKER

Oh man I'm so close...
I found the following:
http://www.dotnet247.com/247reference/msgs/21/109372.aspx
http://www.syncfusion.com/FAQ/WinForms/FAQ_c41c.asp#q1027q

Can someone please translate it to VB.NET? Most I can translate my self but it would be nice if someone can translate it for me.
Especially the following parts:
cparams.ExStyle &= ~512 /*WS_EX_CLIENTEDGE*/;
cparams.Style &= ~8388608 /*WS_BORDER*/;  
cp.Style |= 0x800000; // WS_BORDER

No clue how to translate that into VB.NET. I hope someone can help me with translating the following:
http://www.syncfusion.com/FAQ/WinForms/FAQ_c41c.asp#q1027q

          protected override CreateParams CreateParams
          {
               get
               {
                     System.Windows.Forms.CreateParams cp = base.CreateParams;
                     if(this.needFlatBorder)
                     {
                          cparams.ExStyle &= ~512 /*WS_EX_CLIENTEDGE*/;
                         cparams.Style &= ~8388608 /*WS_BORDER*/;
                         cp.Style |= 0x800000; // WS_BORDER
                    }
               }
          }
 
          protected override void WndProc(ref Message m)
          {
               if(m.Msg == 133/*WM_NCPAINT*/)
               {
                    this.DrawFlatNCBorder(ref m);
               }
               base.WndProc(ref m);
          }
 
          private void DrawFlatNCBorder(ref Message msg)
          {
               IntPtr hRgn1 = (IntPtr) msg.WParam;
               // The update region is clipped to the window frame. When wParam is 1, the entire window frame needs to be updated.
               IntPtr hdc = NativeMethods.GetDCEx(msg.HWnd, hRgn1, 1/*DCX_WINDOW*/|0x0020/*DCX_PARENTCLIP*/);
               if (hdc != IntPtr.Zero)
               {
                    using (Graphics g = Graphics.FromHdc(hdc))
                    {
                         Rectangle bounds = new Rectangle(0,0,this.Width,this.Height);
                         ControlPaint.DrawBorder(g,bounds,this.borderColor,ButtonBorderStyle.Solid);
 
                         // create a clipping region for remaining parts to be drawn excluding
                         // the border we did just drew
                         bounds.Inflate(-1, -1);
                         IntPtr hRgn2 = NativeMethods.CreateRectRgn(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);

                         if(hRgn2 == (IntPtr)1)
                         {
                              // Provide a new clipping region.
                              msg.WParam = (IntPtr) hRgn2;
                         }
                         else
                         {
                              // combine with existing clipping region.
                              NativeMethods.CombineRgn(hRgn1, hRgn1, hRgn2, NativeMethods.RGN_AND);
                              NativeMethods.DeleteObject(hRgn2);
                         }
                    }
                    msg.Result = (IntPtr) 1;
                    NativeMethods.ReleaseDC(msg.HWnd, hdc);
               }                
               Invalidate();
          }
 
Tony
Avatar of paing0d

ASKER

Protected Overrides ReadOnly Property CreateParams() As CreateParams
   Get
      Dim cp As System.Windows.Forms.CreateParams = MyBase.CreateParams
      cparams.ExStyle = cparams.ExStyle And Not 512 'WS_EX_CLIENTEDGE
      cparams.Style = cparams.Style And Not 8388608 'WS_BORDER
      cp.Style = cp.Style Or &H800000 ' WS_BORDER
   End Get
End Property


Protected Overrides Sub WndProc(ByRef m As Message)
   If m.Msg = 133 Then 'WM_NCPAINT
      Me.DrawFlatNCBorder(m)
   End If
   MyBase.WndProc(m)
End Sub 'WndProc

I believe this is correct? Couldn't fix the following:
      If Me.needFlatBorder Then 'Me.needFlatBorder doesn't exist
         cparams.ExStyle = cparams.ExStyle And Not 512 'WS_EX_CLIENTEDGE
         cparams.Style = cparams.Style And Not 8388608 'WS_BORDER
         cp.Style = cp.Style Or &H800000 ' WS_BORDER
      End If

so I made it into:
         cparams.ExStyle = cparams.ExStyle And Not 512 'WS_EX_CLIENTEDGE
         cparams.Style = cparams.Style And Not 8388608 'WS_BORDER
         cp.Style = cp.Style Or &H800000 ' WS_BORDER

Now it's just the last method that needs translation if the above is correct.

Tony
Avatar of paing0d

ASKER

Still having some problems tho.
This is what I think it should be but there are 2 problems left:

    Private Sub DrawFlatNCBorder(ByRef msg As Message)
        Dim hRgn1 As IntPtr = CType(msg.WParam, IntPtr)
        Dim bounds As New Rectangle(0, 0, Me.Width, Me.Height)
        Dim hRgn2 As IntPtr = NativeMethods.CreateRectRgn(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom)

        ' The update region is clipped to the window frame. When wParam is 1, the entire window frame needs to be updated.

        Dim hdc As IntPtr = NativeMethods.GetDCEx(msg.HWnd, hRgn1, 1 Or &H20) 'DCX_WINDOW
        'DCX_PARENTCLIP

        If Not hdc.Equals(IntPtr.Zero) Then
            Dim g As Graphics = Graphics.FromHdc(hdc)
            Try
                ControlPaint.DrawBorder(g, bounds, Me.borderColor, ButtonBorderStyle.Solid)

                ' create a clipping region for remaining parts to be drawn excluding
                ' the border we did just drew
                bounds.Inflate(-1, -1)

                If hRgn2.Equals(New System.IntPtr(1)) Then
                    ' Provide a new clipping region.
                    msg.WParam = hRgn2
                Else
                    ' combine with existing clipping region.
                    NativeMethods.CombineRgn(hRgn1, hRgn1, hRgn2, NativeMethods.RGN_AND)
                    NativeMethods.DeleteObject(hRgn2)
                End If
            Finally
                g.Dispose()
            End Try

            msg.Result = New System.IntPtr(1)
            NativeMethods.ReleaseDC(msg.HWnd, hdc)
        End If

        Invalidate()
    End Sub 'DrawFlatNCBorder

'System.Drawing.NativeMethods' is not accessible in this context because it is 'Private'.
'borderColor' is not a member of 'WindowsApplication1.UserControl1'.

I hope when those are fixed that it's gonna work.
Btw I'm glad that someone replied. Even tho you doesn't know the answer
it keeps stimulating me to find the answer. Been quiet for a while but
now I'm more stimulated then ever to find the answer :)

Take care guys,
Tony
>>'borderColor' is not a member of 'WindowsApplication1.UserControl1'

System.Windows.Forms.UserControl has not a borderColor property; try to declare it by yourself.

can you post the entire class or mail me it so i can try it on my pc?
my mail is

g2k2 @ _nospam_ katamail . com

(remove spaces and _nospam_)

the edge
Avatar of paing0d

ASKER

Hey thanks for your reply but I think I've found a better way to do it.
Check this out :)

    Public Declare Function GetWindowDC Lib "user32" Alias "GetWindowDC" (ByVal hwnd As Int32) As IntPtr
    Public Declare Function ReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hwnd As Int32, ByVal hdc As Int32) As IntPtr

    Protected Overrides Sub WndProc(ByRef m As Message)
        Const WM_NCPAINT As Integer = &H85
        If m.Msg = WM_NCPAINT Then
            Dim hDC As IntPtr = GetWindowDC(m.HWnd.ToInt32)
            Dim graph As Graphics = Graphics.FromHdc(hDC)
            Dim pen1 As New Pen(Color.Blue)
            Dim pen2 As New Pen(Color.Yellow)

            Dim width As Integer = Bounds.Width - 1
            Dim height As Integer = Bounds.Height - 1

            graph.DrawRectangle(pen1, 0, 0, width, height)
            'graph.DrawRectangle(pen2, 1, 1, width - 2, height - 2)

            pen1.Dispose()
            pen2.Dispose()
            graph.Dispose()
            ReleaseDC(m.HWnd.ToInt32, hDC.ToInt32)

            m.Result = IntPtr.Zero
        Else
            MyBase.WndProc(m)
        End If
    End Sub 'WndProc

If you make a custom control and put this in it then you get a blue border in the non-client area :D
Just need to test it out a little and I hope it solves my 'problem'. Btw I've changed the code a bit, so maybe
it aint fully working. Changed the Long to Int32 and some other things too, but this is working fine for me.
Tomorrow is a great day for research :p

Tony
Avatar of Bob Learned
No comment has been added lately, so it's time to clean up this TA.
I will leave the following recommendation for this question in the Cleanup topic area:

PAQ with points refunded

Please leave any comments here within the next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

TheLearnedOne
EE Cleanup Volunteer
ASKER CERTIFIED SOLUTION
Avatar of SpazMODic
SpazMODic

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial