VB.NET Cartesian Coordinate System - vb.net

I'd like to make a Cartesian Coordinate System in a Windows form and be able to plot (x,y) coordinates in it.
How do i do this? I already did my research but unfortunately i only land on "charts" and not the Cartesian plane.
Any links regarding my problem will help ... thanks ...

In WinForms, you can use a PictureBox control and then draw on it using primitives such as DrawLine, DrawEllipse, etc. The following SO question contains an example:
how to draw drawings in picture box
In WPF, you can use a Canvas control similarly:
WPF canvas drawing with Graphics
If you want automatic axes and labeling, Charts are indeed the way to go. For your use case, a point chart seems like the right solution:
Point Chart (Chart Controls)

You should create a custom UserControl and use the Paint even to draw on the surface of the control. The Paint event provides you with a Graphics object which you can use to draw the graph. The big thing to know, however, is that you will need to swap your Y axis. In windows, the top-left of the screen is 0,0 rather than the bottom-left.
So, for instance, the following code will draw the x and y axis of a graph on a contorl:
Public Class CartesianGraph
Public Property BottomLeftExtent() As Point
Get
Return _bottomLeftExtent
End Get
Set(ByVal value As Point)
_bottomLeftExtent = value
End Set
End Property
Private _bottomLeftExtent As Point = New Point(-100, -100)
Public Property TopRightExtent() As Point
Get
Return _topRightExtent
End Get
Set(ByVal value As Point)
_topRightExtent = value
End Set
End Property
Private _topRightExtent As Point = New Point(100, 100)
Private Sub CartesianGraph_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim extentHeight As Integer = _topRightExtent.Y - _bottomLeftExtent.Y
Dim extentWidth As Integer = _topRightExtent.X - _bottomLeftExtent.X
If (extentHeight <> 0) And (extentWidth <> 0) Then
If (_bottomLeftExtent.Y <= 0) And (_topRightExtent.Y >= 0) Then
Dim xAxis As Integer = e.ClipRectangle.Height - (_bottomLeftExtent.Y * -1 * e.ClipRectangle.Height \ extentHeight)
e.Graphics.DrawLine(New Pen(ForeColor), 0, xAxis, e.ClipRectangle.Width, xAxis)
End If
If (_bottomLeftExtent.X <= 0) And (_topRightExtent.X >= 0) Then
Dim yAxis As Integer = e.ClipRectangle.Width * _bottomLeftExtent.X * -1 \ extentWidth
e.Graphics.DrawLine(New Pen(ForeColor), yAxis, 0, yAxis, e.ClipRectangle.Height)
End If
End If
End Sub
End Class

.NET has a charting library, but there are a few open source projects that do this sort of thing quite well. If you want to plot coordinates Zedgraph makes this relatively easy and is quite flexible.
this ZedGraph Example gives a great introduction
Dynamic Data Display is also worth looking at, but it is WPF, not Windows Forms

Related

Is it possible for a picture box to detect colour in another picture box and avoid it?

