Show/Hide Child Controls on MouseMove/MouseLeave VB.NET - vb.net

Imagine a list where the items had child controls (say, a list of songs with media controls).
I'd like for the child to show on MouseMove of the parent.
The problem I'm facing is that the MouseLeave event, which hides the child controls, fires when the mouse leaves the parent to go into the children (which is completely understandable).
How would one overcome this?
I don't have this problem with the text as I have painted it with graphics. I don't want to paint the children as they will need individual event handlers.
All of the items are added dynamically at runtime.
EDIT
It appears I am, in fact, getting the issue with the MouseLeave event of the graphics.
At the moment, I have the parent's MouseMove event set the ForeColor to blue and the MouseLeave event setting the colour to white. The textis drawn on paint (I use the ForeColor of the parent when I paint the string). It seems that if I leave the parent via the graphics (the top of the graphics is at 0), the ForeColor remains blue.
The code
Private Sub ListItem_MouseLeave(sender As Object, e As EventArgs) Handles Me.MouseLeave
Me.ForeColor = Me.Parent.ForeColor
_controls.Hide()
End Sub
Private Sub ListItem_MouseEnter(sender As Object, e As EventArgs) Handles Me.MouseEnter
Me.ForeColor = SystemColors.HotTrack
If _controls Is Nothing Then
Dim p As New Panel
With p
.BackColor = Color.FromArgb(23, 23, 23)
.Width = Me.Height * 1
.Height = Me.Height
.Left = Me.Width - Me.Height
.Top = 0
.ForeColor = Me.Parent.ForeColor
.Anchor = AnchorStyles.Right
End With
Me.Controls.Add(p)
_controls = p
Else
_controls.Show()
End If
End Sub
Private Sub ListItem_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim strLen As SizeF = e.Graphics.MeasureString(SongName, Me.Font)
e.Graphics.DrawString(getTrimmedString(SongName, SongNameMaxWidth), Me.Font, New SolidBrush(Me.ForeColor), New Point(3, (Me.Height / 2) - (strLen.Height / 2)))
End Sub

Related

How to remove the white lines surrounding a button appearing when I click it

It works fine until I click it and pop up a file dialog box,and then white lines appears surrounding it.
I don't know how to remove these ugly lines.
The only code is openFileDialog1.ShowDialog().
It's a Button whose FlatStyle is flat and whose BackgroundImage is a PNG image.
After that the white lines appears, and if I click the Form it will disappear.
A simple workaround is to set the Button FlatAppearance.BorderColor to its Parent.BackColor. It will overwrite the focus rectangle. The MouseUp event can be used to set the value, it will be raised before a new Window is opened (the Control.Leave event will never be raised):
Private Sub SomeButton_MouseUp(sender As Object, e As MouseEventArgs) Handles SomeButton.MouseUp
Dim ctl As Button = DirectCast(sender, Button)
ctl.FlatAppearance.BorderColor = ctl.Parent.BackColor
End Sub
Using the Control.Paint event, we can also use the Control.BackColor property to paint the border, both with the ControlPaint class DrawBorder method (simpler than using the ButtonRenderer class):
Private Sub SomeButton_Paint(sender As Object, e As PaintEventArgs) Handles SomeButton.Paint
Dim ctl As Button = DirectCast(sender, Button)
ControlPaint.DrawBorder(e.Graphics, ctl.ClientRectangle, ctl.BackColor, ButtonBorderStyle.Solid)
End Sub
and painting the Control's border ourselves:
(Note that the ClientRectangle size must be shrinked, by 1 pixel, both in the Width and Height dimensions. This is by design).
Private Sub SomeButton_Paint(sender As Object, e As PaintEventArgs) Handles SomeButton.Paint
Dim ctl As Control = DirectCast(sender, Control)
Dim r As Rectangle = ctl.ClientRectangle
Using pen As Pen = New Pen(ctl.BackColor, 1)
e.Graphics.DrawRectangle(pen, r.X, r.Y, r.Width - 1, r.Height - 1)
End Using
End Sub

Changing color, highlight, background size of a ListBox?

