Hey I was doing a VisualBasic Windows Form Control project and I encountered with an little issue:
This is my OnPaint Method:
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim g As Graphics
g = e.Graphics
Dim ancho As Integer = Me.Width / 2
Dim alto As Integer = Me.Height / 2
_posiciox = 5
Percentatge(_maxim,_minim)
For Index As Double = 0.1 To 10.0
If Index <= _percent Then
If Index >= 9 Then
g.FillRectangle(_color4, _posiciox, alto - 10, 40, 20)
ElseIf Index >= 8 Then
g.FillRectangle(_color3, _posiciox, alto - 10, 40, 20)
ElseIf Index >= 6 Then
g.FillRectangle(_color2, _posiciox, alto - 10, 40, 20)
Else
g.FillRectangle(_color1, _posiciox, alto - 10, 40, 20)
End If
End If
g.DrawRectangle(Pens.Black, _posiciox, alto - 10, 40, 20)
_posiciox = _posiciox + 45
Next
End Sub
Where the color Filled are Brushes.Color params. Also I wanted to let the User chose this Color.
I've tried with Public property like this:
Public Property ColorBaix() As Color
Get
Return Color.Coral
End Get
Set(ByVal value As Color)
End Set
End Property
But I can't transform a Brushes.Color into a Color.Color:
I've found some examples Colors to Brush but I can't use "new param" on OnPaint due to overloading issues.
Is It that the Only way or Maybe there is another solution?
SOLVED:
I adapted my project:
<Description("Color Primari")>
Public Property ColorBaix() As Color
Get
Return color1
End Get
Set(ByVal value As Color)
color1 = value
_color1 = New SolidBrush(value)
Invalidate()
End Set
End Property
You're barking up the wrong tree a bit.
You don't want to turn a brush into a colour, you want to set the color property of your existing brush to a new value.
so when you first made the brush you did something like this:
Dim mybrush As New SolidBrush(Color.Aqua)
then later you want to set the colour
mybrush.Color = Color.Azure
if you want to obtain the colour of a brush, then you can do this:
Dim myColour As New Color
myColour = mybrush.Color
Related
I'm adding a control to a picturebox. This control is a component, precisely it's a toggle switch posted here. I'd like this control to be vertical and not horizontal .
So, since objects can't be rotated or flipped, I found a way to flip the picturebox image with:
PictureBox1.Image.RotateFlip(RotateFlipType.Rotate180FlipNone)
PictureBox1.Refresh()
The error I'm getting at RunTime is:
System.Windows.Forms.PictureBox.Image.get returned Nothing
Endeed the control is not an image so is there a way to flip the control inside of the picturebox by 180 degrees?
Also, You think there is a way to know when the value of the toggle switch is on or off?
Thanks
As already mentioned above, extend the control to have it drawn either horizontally or vertically.
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Public Class ToggleSwitch
Inherits CheckBox
Public Sub New()
MyBase.New
SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.UserPaint, True)
UpdateStyles()
Padding = New Padding(6)
End Sub
Private _orientation As Orientation = Orientation.Horizontal
Public Property Orientation As Orientation
Get
Return _orientation
End Get
Set(value As Orientation)
_orientation = value
Dim max = Math.Max(Width, Height)
Dim min = Math.Min(Width, Height)
If value = Orientation.Vertical Then
Size = New Size(min, max)
Else
Size = New Size(max, min)
End If
End Set
End Property
'Fix by: #41686d6564
<Browsable(False),
Bindable(False),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
EditorBrowsable(EditorBrowsableState.Never)>
Public Overrides Property AutoSize As Boolean
Get
Return False
End Get
Set(value As Boolean)
End Set
End Property
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim g = e.Graphics
g.Clear(BackColor)
g.SmoothingMode = SmoothingMode.AntiAlias
g.PixelOffsetMode = PixelOffsetMode.Half
Dim p = Padding.All
Dim r = 0
Dim rec As Rectangle
Using gp = New GraphicsPath
If _orientation = Orientation.Vertical Then
r = Width - 2 * p
gp.AddArc(p, p, r, r, -180, 180)
gp.AddArc(p, Height - r - p, r, r, 0, 180)
r = Width - 1
rec = New Rectangle(0, If(Checked, Height - r - 1, 0), r, r)
'Or
'rec = New Rectangle(0, If(Checked, 0, Height - r - 1), r, r)
'To get the ON on top.
Else
r = Height - 2 * p
gp.AddArc(p, p, r, r, 90, 180)
gp.AddArc(Width - r - p, p, r, r, -90, 180)
r = Height - 1
rec = New Rectangle(If(Checked, Width - r - 1, 0), 0, r, r)
End If
gp.CloseFigure()
g.FillPath(If(Checked, Brushes.DarkGray, Brushes.LightGray), gp)
g.FillEllipse(If(Checked, Brushes.Green, Brushes.WhiteSmoke), rec)
End Using
End Sub
End Class
As for the second part of your question, please read CheckBox.Checked property and CheckBox.CheckedChanged event.
Impelemntation example:
Private Sub ToggleSwitch1_CheckedChanged(sender As Object, e As EventArgs) Handles ToggleSwitch1.CheckedChanged
If ToggleSwitch1.Checked Then
'ToDo with ON state...
Else
'ToDo with OFF state..
End If
End Sub
I have a simple pixelsearch function searching for a certain Argb Color on screen.
This already works great and it finds the pixel with the color but I would like to add a Color Variation detection to it.
The Color of the pixel it should detect changes sometimes from (255, 100, 100, 100) to (255, 110, 94, 102) or something else (values are changing 10 points). Now the Pixelsearch function should have a Variationdetection so it would detect pixels with a near similar color so instead of only searching for color (255, 100, 100, 100) it should also search for (255, 101, 99, 102)... and more.
Is it possible to code that instead of Dim each Color and search for it?
Thats the code that I have already:
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim xd3 = Color.FromArgb(255, 100, 100, 100) 'Searching for this color on the screen
Dim b As New Bitmap(2210, 1100) 'Position of Bitmap
Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(b)
g.CopyFromScreen(Me.Left, Me.Top, 0, 0, b.Size) 'Searching on Screen
For i = 0 To (Me.Width - 0) 'searching each pixel
For j = 0 To (Me.Height - 0) 'searching each pixel
If b.GetPixel(i, j) = xd3 Then 'If pixel has same color that im searching for it will show a messagebox true
MessageBox.Show("true")
End If
Next
Next
End Sub
I suggest something like this :
If Color_Is_In_The_Target_Variations(10, b.GetPixel(i, j), xd3) Then
MessageBox.Show("true")
End If
and
Private Function Color_Is_In_The_Target_Variations(variation As Integer, tested As Color, target As Color) As Boolean
If tested.R >= target.R - variation And tested.R <= target.R + variation And
tested.G >= target.G - variation And tested.G <= target.G + variation And
tested.B >= target.B - variation And tested.B <= target.B + variation Then
Return True
Else
Return False
End If
End Function
The Problem: I'm programmatically generating labels but am having trouble referencing them in code because they don't exist at runtime.
The Context: For a game, I've generated a 10x10 grid of labels with the following:
Public lbl As Label()
Dim tilefont As New Font("Sans Serif", 8, FontStyle.Regular)
Private Sub Lucror_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim i As Integer = 0
Dim a As Integer = 0
Dim height As Integer
Dim width As Integer
height = 30
width = 30
ReDim lbl(99)
For i = 0 To 99
lbl(i) = New Label
lbl(i).Name = i
lbl(i).Size = New System.Drawing.Size(30, 30)
lbl(i).Location = New System.Drawing.Point((width), height)
lbl(i).Text = i
lbl(i).Font = tilefont
Me.Controls.Add(lbl(i))
width = width + 30
a = a + 1 'starting new line if required
If (a = 10) Then
height = height + 30
width = 30
a = 0
End If
Next
End Subenter code here
This worked fine but the labels function as tiles in the game and game tiles need to store 2-3 integers each as well as be able to be referenced through event handlers. I figured a possible way to store integers would be to generate 100 arrays, each named after a label and each holding the 2-3 integers, but that seems very redundant.
What I need:
On click and on hover event handlers for every label
An array (or dictionary?) to store 2-3 integers for every label
Labels have to reference each others names ie. do something to label with name (your name + 1).
The Question: Is there a simple way to achieve these three things with the current way I generate labels (and if so, how?) and if not, how else can I generate the 100 labels to make achieving these things possible?
Any help is much appreciated.
Your labels do exist at runtime, but not at compile time. Attaching events is a little different at runtime, you must use AddHandler.
Below is some sample code that should illustrate everything you're asking for. I've introduced inheritance as a way of saving data that is pertinent to each tile. The GameTile type behaves exactly as a label, and we've added some functionality for storing integers and naming the control.
Public Class Form1
Dim tilefont As New Font("Sans Serif", 8, FontStyle.Regular)
Public Property GameTiles As List(Of GameTile)
Private Sub Lucror_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim a As Integer = 0
Dim xPosition As Integer = 30
Dim yPosition As Integer = 30
GameTiles = New List(Of GameTile)
For i = 0 To 99
Dim gt As New GameTile(i.ToString)
gt.Size = New System.Drawing.Size(30, 30)
gt.Location = New System.Drawing.Point((yPosition), xPosition)
gt.Font = tilefont
gt.Integer1 = i + 1000
gt.Integer2 = i + 2000
gt.Integer3 = i + 3000
Me.Controls.Add(gt)
AddHandler gt.Click, AddressOf TileClickHandler
GameTiles.Add(gt)
yPosition = yPosition + 30
a = a + 1 'starting new line if required
If (a = 10) Then
xPosition = xPosition + 30
yPosition = 30
a = 0
End If
Next
End Sub
Private Sub TileClickHandler(sender As Object, e As EventArgs)
Dim gt = CType(sender, GameTile)
MsgBox("This tile was clicked: " & gt.Text &
Environment.NewLine & gt.Integer1 &
Environment.NewLine & gt.Integer2 &
Environment.NewLine & gt.Integer3)
End Sub
End Class
Public Class GameTile
Inherits Label
'this class should be in a separate file, but it's all together for the sake of clarity
Public Property Integer1 As Integer
Public Property Integer2 As Integer
Public Property Integer3 As Integer
Public Sub New(NameText As String)
MyBase.New()
Name = NameText
Text = NameText
End Sub
End Class
I want to make a custom polygon shape class, which i can drag and drop unto my form at will (just as it is done in the case of OvalShape and RectangleShape objects in VS toolbox). I checked site1, site2 and site3, one of which specifically said that the OnPaint Event of my form should be overridden. Is there any way I can achieve the same while creating the custom polygon shape, and still have my polygon appear on the toolbox?
Edit:
#Jens: I'll like the control to generate its code with the following tested code:
Me.ClientSize = New Point(24, 24)
Dim r1 As Integer = Min(cx, cy) - 10
Dim r2 As Integer = Min(cx, cy) \ 2
Dim pts(9) As Point
For i As Integer = 0 To 9 Step 2
pts(i).X = cx + CInt(r1 * Cos(i * PI / 5 - PI / 2))
pts(i).Y = cy + CInt(r1 * Sin(i * PI / 5 - PI / 2))
pts(i + 1).X = cx + CInt(r2 * Cos((i + 1) * PI / 5 - PI / 2))
pts(i + 1).Y = cy + CInt(r2 * Sin((i + 1) * PI / 5 - PI / 2))
Next i
That gives me a star with 5 spikes. How can i store them in the Points variable created,
OR
store the points as a region so that whenever i change forecolor, it fills the region (i.e. polygn) with the selected color. I also want to prevent painting the backcolor. Please take a look at the links below to a c# solution of what i really want, but i suck at converting c# to vb.
link1; Link2
Thanks a lot
I am not entirely sure that that is what you want. You can always derive a new class from Control and use its Paint event to draw whatever you like. In your case a polygon.
The control therefore contains a Points property that is just an array of PointF values that define the edges of the polygon. By using the DesignerSerializationVisible.Content attribute you make it possible to edit these values through the designer directly. The code looks like this:
Public Class PolygonControl
Inherits Control
Private _Points(2) As PointF
<System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Content)>
Public Property Points As PointF()
Get
Return _Points
End Get
Set(value As PointF())
_Points = value
End Set
End Property
Public Property LineColor As Color = Color.Black
Public Property LineWidth As Integer = 2
Private Sub PolygonControl_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
e.Graphics.Clear(Me.BackColor)
If Points IsNot Nothing AndAlso Points.Count > 1 Then
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
Using b As New SolidBrush(ForeColor)
Using p As New Pen(b, LineWidth)
e.Graphics.DrawPolygon(p, Points)
End Using
End Using
End If
End Sub
End Class
I added a color and width property as well. This is just to give you a rough idea. Notice the attribute above the Points property.
In "action" it looks like this:
Adding better designer support is certainly possible, but I have no experience with that whatsoever. But it is a start.
Edit
Since you always draw the same shape, you can precalculate the points in the control's constructor and just draw the shape in the paint event:
Public Class StarControl
Inherits Control
'Storage for the shape's points
Private pts(9) As Point
'Constructor
Public Sub New()
Me.ClientSize = New Size(24, 24)
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
'Precalculate the shape
Dim cx = CInt(Me.ClientSize.Width / 2)
Dim cy = CInt(Me.ClientSize.Height / 2)
Dim r1 As Integer = Min(cx, cy) - 10
Dim r2 As Integer = Min(cx, cy) \ 2
ReDim pts(9)
For i As Integer = 0 To 9 Step 2
pts(i).X = cx + CInt(r1 * Cos(i * PI / 5 - PI / 2))
pts(i).Y = cy + CInt(r1 * Sin(i * PI / 5 - PI / 2))
pts(i + 1).X = cx + CInt(r2 * Cos((i + 1) * PI / 5 - PI / 2))
pts(i + 1).Y = cy + CInt(r2 * Sin((i + 1) * PI / 5 - PI / 2))
Next i
End Sub
Public Property LineColor As Color = Color.Black
Public Property FillColor As Color = Color.Gold
Public Property LineWidth As Integer = 1
Public Sub PaintMe(sender As Object, e As PaintEventArgs) Handles Me.Paint
'Draw the precalculated shape
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
Using b As New SolidBrush(FillColor)
e.Graphics.FillPolygon(b, pts)
End Using
Using b As New SolidBrush(LineColor)
Using p As New Pen(b, LineWidth)
e.Graphics.DrawPolygon(p, pts)
End Using
End Using
End Sub
End Class
For an even cooler effect move the shape calculation into the Paint event handler so the shape resizes itself based on the control's size. This allows you to draw stars of arbitrary size.
how can I change the grey part into white color?
I want my tabcontrol filled with full white color.
So far what i did is like this:
Private Sub TabControl1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles TabControl1.DrawItem
Dim g As Graphics = e.Graphics
Dim tp As TabPage = TabControl1.TabPages(e.Index)
Dim br As Brush
Dim sf As New StringFormat
Dim r As New RectangleF(e.Bounds.X, e.Bounds.Y + 2, e.Bounds.Width, e.Bounds.Height - 2)
sf.Alignment = StringAlignment.Center
Dim strTitle As String = tp.Text
'If the current index is the Selected Index, change the color
If TabControl1.SelectedIndex = e.Index Then
'this is the background color of the tabpage header
br = New SolidBrush(Color.White) ' chnge to your choice
g.FillRectangle(br, e.Bounds)
'this is the foreground color of the text in the tab header
br = New SolidBrush(Color.Black) ' change to your choice
g.DrawString(strTitle, TabControl1.Font, br, r, sf)
Else
'these are the colors for the unselected tab pages
br = New SolidBrush(Color.White) ' Change this to your preference
g.FillRectangle(br, e.Bounds)
br = New SolidBrush(Color.Black)
g.DrawString(strTitle, TabControl1.Font, br, r, sf)
End If
End Sub
and I also put this at PageLoad function:
TabControl1.DrawMode = TabDrawMode.OwnerDrawFixed
For Each tg As TabPage In TabControl1.TabPages
tg.BackColor = Color.White
Next
There is no property to do this. However it is possible by using something like this
http://dotnetrix.co.uk/tabcontrol.htm
All controls on this site are freely available under MIT license.
Spending fair time to research if someone find a solution; There could be some work around. But according to MSDN Ref.
TabControl.BackColor Property
NET Framework (current version) This API supports the product
infrastructure and is not intended to be used directly from your code.
This member is not meaningful for this control.
Namespace: System.Windows.Forms Assembly: System.Windows.Forms (in
System.Windows.Forms.dll)
As far as I understand, this is adjustable from user's windows setting. (Highlight Color) of TabControl, Forms and other controls; otherwise MS could simply turn this property on.
I make a trick to get around this, I put on the gray part a white label and I have the following result:
Since that color segment of the tabcontrol is unpaintable and cannot be controlled, you have to use a panel or label, etc. to cover up the background color where there is no tabpage header. I use a panel to do this.
This statement working correctly:
Dim PutBackColor As Boolean = False
Private Sub TabControl1_DrawItem(sender As System.Object, e As System.Windows.Forms.DrawItemEventArgs) Handles TabControl1.DrawItem
If Me.PutBackColor = False Then
e.Graphics.FillRectangle(New SolidBrush(<YourColor>), 0 , 0, e.Bounds.Width + 2, e.Bounds.Height + 2)
Me.PutBackColor = True
End If
e.Graphics.FillRectangle(New SolidBrush(<YourColor>), 0 , 0, e.Bounds.Width + 2, e.Bounds.Height + 2)
e.Graphics.DrawString(Me.TabControl1.TabPages(e.In dex).Text, e.Font, Brushes.White, e.Bounds.X + 5, e.Bounds.Y + 5)
If e.State = DrawItemState.Selected Then
Me.PutBackColor = False
End If
End Sub