I am currently attempting to make a visual route planner interface for a local town.
The GUI is a map lacking in detail simply showing a green background with grey lines for the roads.
Is it possible for another picture box representing a vehicle to avoid and be unable to access the green coloured areas of the Map Picture box?
How can I make the car picture box follow certain routes along the map picture box that can be worked out through calculations?
We'll do this in a couple steps:
Build the map from the data.
Implement a flexible pathfinding algorithm.
Draw a human-friendly version of the map.
Wrap up with user interactions.
I'll enrich this answer as you progress so it stays relevant.
1
First thing, we'll manipulate data. A road map is basically a network of points (or nodes) linked by lines (which I'll call vertex).
The points have coordinates (so we can draw them later), and sometimes other values, like a name. They are every start and end of a road, and sometimes in-between. To keep things simple, the user will only be able to start and end on points.
Vertex have length and sometimes stuff like "difficulty", "max speed", etc. These stats will determinate which road is the most optimized for the user's trip. We can also make sure that the algorithm doesn't consider a vertex when the user doesn't want to go this way, or force him to go through a specific vertex if we choose so.
You'll find that I included a sample map by setting it up in the map's constructor. I included approximative coordinates and distances. You can change it any way you like. Here what the data represents:
2
I'm using the A* (read A STAR) algorithm here. You mentioned Dijkstra's algorithm sooner, which is nice, but for this purpose I'll stick to A*.
There are differences between these two methods. If you wikipedia them, you'll find these two images which, I think, show really well the main difference between the two:
Dijkstra's algorithm:
A* algorithm:
As you can see by yourself, both algorithm are doing a fine job.
I commented the code, but You'll probably have a ton of questions about all these things. I'll hang around to answer them.
To manipulate this algorithm, you have to know this:
the difficulty value of a vertex makes it seem longer to the algorithm. It's not necessary (which is why I put it to 1 everywhere), but if you want to compare a mountain road to a speedway or a road with a 30 km/h speed limit to another one where you can speed at 100 km/h, you can tweak this value.
the x and y coordinates of the nodes aren't very important in themselves, but the A* algorithm uses them to get this "I'm going toward my goal" effect you just saw in the image. Approximatives values are fine, as long as there are values that make some sense in there. You could calculate the H value otherwise, but as this is cartography I though it made sense.
a vertex MUST ALWAYS be connected to a starting point and an end point. Which is which have no meaning, as long as there are two of them (or the same point twice, but that would lead to the place where it started without any gain whatsoever).
a point may have any number of vertex.
you could make some points "impossible to pass", but I didn't code it that way. You can pump up the difficulty to an insane amount to get a somewhat similar result, except that if there are no other way the algorithm will eventually use the difficult path anyway.
if the end node has no connection to the network of the starting node, the algorithm will try everything then abandon and let you know that there is no path to the end point.
use the TestMyMap() sub to try some pathfinding. Calculate it by yourself to compare. Change the end point and the starting point for something else. Go wild!
The Code
#Region " Mapping "
Public Class MapPoint
Private _vertexList As New List(Of MapVertex) 'one point can have as many "roads" as you want
Private _xCoord As Decimal 'for now the coordinates are meaningless, but at some point we might want to use them to actually paint the map
Private _yCoord As Decimal
Private _name As String 'just a useful label
Public Parent As MapVertex = Nothing 'useful for backtracking at the end (and get an itinary)
'f is the total "cost" of the the node being analyzed (f = g + h) while doing pathfinding
'g is the distance between the node being analyzed and the starting point while doing pathfinding
'those values serve no other purpose
'h is the estimated minimal distance between the two points while doing pathfinding
'in the Sub 'CalculateH' I'm using the points coordinates and simple trigonometry to estimate h
'technically you can skip the square root part, but I decided against it. There are no dealmaking advantages to my decision.
'it's better to underestimate the minimal distance, that's why a theoretical straight line is a good choice
Public f As Decimal = 0
Public g As Decimal = 0
Public h As Decimal = 0
Public ReadOnly Property VertexList As List(Of MapVertex)
Get
Return _vertexList
End Get
End Property
Public ReadOnly Property X As Decimal
Get
Return _xCoord
End Get
End Property
Public ReadOnly Property Y As Decimal
Get
Return _yCoord
End Get
End Property
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Public Sub New(name As String, xx As Decimal, yy As Decimal, ParamArray vertex() As MapVertex)
_name = name
_xCoord = xx
_yCoord = yy
For Each v As MapVertex In vertex
_vertexList.Add(v)
Next
End Sub
Public Sub AddVertex(vertex As MapVertex)
_vertexList.Add(vertex)
End Sub
Public Sub CalculateH(startingPoint As MapPoint, endPoint As MapPoint)
h = Convert.ToDecimal(Math.Sqrt(Math.Pow((startingPoint.X - endPoint.X), 2) + Math.Pow((startingPoint.Y - endPoint.Y), 2)))
End Sub
Public Sub UpdateFandG(currentNodeG As Decimal, distance As Decimal)
g = currentNodeG + distance
f = g + h
End Sub
Public Sub ResetPathfindingValues()
f = 0
g = 0
h = 0
Parent = Nothing
For Each v As MapVertex In _vertexList
v.ResetPathfindingValues()
Next
End Sub
End Class
Public Class MapVertex
Private _name As String 'just a useful label
Private _length As Decimal 'length of the road. If you have straight roads we can use simple math to get the distances, but curvy roads have their own length, and I'll assume that your roads will be anything
Private _difficulty As Decimal 'if you want to make some roads faster than others, we can use a variable like this one. It could be something else, like "maxSpeed", but for a prototype "difficulty" will do fine
'I suggest making the difficulty a multiplier. It'll be easier to use that way (so a road twice faster would be a '0.5' and a road twice harder to use would be a '2.0')
Public Parent As MapPoint = Nothing 'useful for backtracking at the end (and get an itinary)
'start and end has no meaning here, as both are end points for the line. The important part is that they refer to existing points
'a vertex must ALWAYS be linked to two points (or it makes no sense, you cannot have a line with only one end unless you go full moebius and we're not using enough dimensions for this to make sense
'if you feel like it, you can have a vertex looping from one point and going back to it, but it'll serve no purpose and will never be actually used except by the pathfinding algorithm (which will note it as a bad move every time)
Private _startPoint As MapPoint
Private _endPoint As MapPoint
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
'you can play around with difficulty if you like, it'll change which path the algorithm thinks is the better
Public ReadOnly Property AdjustedLength As Decimal
Get
Return _length * _difficulty
End Get
End Property
Public Sub New(name As String, startPoint As MapPoint, endPoint As MapPoint, length As Decimal, difficulty As Decimal)
_name = name
_startPoint = startPoint
_endPoint = endPoint
_length = length
_difficulty = difficulty
'automatically adding this vertex to it's points on creation:
_startPoint.AddVertex(Me)
_endPoint.AddVertex(Me)
End Sub
'this function is so we can get the "other side" of a path from it's start
Public Function GetOtherNode(currentNode As MapPoint) As MapPoint
If _startPoint Is currentNode Then
Return _endPoint
Else
Return _startPoint
End If
End Function
Public Sub ResetPathfindingValues()
Parent = Nothing
End Sub
End Class
Public Class Map
'the Map object is a collection of points.
'those points are linked by vertex
'it could be different depending on what's your purpose
Private _points As New List(Of MapPoint)
Public Function GetPoint(name As String) As MapPoint
For Each p As MapPoint In _points
If p.Name = name Then
Return p
End If
Next
Return Nothing
End Function
Public Sub New()
'You can use this part to build a simple map with a handful of points. For the demonstration that's how we'll work, but later on you can design a mean to load maps from a specific source if you want
'Here's one I threw on the screen at random. If you have one you like better, send me a pastebin and I'll use it instead
'First I create the points:
Dim oldBarn As MapPoint = New MapPoint("Old Barn", 0, 0)
Dim home As MapPoint = New MapPoint("Home", 0, 12)
Dim forest As MapPoint = New MapPoint("Forest", 0, 21)
Dim creepyDeadEnd As MapPoint = New MapPoint("Creepy Dead End", 0, 26)
Dim groceries As MapPoint = New MapPoint("Groceries", 11, 8)
Dim girlfriendsPlace As MapPoint = New MapPoint("Girlfriend's Place", 20, 8)
Dim friendsHome As MapPoint = New MapPoint("Friend's Home", 5, 13)
Dim bar As MapPoint = New MapPoint("The Foo's Bar", 32, 14) 'hehehe
'Second I create the roads between those points (as long as 2 points exist I could create the road, I just decided I would be systematic)
Dim smallRoad As MapVertex = New MapVertex("Small Road", oldBarn, home, 12, 1)
Dim oakStreet As MapVertex = New MapVertex("Oak Street", home, forest, 9, 1)
Dim pathway As MapVertex = New MapVertex("Pathway", forest, creepyDeadEnd, 5, 1)
Dim oldRoad As MapVertex = New MapVertex("Old Road", oldBarn, friendsHome, 17, 1)
Dim arlingtonStreet As MapVertex = New MapVertex("Arlington Street", home, groceries, 7, 1)
Dim fourthStreet As MapVertex = New MapVertex("4th Street", home, girlfriendsPlace, 12, 1)
Dim placeLittlefinger As MapVertex = New MapVertex("Place Littlefinger", groceries, girlfriendsPlace, 9, 1)
Dim cedarCreek As MapVertex = New MapVertex("Cedar Creek", forest, bar, 19, 1)
Dim alley As MapVertex = New MapVertex("Alley", friendsHome, groceries, 7, 1)
Dim mainStreet As MapVertex = New MapVertex("Main Street", groceries, bar, 22, 1)
Dim durnhamRoad As MapVertex = New MapVertex("Durnham Road", friendsHome, bar, 27, 1)
Dim secretRoad As MapVertex = New MapVertex("Secret Road", oldBarn, bar, 61, 1)
'Adding the points to the Map
_points.AddRange({oldBarn, home, forest, creepyDeadEnd, groceries, girlfriendsPlace, friendsHome, bar})
End Sub
'This is an implementation of the A* algorithm, which is a very popular pathfinding algorithm for simple grids/node networks
'You could use Dijkstra's algorithm if you like it better or are a Sapkowsky's fan, but I think A* will do a great job here
Public Function FindTheShortestPath(startingPoint As MapPoint, endPoint As MapPoint) As String
Dim openList As New List(Of MapPoint) 'nodes that are going to be analyzed soon
Dim closedList As New List(Of MapPoint) 'nodes that have been analyzed
'we always start the analysis... from the starting point of course!
openList.Add(startingPoint)
startingPoint.CalculateH(startingPoint, endPoint)
'as long as we haven't found the path to the end point, the algorithm will continue looking
'there are 2 ways to exit this function:
' #1 is finding the endPoint
' #2 is having nowhere left to go and still not finding the end point (which means that it's impossible)
While (openList.Count > 0)
'look for the lowest f in the openList
'this is our current node for the analysis
Dim currentNode As MapPoint = Nothing
For Each p As MapPoint In openList
If currentNode Is Nothing OrElse p.f < currentNode.f Then
currentNode = p
End If
Next
'remove the currentNode from the open list (it's being analyzed) and add to the closedList (no need to come back)
openList.Remove(currentNode)
closedList.Add(currentNode)
'check if we've reached the end node
If currentNode Is endPoint Then
'yay!
'now let's backtrack to get an itinary:
Dim path As String = BackTrack(endPoint)
ResetAllPathfindingVariables()
Return path
End If
'finding which nodes are connected to the Current node
'then analyzing it
For Each vertex As MapVertex In currentNode.VertexList
Dim nextNode As MapPoint = vertex.GetOtherNode(currentNode)
'only work on a node if it's out of the closedList
If Not closedList.Contains(nextNode) Then
'I'm tracking parents to make an itinary when this is finished
nextNode.CalculateH(currentNode, endPoint)
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
'if it's not yet on the openList, now's time to add it there!
'(I know that a negative check with a 'Else' clause is stupid, but it's easier to read in this context)
If Not openList.Contains(nextNode) Then
openList.Add(nextNode)
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
nextNode.Parent = vertex
vertex.Parent = currentNode
Else
'if this is a known node but we found a faster path to reach it, update it's parent
If currentNode.g + vertex.AdjustedLength < nextNode.g Then
nextNode.UpdateFandG(currentNode.g, vertex.AdjustedLength)
nextNode.Parent = vertex
vertex.Parent = currentNode
End If
End If
End If
Next
End While
ResetAllPathfindingVariables()
Return "No path was found."
End Function
Private Sub ResetAllPathfindingVariables()
For Each p As MapPoint In _points
p.ResetPathfindingValues()
Next
End Sub
'recursive function to show the path found by the algorithm
Private Function BackTrack(location As Object, Optional path As String = "") As String
If path <> "" Then path = " => " & path
Select Case True
Case TypeOf location Is MapPoint
Dim currentPoint As MapPoint = DirectCast(location, MapPoint)
path = currentPoint.Name & path
If currentPoint.Parent Is Nothing Then
Return path
Else
Return BackTrack(currentPoint.Parent, path)
End If
Case TypeOf location Is MapVertex
Dim currentVertex As MapVertex = DirectCast(location, MapVertex)
path = currentVertex.Name & path
If currentVertex.Parent Is Nothing Then
Return path
Else
Return BackTrack(currentVertex.Parent, path)
End If
End Select
Return ""
End Function
End Class
Private Sub TestMyMap()
_map = New Map()
Dim path As String = _map.FindTheShortestPath(_map.GetPoint("Home"), _map.GetPoint("The Foo's Bar"))
Console.WriteLine(path)
End Sub
#End Region
Of course I'll be there to help you understand this part. It's heavy, I know. It's still a lot of fun, especially once it's finished and you get to use it!