So I've searched around and managed to highlight the values in my ListBox, but I'm trying to increase the font size for the text inside the ListBox but it results in the following image as attached:
This is my current code:
Private Sub ListBox1_DrawItem(sender As System.Object, e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox1.DrawItem
e.DrawBackground()
If ListBox1.Items(e.Index).ToString().Contains("*") Then
e.Graphics.FillRectangle(Brushes.Red, e.Bounds)
End If
e.Graphics.DrawString(ListBox1.Items(e.Index), e.Font, Brushes.Black, New System.Drawing.PointF(e.Bounds.X, e.Bounds.Y))
e.DrawFocusRectangle()
I've tried messing with the "e.Bounds.X, e.Bounds.Y" to increase the rectangle/size of the highlighted value but nothing seemed to work.
How does one allow the highlighted rectangle increase according to the font size?
When you set the DrawMode of a ListBox control to OwnerDrawVariable or you change the Font size after the control handle has been created (i.e. after it has already processed the WM_MEASUREITEM message), you need to manually set the ItemHeigh property to the new Font height.
The ItemHeight property is set subscribing the ListBox MeasureItem event and setting the MeasureItemEventArgs e.ItemHeight property.
Also, if you change the Font size on the fly, you also need to force the WM_MEASUREITEM message to be re-sent to the ListBox control, otherwise the Items Bounds will not be updated.
In other words, when the DrawItem event is raised, the DrawItemEventArgs e.Bounds property will report wrong measures.
A way to force the ListBox control to re-measure its Items bounds, is to set ListBox.DrawMode = DrawMode.Normal and immediatly resetting it back to OwnerDrawVariable. This causes the WM_MEASUREITEM message to be processed again.
listBox1.DrawMode = DrawMode.Normal
listBox1.DrawMode = DrawMode.OwnerDrawVariable
listBox1.Update()
Here I'm using the Font.Height to measure the current ItemHeight in the MeasureItem event, because it rounds up the measure. You could use TextRenderer.MeasureText or Font.GetHeight(); you'll end up with the same measure, but rounded down.
Private Sub ListBox1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ListBox1.DrawItem
Dim ItemForeColor As Color
Dim ItemBackColor As Color
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
ItemForeColor = Color.FromKnownColor(KnownColor.HighlightText)
ItemBackColor = If(ListBox1.Items(e.Index).ToString().Contains("*"), Color.Red, Color.FromKnownColor(KnownColor.Highlight))
Else
ItemForeColor = ListBox1.ForeColor
ItemBackColor = If(ListBox1.Items(e.Index).ToString().Contains("*"), Color.Red, ListBox1.BackColor)
End If
Using TextBrush As New SolidBrush(ItemForeColor)
Using ItemBrush As New SolidBrush(ItemBackColor)
e.Graphics.FillRectangle(ItemBrush, e.Bounds)
e.Graphics.DrawString(ListBox1.Items(e.Index).ToString(), ListBox1.Font, TextBrush, e.Bounds, StringFormat.GenericTypographic)
End Using
End Using
e.DrawFocusRectangle()
End Sub
Private Sub ListBox1_MeasureItem(sender As Object, e As MeasureItemEventArgs) Handles ListBox1.MeasureItem
e.ItemHeight = ListBox1.Font.Height
End Sub
Test it resizing the Font:
ListBox1.Font = New Font(ListBox1.Font.FontFamily, ListBox1.Font.SizeInPoints + 2, ListBox1.Font.Style, GraphicsUnit.Point)
ListBox1.DrawMode = DrawMode.Normal
ListBox1.DrawMode = DrawMode.OwnerDrawVariable
ListBox1.Height = '[OriginalHeight]
ListBox1.Update()

I draw image to form, but it is limited to top left corner of form

I have created a form and imported two square images saved as PNG files in resources. when I run the code below the black box which is drawn will only go about 200 pixels in the x coordinate and 150 pixels in the Y coordinate from where the image is drawn, after that the background remains white, and it seems I am unable to draw anything and anything I do draw stops around this point.
I have tried redrawing the image in a completely different location on the screen and It will not be visible if it is not within the region to the top left of the form, I have also tried drawing other images, but they also cease to exist when not in the top left of my form.
What I want is for the black box/other images to be drawn across the whole form, and not just in the top left corner, which something is preventing me from doing.
Public Class Form1
Dim gameGraphics As System.Drawing.Graphics = Me.CreateGraphics
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Draws black square which I have saved as resource
gameGraphics.DrawImage(My.Resources.black_Background, 0, 80, 1600, 600)
'Draws green square which I have saved as resource
gameGraphics.DrawImage(My.Resources.greenSquare, 2, 82, 40, 40)
End Sub
'makes the form fullscreen
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.FormBorderStyle = FormBorderStyle.None
Me.WindowState = FormWindowState.Maximized
End Sub
'closes form if quitbutton is clicked
Private Sub QuitButton_Click(sender As Object, e As EventArgs) Handles QuitButton.Click
Me.Close()
End Sub
End Class
Thanks for your time!
The Graphics Object cannot be stored. It's Erased/Updated constantly. You'll end up with an invalid one. It's really useless and, you could say, a mistake.
You can use a Graphics Object created with Control.CreateGraphics(), but you have to remember that it's not persistent; it will be erased when the Control you have painted it on needs to re-Paint() itself (e.g. you drag something over it, if it's a Form, when it's minimized etc.).
Those Properties, Me.FormBorderStyle = FormBorderStyle.None and Me.WindowState = FormWindowState.Maximized are better set in the designer. There's no reason to set them on a Form.Load() event. Their state is not even subject to a condition. In general, leave the Load event of a Form as lightweight as possible and avoid setting properties that can cause cascading events.
An example:
Define an object to store your images:
(The DrawBitmaps flag is used to let your Form know when to draw those Bitmaps).
Public Class MyBitmap
Public Property Image As Bitmap
Public Property Position As Point
Public Property Size As Size
End Class
Public MyBitmaps As List(Of MyBitmap)
Public DrawBitmaps As Boolean = False
Somewhere (even in Form.Load()), fill the list with you bitmaps:
(Here, the bitmap size is set to original size, but you can set it to whatever dimension you see fit).
MyBitmaps = New List(Of MyBitmap)
MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.black_Background,
.Position = New Point(0, 80),
.Size = New Size(My.Resources.black_Background.Width,
My.Resources.black_Background.Height)})
MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.greenSquare,
.Position = New Point(2, 82),
.Size = New Size(My.Resources.greenSquare.Width,
My.Resources.greenSquare.Height)})
The Paint() event e.Graphics of the Form performs all the painting:
(Note that it will not paint its surface unless the DrawBitmaps flag is set to True => It will not paint those Bitmaps when it's loading/showing. The other condition is a basic fail-safe.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
If DrawBitmaps = True AndAlso MyBitmaps.Count > 0 Then
For Each _Item As MyBitmap In MyBitmaps
e.Graphics.DrawImage(_Item.Image, New Rectangle(_Item.Position, _Item.Size))
Next
End If
End Sub
When Button1 is clicked, the Form will draw your list of Bitmaps:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
DrawBitmaps = True
Me.Invalidate()
End Sub
Somewhere in your code, add a new Bitmap and tell the Form to Invalidate only a region of the size of this new Bitmap:
MyBitmaps.Add(New MyBitmap With {.Image = My.Resources.[AnotherBitmap],
.Position = New Point(50, 50),
.Size = New Size(200, 200)})
Me.Invalidate(New Rectangle(MyBitmaps.Last().Position, MyBitmaps.Last().Size))
Remove a Bitmap from the list and repaint:
MyBitmaps.RemoveAt(0)
Me.Invalidate()

VB.NET - Non-client painting with Graphics.FromHwnd as Handle

I'm trying to do some non-client area painting to get a MS Office like windowsform. I have one or two other posts of the sort, but here is the one that is done with Graphics.FromHwnd passing IntPtr.Zero as arg. I consulted a lot of information, that I tried and just simply cannot get it to work. Dwm functions, GetWindowDC, and or combination of these. Nothing works. Except this example that I post.
Public Class Form6
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
Select Case m.Msg
Case WinAPI.Win32Messages.WM_ACTIVATEAPP
Me.Invalidate()
End Select
End Sub
Private Sub Form6_LocationChanged(sender As Object, e As EventArgs) Handles Me.LocationChanged
Me.Invalidate()
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim usedColor As Color = Color.Beige
Me.BackColor = usedColor
Dim usedBrush As Brush = New SolidBrush(usedColor)
'Dim hDC As IntPtr = WinAPI.GetWindowDC(Me.Handle.ToInt64)
Using g As Graphics = Graphics.FromHwnd(IntPtr.Zero)
'Using g As Graphics = Graphics.FromHdc(hDC)
'Caption
Dim rect As Rectangle = New Rectangle(Me.Left, Me.Top, Me.Width, SystemInformation.CaptionHeight + 2 * SystemInformation.FrameBorderSize.Height)
g.FillRectangle(usedBrush, rect)
'left border
rect = New Rectangle(Me.Left, Me.Top + SystemInformation.CaptionHeight + 2 * SystemInformation.FrameBorderSize.Height, (Me.Width - Me.ClientSize.Width) / 2, Me.ClientSize.Height)
g.FillRectangle(usedBrush, rect)
'right border
rect = New Rectangle(Me.Right - 2 * SystemInformation.FrameBorderSize.Width, Me.Top + SystemInformation.CaptionHeight + 2 * SystemInformation.FrameBorderSize.Height, (Me.Width - Me.ClientSize.Width) / 2, Me.ClientSize.Height)
g.FillRectangle(usedBrush, rect)
'bottom border
'If on maximize this border isn't drawn, by default the windowsize "drawing" is correct
If Me.WindowState <> FormWindowState.Maximized Then
rect = New Rectangle(Me.Left, Me.Bottom - 2 * SystemInformation.FrameBorderSize.Width, Me.Width, 2 * SystemInformation.FrameBorderSize.Height)
g.FillRectangle(usedBrush, rect)
End If
End Using
'WinAPI.ReleaseDC(Me.Handle.ToInt64, hDC)
End Sub
Private Sub Form6_Resize(sender As Object, e As EventArgs) Handles Me.Resize
Me.Invalidate()
End Sub
Private Sub Form6_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
Me.Invalidate()
End Sub
End Class
To generate graphics, I pass IntPtr.Zero for the hole screen.
I tried the GetWindowDC API (commented in code), and nothing happens. The handle was passed as Me.Handle, Me.Handle.ToInt32 and .ToInt64, and no result.
The invalidate called is to try to draw in every situation possible.
Problems that bring me here:
Form does not start up painted (can't figure it out);
Resizing flickers a lot (probably because the handle is to the entire screen, even form being double-buffered);
On the resizing, it's visible the painting over the cursor (again probably because of the handle for the graphics isn't the form's handle);
On mouse over control buttons (min, max and close), all drawing disappears;
Although I can detect problems, I can't get other ways to work, like the famous GetWindowDC, regardless of how many examples I tried that don't work, or even the DWM functions.
Being the purpose of getting my own "Office" like form, I ask some help in getting improvements to this code or some other ideas, that are welcome.
[EDIT]
Another flavor of the above code. This code was tried in form_load event, but nothing happened.
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
If Not DwmAPI.DwmIsCompositionEnabled(True) Then
Dim myHandle As IntPtr = WinAPI.FindWindow(vbNullString, Me.Text)
Dim hDC As IntPtr = WinAPI.GetWindowDC(myHandle)
Dim rect As WinAPI.RECT
With rect
.Left = 0
.Right = Me.Width
.Top = 0
.Bottom = 30
End With
Using g As Graphics = Graphics.FromHdc(hDC)
g.DrawString("TESTER", New Font(Me.Font.Name, 50), Brushes.Red, New Point(0, 0))
End Using
WinAPI.ReleaseDC(myHandle, hDC)
End If
End Sub
The result is this:
http://postimg.org/image/yyg07zf87/
As it would be clear, I want to have whatever if graphics drawn over titlebar and not under, although it's visible that the coords for the drawing are from full form area and not client area. If I doublebuffer the form, nothing is drawn. Any ideas?
Thanks for your patience. Best regards.

How can you create a custom window (not a form object) in VB.net?

As the title states, is it possible / how can you create a custom window to draw onto? Normally, you would just use a form and form controls, but I want my own window with a handle that I'll attach hooks to and handle the paint events and the like. Is this possible? Essentially, I just need a container for my program's image that isn't a Form. If not in VB.Net, is it possible in C#?
EDIT:
I'm just not very fond of how the window draws (even with control over paint event). I removed the form border and the control bar and replaced them with my own functions (to place the max/min/exit buttons, title, form borders + sizing, etc) so the form I'm using is essentially just a floating panel - though with built in hooks that are nice of course. But the form still flickers too much and so I wanted to handle everything myself. I use doublebuffering on all controls I use and I use setbounds to move/resize controls as opposed to setting width/height individually (reduced some of the flicker). I draw the form border in the form's paint event, the rest is drawn as controls (including the form's top bar).
I mostly hate the black boxes that I see when I expand the form (generally don't see that when decreasing window size, but still some small amount of flicker). An alternative method, perhaps a different draw style (in VB 2010) or something, would work as well I guess.
EDIT (again):
The black box issue happens regardless of how many controls are on the form. If I try to manually resize it (the custom empty form control posted below that inherits from Form), using setbounds on each mousemove during a click and drag event (does not occur when not intended, so I know it's not running the sub more than it has to).
EDIT (code):
http://img211.imageshack.us/img211/900/j9c.png
So even on a blank "SimpleForm" (as posted in the first answer") with no controls, when resized to be larger (in the pic, resized northeast), black boxes are drawn under where the form will be drawn. Controlstyles / backbuffering done as posted in the second answer, as well as the createparams posted by Hans. This is what I used to set the form bounds:
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or &H2000000
cp.Style = cp.Style Or &H2000000
Return cp
End Get
End Property 'CreateParams
Public Sub New(ByRef ContentFolder As String, ByRef x As Integer, ByRef y As Integer, ByRef w As Integer, ByRef h As Integer)
FormBorderStyle = FormBorderStyle.None
'Note, I have tried the original suggested control styles in many combinations
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint
UpdateStyles()
OL = x 'Used for resizing, to know what the original bounds were - especially in maximizing, didn't like the standards maximize call
OT = y
OW = w
OH = h
BackColor = Color.White
BorderColor = New Pen(BarColor.Color)
MinimumSize = New Size(200, 200)
TransparencyKey = Color.FromArgb(255, 255, 0, 128)
CF = ContentFolder
ControlBar = New FormBar(Me, "Explorer woo", CF)
AddHandler Me.Load, AddressOf EF_Load
AddHandler Me.MouseUp, AddressOf EF_MouseUp
AddHandler Me.MouseDown, AddressOf EF_MouseDown
AddHandler Me.MouseMove, AddressOf EF_MouseMove
AddHandler Me.LostFocus, AddressOf EF_LostFocus
End Sub
Public Sub EF_Load(ByVal sender As Object, ByVal e As EventArgs)
SetFormBounds(OL, OT, OW, OH)
End Sub
Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
ControlBar.SetBar(Width) 'Sets the width of controlbar to new width, and updates position of the 3 top-right form buttons
If Not (_backBuffer Is Nothing) Then
_backBuffer.Dispose()
_backBuffer = Nothing
End If
RaiseEvent Resized(Me, e) 'Resizes controls in custom handler, in this example, it is unused - with controls, they don't flicker when resized though
MyBase.OnSizeChanged(e)
End Sub
Private Sub SetFormBounds(ByRef l As Integer, ByRef t As Integer, ByRef w As Integer, ByRef h As Integer)
If w < Me.MinimumSize.Width Then
w = Me.MinimumSize.Width
l = Left
End If
If h < Me.MinimumSize.Height Then
h = Me.MinimumSize.Height
t = Top
End If
If l = Left AndAlso t = Top AndAlso w = Width AndAlso h = Height Then Exit Sub
ControlBar.SetBar(w)
SetBounds(l, t, w, h)
'Used for detecting if user coords are on the form borders with L-shaped areas so as to not include too much of the interior of the bar, Borderthickness = pixel width of border
CornerRects = New List(Of Rectangle) From {{New Rectangle(0, 0, BorderThickness, 15)}, {New Rectangle(0, 0, 15, BorderThickness)}, {New Rectangle(Width - 15, 0, 15, BorderThickness)}, {New Rectangle(Width - BorderThickness, 0, BorderThickness, 15)}, {New Rectangle(0, Height - 15, BorderThickness, 15)}, {New Rectangle(BorderThickness, Height - BorderThickness, 10, BorderThickness)}, {New Rectangle(Width - BorderThickness, Height - 15, BorderThickness, 15)}, {New Rectangle(Width - 15, Height - BorderThickness, 10, BorderThickness)}}
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
If _backBuffer Is Nothing Then
_backBuffer = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
End If
Dim g As Graphics = Graphics.FromImage(_backBuffer)
g.Clear(SystemColors.Control)
'Draw Control Box
g.TextRenderingHint = Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit
g.FillRectangle(BarColor, 0, 0, Width, ControlBar.Height)
If ControlBar.Title <> "" Then g.DrawString(ControlBar.Title, ControlBar.Font, ControlBar.FontBrush, ControlBar.TextLeft, ControlBar.TextTop)
g.DrawImage(FormBar.bmpCorners(0), 0, 0) 'Makes transparent corner, very small bitmap created at run-time
g.DrawImage(FormBar.bmpCorners(1), Width - FormBar.bmpCorners(0).Width, 0)
'Draw Control Box buttons top right
If ControlBar.ExitButton.Enabled = True Then g.DrawImage(ControlBar.ExitButton.Img, ControlBar.ExitButton.Rect.X, ControlBar.ExitButton.Rect.Y)
If ControlBar.MaximizeButton.Enabled = True Then g.DrawImage(ControlBar.MaximizeButton.Img, ControlBar.MaximizeButton.Rect.X, ControlBar.MaximizeButton.Rect.Y)
If ControlBar.MinimizeButton.Enabled = True Then g.DrawImage(ControlBar.MinimizeButton.Img, ControlBar.MinimizeButton.Rect.X, ControlBar.MinimizeButton.Rect.Y)
If Not ControlBar.Ico Is Nothing Then g.DrawImage(ControlBar.Ico, 5, 5) 'Draw Control Box icon (program icon) if it is set
'Draw the form border
For i = 0 To BorderThickness - 1
g.DrawLine(BorderColor, i, ControlBar.Height, i, Height - 1)
g.DrawLine(BorderColor, Width - 1 - i, ControlBar.Height, Width - 1 - i, Height - 1)
g.DrawLine(BorderColor, BorderThickness, Height - 1 - i, Width - BorderThickness, Height - 1 - i)
Next
g.Dispose()
e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0)
End Sub
Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs)
End Sub
It is not really possible at all, in either language. This isn't a language thing, or even a framework (i.e. WinForms) thing. Rather, it's more because of the design of Windows itself. Essentially, everything in Windows is a window, and the Form class represents a basic top-level window that can be displayed directly on the desktop. If you want a window displayed on the desktop, you need to use the Form class. Moreover, if you want to have a window handle that you can attach hooks to, you'll need to use this class; it's the one with all the necessary plumbing to get that going.
But that doesn't mean it has to look like a default Form object does. The appearance is infinitely customizable. Start by setting the FormBorderStyle property of your form to remove the default window frame/chrome. That will give you a completely blank slate. Then, do like you said and handle its Paint event. Except that when you're wanting to handle the events of a derived class, you should override the OnXxx method directly, instead of subscribing to the events. So you'd have this code:
Public Class SimpleForm : Inherits Form
Public Sub New()
' Alter the form's basic appearance by removing the window frame,
' which gives you a blank slate to draw onto.
FormBorderStyle = FormBorderStyle.None
' Indicate that we're painting our own background.
SetStyle(ControlStyles.Opaque, True)
End Sub
Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
' Call the base class.
MyBase.OnPaint(e)
' Paint the background...
e.Graphics.FillRectangle(Brushes.MediumAquamarine, Me.ClientRectangle)
' ...and then the foreground.
' For example, drawing an 'X' to mark the spot!
Using p As New Pen(Color.Navy, 4.0)
e.Graphics.DrawLine(p, 0, 0, Me.Width, Me.Height)
e.Graphics.DrawLine(p, Me.Width, 0, 0, Me.Height)
End Using
End Sub
End Class
Of course, such a window has severe usability problems. For starters, the user has no way to move it around on the screen or to close it. You'll need to handle those things yourself if you're eliminating the default border.
Can you show the method you are using to enable double buffering? Here's an article that addresses this. Perhaps it will help.
https://web.archive.org/web/20140811193726/http://bobpowell.net/doublebuffer.aspx
Basically, the code is like this (from the article):
Private _backBuffer As Bitmap
Public Sub New
InitializeComponents()
Me.SetStyle(ControlStyles.AllPaintingInWmPaint OR _
ControlStyles.UserPaint OR _
ControlStyles.DoubleBuffer, True)
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
If _backBuffer Is Nothing Then
_backBuffer = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
End If
Dim g As Graphics = Graphics.FromImage(_backBuffer)
'Paint on the Graphics object here
g.Dispose()
'Copy the back buffer to the screen
e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0)
End Sub 'OnPaint
'Don't allow the background to paint
Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs)
End Sub 'OnPaintBackground
Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
If Not (_backBuffer Is Nothing) Then
_backBuffer.Dispose()
_backBuffer = Nothing
End If
MyBase.OnSizeChanged(e)
End Sub 'OnSizeChanged