Transparency of picture box

Im just looking for an answer in my simple problem. Here it is
I have a pricturebox that has image with transparent background i Set the picturebox backcoloras transparent.
and after that, the picture has transparent bg. But after i added this code
ìmg1.Left = windows.forms.cursor.Position.X - me.Left
ìmg1.Top= windows.forms.cursor.Position.Y - me.Top
'code for using img as cursor
the image bg is not really transparent like this
I think the transaparent backcoloris not really transparent. it will only get the backcolorof form and use it as backcolorof image instead of transparent.
Is there any solution to make it fully transparent?
You are correct in your assumption.
Transparency in winforms does not mean that the object is actually transparent. Instead, it means that it will display it's parent object instead of it's background, including it's background, images and text, but not including any other controls on it, hence your problem.
Since the parent control of your top most picture box is not and can not be the other picture boxes, the fact that your top most picture box have a transparent background will not help.
Unfortunately, using the form's TransparencyKey property will also not help for this. (It will make the selected color transparent, but will yield unexpected (and usually undesired) results.
In order to achieve your goal, you will have to follow OneFineDay's advice in the comments, and use Graphics to draw the image yourself.
Fortunately, this is very easy to do:
Public Sub DrawImage(Image as Image, Location As Point)
Using(Dim g as Graphics = Me.CreateGraphics())
g.DrawImage(Image, Location)
EndUsing
End Sub
This blog article inspired this SO answer. These were the basis for a more robust control with scaling, text, contentalignment etc.
The following is a scaled back version (in VB) to primarily implement the appearance of true transparency. The core painting is nearly identical to the original SO post except to account for a border in the painting. A few control level features have also been retained.
'Namespace omitted to reduce indentation
Imports System.Windows.Forms
Imports System.Drawing
Imports System.ComponentModel
Imports System.Drawing.Drawing2D
Public Class TransPicBox
Inherits PictureBox
Public Enum ImageSizing
None
Stretch
Scale
End Enum
Public Sub New()
' defaults for a new one
MyBase.BackColor = Color.Transparent
MyBase.InitialImage = Nothing
MyBase.ErrorImage = Nothing
MyBase.Image = Nothing
End Sub
Public Overloads Property Image As Image
Get
Return MyBase.Image
End Get
Set(value As Image)
MyBase.Image = value
InvalidateParent()
End Set
End Property
Private imgSizing As ImageSizing = ImageSizing.None
Public Property ImageSizing As ImageSizing
Get
Return imgSizing
End Get
Set(value As ImageSizing)
imgSizing = value
InvalidateParent()
End Set
End Property
' because the child control displays are interdependent
' tell the parent to update when some things change
' Image, Scaling, Border, Text, BackColor etc
Private Sub InvalidateParent()
Invalidate()
If MyBase.Parent IsNot Nothing Then
MyBase.Parent.Invalidate()
End If
End Sub
' since the display depends on ZOrder, provide
' a control method to alter it
Public Sub MoveUpZOrder()
ChangeZOrder(-1)
End Sub
Public Sub MoveDownZOrder()
ChangeZOrder(+1)
End Sub
Private Sub ChangeZOrder(value As Int32)
Dim ndx As Integer = Parent.Controls.GetChildIndex(Me)
If ((ndx + value) >= 0) AndAlso ((ndx + value) < Me.Parent.Controls.Count) Then
Me.Parent.Controls.SetChildIndex(Me, ndx + value)
End If
End Sub
' if you want to remove properties, this is how
<Browsable(False), EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Property ErrorImage As Image
Protected Overrides Sub OnPaintBackground(pevent As PaintEventArgs)
If MyBase.BackColor = Color.Transparent Then
' magic happens here!
PaintSiblings(pevent)
Else
' do nothing special when the backcolor is not Transparent
MyBase.OnPaintBackground(pevent)
End If
End Sub
' code for painting the image
Protected Overrides Sub OnPaint(pe As PaintEventArgs)
Dim rect As Rectangle
If (MyBase.Image IsNot Nothing) Then
rect = GetImgRect(Bounds)
pe.Graphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
pe.Graphics.CompositingQuality = CompositingQuality.HighQuality
pe.Graphics.SmoothingMode = SmoothingMode.HighQuality
pe.Graphics.DrawImage(Image, rect)
End If
End Sub
Private Sub PaintSiblings(e As PaintEventArgs)
' need to access the parent' controls collection
If (Parent IsNot Nothing) Then
Dim borderSize As Integer = 0
Dim thisLeft As Single = -Left
Dim thisTop As Single = -Top
' fix
Select Case MyBase.BorderStyle
Case BorderStyle.FixedSingle
borderSize = SystemInformation.BorderSize.Width
Case BorderStyle.Fixed3D
borderSize = SystemInformation.Border3DSize.Width
End Select
' Shift ClipBounds to form relative coords
e.Graphics.TranslateTransform(thisLeft, thisTop)
' Get Parent to paint the part behind us:
' we cant know if thats been done or not
Using pea As New PaintEventArgs(e.Graphics, e.ClipRectangle)
InvokePaintBackground(Parent, pea)
InvokePaint(Parent, pea)
End Using
' shift back
e.Graphics.TranslateTransform(-thisLeft, -thisTop)
' starting control index is...well, ours
Dim startAt As Integer = Parent.Controls.GetChildIndex(Me)
Dim ctl As Control
' Controls are in z-Order, so loop
' thru the controls "behind" me
For n As Int32 = Parent.Controls.Count - 1 To startAt + 1 Step -1
ctl = Parent.Controls(n)
' skip if they are invisible, too small or do not overlap me
If (ctl.Visible = False OrElse
ctl.Width = 0 OrElse
ctl.Height = 0 OrElse
Bounds.IntersectsWith(ctl.Bounds) = False) Then
Continue For
Else
Using bmp As New Bitmap(ctl.Width, ctl.Height, e.Graphics)
' draw this sibling to a bitmap
ctl.DrawToBitmap(bmp, New Rectangle(0, 0, ctl.Width, ctl.Height))
' shift the orientation relative to sibling and draw it
thisLeft = ctl.Left - Left
thisTop = ctl.Top - Top
'offset, then draw the image, reset
e.Graphics.TranslateTransform(thisLeft - borderSize,
thisTop - borderSize)
e.Graphics.DrawImageUnscaled(bmp,
New Point(0, 0))
e.Graphics.TranslateTransform(-thisLeft + borderSize,
-thisTop + borderSize)
End Using
End If
Next
Else
' not sure how this could happen
Using br As New SolidBrush(MyBase.BackColor)
e.Graphics.FillRectangle(br, ClientRectangle)
End Using
End If
End Sub
' image scaling is mainly a matter of the size and location
' of the img rect we use in Paint
Private Function GetImgRect(destRect As Rectangle) As Rectangle
Dim pt As New Point(0, 0)
Dim sz As Size
If MyBase.Image IsNot Nothing Then
Select Case Me.ImageSizing
Case ImageSizing.None
sz = Image.Size
Case ImageSizing.Scale
If Width > Height Then
sz = New Size(GetScaledWidth(Height), Height)
Else
sz = New Size(Width, GetScaledHeight(Width))
End If
Case ImageSizing.Stretch
sz = Me.Size
End Select
End If
' ToDo: move the pt if you add an Image ContentAlignment
' (Top, TopLeft, BottomRight...) property
Return New Rectangle(pt, sz)
End Function
Private Function GetScaledWidth(h As Integer) As Integer
Dim scale As Single = CSng(Image.Width / Image.Height)
Return CInt(h * scale)
End Function
Private Function GetScaledHeight(w As Integer) As Integer
Dim scale As Single = CSng(Image.Height / Image.Width)
Return CInt(w * scale)
End Function
End Class
How to Use It
Create a Class Library
Replace the new class boilerplate code with the above
Add references for the NameSpaces listed in the Imports statements
Build the Library. A new TransPicBox should show in the toolbox.
You can also just include the class code file in your project and rebuild to avoid a DLL dependency which includes just one thing. Results:
Four small PNGs under a larger one; all are on a Panel (rose BG)
The TopLeft and BottomRight images use a Transparent BG, the other 2 do not
They all have the border turned on to show the client area; the BL Clock uses a 3D border
The larger PNG uses ImageSizing.Scale to be about 150% larger
The parent backcolor shows thru the TL and BR images as well as the overlapping larger one in front. The control will display BMP and JPGs normally and still show whats behind empty areas (if any) when the control's back color is Transparent.
Notes:
This is a fairly expensive Paint. Each time one of these needs to be painted, at least a portion of the parent and every control under it must be repainted as well.
When moving a TransPicBox in the form designer, VS temporarily brings the control to the front, so the display is temporarily whacked
Windows ambles on normally so things behind your special control are still hidden as far as it is concerned. The image below shows that the portions of a button partially behind a TransPicBox will not 'glow' when the mouse is over it. As far as Windows knows, that portion of it cant be seen so it is not repainted.
Drawing the image using a graphics object is the recommended procedure if you're going to use it as a cursor. But if you sometime want to use a PictureBox (for reasons like being able to quickly change image using it's Image property, etc), that is possible too.
This code will draw a better "transparent" background, by drawing each control behind your PictureBox on it's background.
How to use:
1) Create a custom class.
2) Put Inherits PictureBox below the Public Class ... line.
3) Paste this code inside the class:
Protected Overrides Sub OnPaintBackground(e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(e)
If Parent IsNot Nothing Then
Dim index As Integer = Parent.Controls.GetChildIndex(Me)
For i As Integer = Parent.Controls.Count - 1 To index + 1 Step -1
Dim c As Control = Parent.Controls(i)
If c.Bounds.IntersectsWith(Bounds) AndAlso c.Visible = True Then
Dim bmp As New Bitmap(c.Width, c.Height, e.Graphics)
c.DrawToBitmap(bmp, c.ClientRectangle)
e.Graphics.TranslateTransform(c.Left - Left, c.Top - Top)
e.Graphics.DrawImageUnscaled(bmp, Point.Empty)
e.Graphics.TranslateTransform(Left - c.Left, Top - c.Top)
bmp.Dispose()
End If
Next
End If
End Sub
4) Build your project.
5) Select your class from the toolbox and add it to your form/usercontrol.

Dropping shadow on WinForm distorts interface

I'm using the following code to create a Windows7 style drop shadow effect on my WinForms:
<DllImport("dwmapi.dll", PreserveSig:=True)> _
Private Shared Function DwmSetWindowAttribute(hwnd As IntPtr, attr As Integer, ByRef attrValue As Integer, attrSize As Integer) As Integer
End Function
<DllImport("dwmapi.dll")> _
Private Shared Function DwmExtendFrameIntoClientArea(hWnd As IntPtr, ByRef pMarInset As Margins) As Integer
End Function
Private Function CreateDropShadow() As Boolean
Try
Dim val As Integer = 2
Dim ret1 As Integer = DwmSetWindowAttribute(Me.Handle, 2, val, 4)
If ret1 = 0 Then
Dim m As New Margins(0, 0, 0, 0)
Dim ret2 As Integer = DwmExtendFrameIntoClientArea(Me.Handle, m)
Return ret2 = 0
Else
Return False
End If
Catch ex As Exception
' Probably dwmapi.dll not found (incompatible OS)
Return False
End Try
End Function
Protected Overrides Sub OnHandleCreated(e As EventArgs)
CreateDropShadow()
MyBase.OnHandleCreated(e)
End Sub
The result of above code creates a nice drop shadow effect on my borderless winform, but it causes the UI to distort. All the controls and labels on my form aren't appearing properly, with text not readable.
Am I missing something here? I don't want to use the traditional drop shadow effect using CreateParams, its too 'boxy' look and doesn't give a nice shadow effect.
Here are screenshots of without shadow and with shadow:
Thanks.
Dim m As New Margins(0, 0, 0, 0)
There's a subtle mistake visible here, looks a lot like you are using System.Drawing.Printing.Margins. But that's not a type that's compatible with the Windows' MARGINS type. Which is a structure, not a class.
So this just goes complete wrong, Windows reads nonsense instead of (0, 0, 0, 0). And extends the frame into the entire client area. Which then plays havoc on any control that draws with GDI, it is a 24bpp drawing api that leaves the alpha at 0 so anything that should be black becomes transparent instead.
Fix this by declaring a proper MARGINS structure:
Structure MARGINS
Public Left, Right, Top, Bottom As Integer
End Structure

Create Image from Graphics

In VB.NET, I need to create an Image based on a Graphics object I have. However, there is no method such as Image.fromGraphics() etc. What should I do then?
Try something like this MSDN article states. Essentialy create a Graphics Object from a Bitmap. Then use Graphic methods to do what you need to to the Image and then you can use the Image how you need to. As #Damien_The_Unbeliever stated your Graphics Object is created to enable drawing on another object, it does not have an Image to copy, the object it was created on does.
From above article:
Dim flag As New Bitmap(200, 100)
Dim flagGraphics As Graphics = Graphics.FromImage(flag)
Dim red As Integer = 0
Dim white As Integer = 11
While white <= 100
flagGraphics.FillRectangle(Brushes.Red, 0, red, 200, 10)
flagGraphics.FillRectangle(Brushes.White, 0, white, 200, 10)
red += 20
white += 20
End While
pictureBox1.Image = flag
Have a look at the Graphics.DrawImage method and its overloads.
Here's a snippet from one of the examples that draws an image onto the screen, using a Graphics object from Winform's Paint event:
Private Sub DrawImageRect(ByVal e As PaintEventArgs)
' Create image.
Dim newImage As Image = Image.FromFile("SampImag.jpg")
' Create rectangle for displaying image.
Dim destRect As New Rectangle(100, 100, 450, 150)
' Draw image to screen.
e.Graphics.DrawImage(newImage, destRect)
End Sub

Data grid view header Grid color

This is a VB .NET application where we are showing the output of a SQL statement in a Datagrid view. I'm using .NET 2005.
We need to get the separators of the headers on the grid control to be the same colors as the GridColor on the form.
We've tried looking through all of the properties of the DataGridView control, and found some interesting things that looked promising such as the DataGridViewAdvancedHeaderStyle, and DataGridViewHeaderBorderStyle, but none of it seems to allow you to change the colors on it.
Does anyone know how to do this without remaking the entire thing with a GDI+ control?
Well, I never did find a property for this, so I ended up creating a custom component, and overloading the OnPaint event handler to draw a line over the existing one.
Here is the code for it if anyone else ever comes across this post looking for a solution:
Private Sub CustomDataGridView_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim g As Graphics = e.Graphics
Dim pen As New Pen(Me.GridColor)
Dim TWidth As Integer = 2
Dim HeaderWidth As Integer = 0
If Me.RowHeadersVisible Then
HeaderWidth = Me.RowHeadersWidth
End If
For Each column As DataGridViewColumn In Me.Columns
Dim x As Integer = HeaderWidth + TWidth - 1
TWidth += column.Width
Dim top As Integer = column.HeaderCell.ContentBounds.Top
Dim bottom As Integer = column.HeaderCell.ContentBounds.Bottom + 1
pen.Width = 2
g.DrawLine(pen, x, top, x, bottom)
Next column
End Sub
To change the backcolor of the Column Headers in a datagridview, choose False for EnableHeadersVisualStyles. Then open ColumnHeadersDefaultCellStyle and choose the background color.
I can't see the picture but what about playing with these?
DataGridView.ColumnBordersHeaderStyle
DataGridView.RowBordersHeaderStyle