Imports System.Drawing.Graphics
Imports System.Drawing.Pen
Imports System.Drawing.Color
Imports System.Drawing.Brush
Imports System.Drawing.Point
Public Class Main
Protected m_pen As Pen
Protected m_timer As Timer
Protected m_vertices(10) As Point3D
Protected m_faces(10, 4) As Integer
Protected m_angle As Integer
Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Create a GDI+ Pen. This will be used to draw lines.
m_pen = New Pen(Color.Red)
InitCube()
' Create the timer.
m_timer = New Timer()
' Set the timer interval to 33 milliseconds. This will give us 1000/34 ~ 30 frames per second.
m_timer.Interval = 33
' Set the callback for the timer.
AddHandler m_timer.Tick, AddressOf AnimationLoop
' Start the timer.
m_timer.Start()
End Sub
Private Sub InitCube()
' Create an array with 12 points.
m_vertices = New Point3D() {
New Point3D(0, 0, 1),
New Point3D(1, 0, -1),
New Point3D(1, 0, 1),
New Point3D(0, 0, 1),
New Point3D(0, 1, 1),
New Point3D(1, 1, 1),
New Point3D(0, 1, -1),
New Point3D(1, 1, -1),
New Point3D(-1, 0, -1),
New Point3D(-1, 0, 1),
New Point3D(-1, 1, 1),
New Point3D(-1, 1, -1)}
' Create an array representing the 6 faces of a cube. Each face is composed by indices to the vertex array
' above.
m_faces = New Integer(,) {{0, 1, 2, 3}, {0, 8, 9, 3}, {0, 1, 7, 6}, {0, 8, 6, 10}, {10, 11, 4, 6}, {4, 5, 6, 7}, {2, 3, 4, 5}, {3, 4, 11, 9}, {8, 9, 10, 11}, {1, 2, 5, 7}}
End Sub
Private Sub AnimationLoop()
' Forces the Paint event to be called.
Me.Invalidate()
' Update the variable after each frame.
m_angle += 1
End Sub
Private Sub Main_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim t(8) As Point3D
Dim f(4) As Integer
Dim v As Point3D
' Clear the window
e.Graphics.Clear(Color.LightBlue)
' Transform all the points and store them on the "t"- array.
For i = 0 To 19
v = m_vertices(i)
t(i) = v.RotateX(m_angle).RotateY(m_angle).RotateZ(m_angle)
t(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 4)
Next
' Draw the wireframe cube. Uses the "m_faces" array to find the vertices that compose each face.
For i = 0 To 17
e.Graphics.DrawLine(m_pen, CInt(t(m_faces(i, 0)).X), CInt(t(m_faces(i, 0)).Y), CInt(t(m_faces(i, 1)).X), CInt(t(m_faces(i, 1)).Y))
e.Graphics.DrawLine(m_pen, CInt(t(m_faces(i, 1)).X), CInt(t(m_faces(i, 1)).Y), CInt(t(m_faces(i, 2)).X), CInt(t(m_faces(i, 2)).Y))
e.Graphics.DrawLine(m_pen, CInt(t(m_faces(i, 2)).X), CInt(t(m_faces(i, 2)).Y), CInt(t(m_faces(i, 3)).X), CInt(t(m_faces(i, 3)).Y))
e.Graphics.DrawLine(m_pen, CInt(t(m_faces(i, 3)).X), CInt(t(m_faces(i, 3)).Y), CInt(t(m_faces(i, 0)).X), CInt(t(m_faces(i, 0)).Y))
Next
End Sub
End Class
This code is meant to show an animation of two cubes joined together rotating around all 3 axis. Note this is modified code of an original program that just showed a single cube.
The program throws an error when it hits this loop saying "indexOutOfRangeExeption Occured"
For i = 0 To 19
v = m_vertices(i)
t(i) = v.RotateX(m_angle).RotateY(m_angle).RotateZ(m_angle)
t(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 4)
Next
The actual line (according to visual studios) that is causing the error is this:
t(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 4)
Whats a fix for this and why does it fix it as I don't understand why this is a problem.
m_vertices only sized to 11 elements, and you are trying to read 20.
t is sized to 9, and you are trying to read 20.
You need bigger arrays, or you need to change the way to code executes.
Try increasing the array sizes at Protected m_vertices(10) As Point3D and Dim t(8) As Point3D, though you may have other issues.
Related
Can you help me with my DataGridView? I need to show sum of column based on another column.
For example, I have Part number 1,2,3. QTY for PN is always 1 because of the serial number given.
PN 1 has 10qty (10rows). I need to sum it based on that PN and put the sum value at the end cell. Please see below sample:
It is excel I know, but just please bear with me pretend it is DataGridView.
Total sum is based on sum of cost for the same PN.
You will need to follow the link in my comment, and do some manipulation in the DataGridView_Paint event. I have done that below.
I made a class to hold your data called Model. I also used DataBinding to put that data into the DataGridView. Your method for holding and applying the data might be different, but this works well.
Public Class Form1
Private data As List(Of Model)
Private dataGroups As IEnumerable(Of (PN As Integer, TotalSum As Double, Count As Integer))
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
data = New List(Of Model) From {
New Model(1, 1, 11.5),
New Model(1, 12, 2),
New Model(1, 13, 10.4),
New Model(1, 14, 12.3),
New Model(1, 15, 10),
New Model(1, 16, 10),
New Model(2, 17, 5),
New Model(2, 18, 1),
New Model(2, 19, 7),
New Model(2, 20, 2),
New Model(2, 21, 4),
New Model(3, 22, 4),
New Model(3, 23, 6),
New Model(3, 24, 3),
New Model(3, 25, 7)}
DataGridView1.DataSource = data
dataGroups = data.GroupBy(Function(d) d.PN).Select(Function(g) (g.Key, g.Sum(Function(g1) g1.Cost), g.Count()))
Dim textBoxColumn = New DataGridViewTextBoxColumn() With {.HeaderText = "Total Sum"}
DataGridView1.Columns.Add(textBoxColumn)
End Sub
Private Sub DataGridView1_Paint(sender As Object, e As PaintEventArgs) Handles DataGridView1.Paint
If DataGridView1.DataSource IsNot Nothing Then
Dim columnIndex = DataGridView1.Columns.Count - 1
Dim counter As Integer = 0
Dim index As Integer = 0
Dim rowDisplayRectangle = DataGridView1.GetRowDisplayRectangle(0, True)
Dim headerCell = DataGridView1.Columns(0).HeaderCell
Dim defaultCellStyle = DataGridView1.DefaultCellStyle
Dim font = DataGridView1.Font
For Each dataGroup In dataGroups
Dim columnDisplayRectangle = DataGridView1.GetColumnDisplayRectangle(columnIndex, True)
Dim totalSumString = dataGroup.TotalSum.ToString()
Dim rect As New Rectangle(
columnDisplayRectangle.X,
columnDisplayRectangle.Y + headerCell.ContentBounds.Height + counter * rowDisplayRectangle.Height + 8,
columnDisplayRectangle.Width - 1,
(rowDisplayRectangle.Height + 1) * dataGroup.Count - 7 + index)
e.Graphics.FillRectangle(New SolidBrush(defaultCellStyle.BackColor), rect)
Dim point As New Point(
columnDisplayRectangle.X + columnDisplayRectangle.Width - e.Graphics.MeasureString(totalSumString, font).Width - 8,
rect.Y + rect.Height - e.Graphics.MeasureString(totalSumString, font).Height - (rowDisplayRectangle.Height - e.Graphics.MeasureString(totalSumString, font).Height) / 2)
e.Graphics.DrawString(totalSumString, font, New SolidBrush(defaultCellStyle.ForeColor), point)
counter += dataGroup.Count
index += 1
Next
End If
End Sub
End Class
Public Class Model
Public Sub New(pn As Integer, serial As Integer, cost As Double)
Me.PN = pn
Me.Serial = serial
Me.Cost = cost
End Sub
Public Property PN As Integer
Public Property Serial As Integer
Public Property Cost As Double
End Class
It is not straightforward and is not handled out of the box. You also may need to fool with the integers in the draw event if you find items not aligning with different fonts. I don't have time to do that.
In preparation for my Fall upcoming Adobe Illustrator class, where students always curse while learning the Pen tool and how to draw Bézier curves, I thought I'd provide them with some "theoretical foundation" outside of Illustrator. So far, I'm able to demonstrate the workings of a curve through four points described by x and y coordinates entered in a separate text boxes (see attached screen capture). My question, how can I "transform" this static demonstration into an interactive one, by allowing the students to "select" control points (shown in blue) and move them around the PictureBox? That's not a simple problem. Any pointers would be appreciated.
Here is my source code so far:
Public Class Form1
Dim Point1_X, Point1_Y, Point2_X, Point2_Y, Point3_X, Point3_Y, Point4_X, Point4_Y As Integer
Dim LignesDeDirection As Boolean
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LignesDeDirection = False
Point1_X = 100
Point1_Y = 100
Point2_X = 200
Point2_Y = 200
Point3_X = 50
Point3_Y = 250
Point4_X = 400
Point4_Y = 400
tbPoint1_X.Text = Point1_X
tbPoint1_Y.Text = Point1_Y
tbPoint2_X.Text = Point2_X
tbPoint2_Y.Text = Point2_Y
tbPoint3_X.Text = Point3_X
tbPoint3_Y.Text = Point3_Y
tbPoint4_X.Text = Point4_X
tbPoint4_Y.Text = Point4_Y
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.Clear(Color.LightGray)
Dim FondBlanc As New SolidBrush(Color.White)
e.Graphics.FillRectangle(FondBlanc, 0, 0, PictureBox1.Width, PictureBox1.Height)
Dim blackPen = New Pen(Color.FromArgb(128, 128, 128), 1)
Dim blackPen2pix = New Pen(Color.FromArgb(64, 64, 64), 2)
Dim EllipsePen = New Pen(Color.FromArgb(0, 128, 255), 3)
Dim blackPen3 = New Pen(Color.Black, 5.0F)
Dim blackPen2 = New Pen(Color.FromArgb(164, 164, 164), 1)
Dim CouleurPoint As New SolidBrush(Color.Magenta)
Dim CouleurControl As New SolidBrush(Color.Blue)
Dim Color2 = New Pen(Color.FromArgb(128, 128, 128), 1)
Dim PenBleu As New Pen(Color.Black, 2.0F)
PenBleu.EndCap = System.Drawing.Drawing2D.LineCap.Flat 'PenBleu.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor
PenBleu.CustomEndCap = New System.Drawing.Drawing2D.AdjustableArrowCap(8, 8)
Dim point1 As New Point(Point1_X, Point1_Y)
Dim point2 As New Point(Point2_X, Point2_Y)
Dim point3 As New Point(Point3_X, Point3_Y)
Dim point4 As New Point(Point4_X, Point4_Y)
e.Graphics.FillEllipse(CouleurPoint, Point1_X - 5, Point1_Y - 5, 10, 10)
e.Graphics.FillEllipse(CouleurControl, Point2_X - 5, Point2_Y - 5, 10, 10)
e.Graphics.FillEllipse(CouleurControl, Point3_X - 5, Point3_Y - 5, 10, 10)
e.Graphics.FillEllipse(CouleurPoint, Point4_X - 5, Point4_Y - 5, 10, 10)
Dim PenDashMagenta As New Pen(Color.Magenta, 1.5F)
PenDashMagenta.DashStyle = Drawing2D.DashStyle.Dash
Dim PenRéférence As New Pen(Color.ForestGreen, 1.0F)
If cbDirectionLines.Checked = True Then
LignesDeDirection = True
e.Graphics.DrawLine(PenRéférence, Point1_X, Point1_Y, Point2_X, Point2_Y)
e.Graphics.DrawLine(PenRéférence, Point3_X, Point3_Y, Point4_X, Point4_Y)
Else
LignesDeDirection = False
End If
e.Graphics.DrawEllipse(PenDashMagenta, Point1_X - 40, Point1_Y - 40, 80, 80)
e.Graphics.DrawEllipse(PenDashMagenta, Point4_X - 40, Point4_Y - 40, 80, 80)
e.Graphics.DrawBezier(PenBleu, point1, point2, point3, point4)
End Sub
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Point1_X = tbPoint1_X.Text
Point1_Y = tbPoint1_Y.Text
Point2_X = tbPoint2_X.Text
Point2_Y = tbPoint2_Y.Text
Point3_X = tbPoint3_X.Text
Point3_Y = tbPoint3_Y.Text
Point4_X = tbPoint4_X.Text
Point4_Y = tbPoint4_Y.Text
PictureBox1.Invalidate()
End Sub
End Class
I have a Custom Control that displays color selections in a drop down and it works good.
I found the performance was poor with multiple controls on the same Form so I changed it to store the Color index in the Items collection.
This works good but the Designer gets populated with a large array of values and this causes empty items in the control.
How do I stop the designer from storing the Items?
Here is the designer code I don't want:
Me.cboCWarcColor.Items.AddRange(New Object()
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140}
)
Here is the Custom Control code:
Imports System.Collections.Generic
Public Class ColorCombo
Inherits System.Windows.Forms.ComboBox
Private mSelectedColor As Color = Nothing
Private Shared myColors As New List(Of Color)
Private Shared myColorsIndices As New List(Of Object)
Private Sub ColorCombo_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles Me.DrawItem
Try
If e.Index < 0 Or e.Index >= myColors.Count Then
e.DrawBackground()
e.DrawFocusRectangle()
Exit Try
End If
' Get the Color object from the Items list
Dim aColor As Color = myColors.Item(e.Index) 'myColors.Item(e.Index)
' get a square using the bounds height
Dim rect As Rectangle = New Rectangle(4, e.Bounds.Top + 2, CInt(e.Bounds.Height * 1.5), e.Bounds.Height - 4)
' call these methods first
e.DrawBackground()
e.DrawFocusRectangle()
Dim textBrush As Brush
' change brush color if item is selected
If e.State = DrawItemState.Selected Then
textBrush = Brushes.White
Else
textBrush = Brushes.Black
End If
' draw a rectangle and fill it
Dim p As New Pen(aColor)
Dim br As New SolidBrush(aColor)
e.Graphics.DrawRectangle(p, rect)
e.Graphics.FillRectangle(br, rect)
' draw a border
rect.Inflate(1, 1)
e.Graphics.DrawRectangle(Pens.Black, rect)
' draw the Color name
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
e.Graphics.DrawString(aColor.Name, Me.Font, textBrush, rect.Width + 5, ((e.Bounds.Height - Me.Font.Height) \ 2) + e.Bounds.Top)
p.Dispose()
br.Dispose()
Catch ex As Exception
e.DrawBackground()
e.DrawFocusRectangle()
End Try
End Sub
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
Try
Dim aColorName As String
Me.BeginUpdate()
Items.Clear()
SelectedItem = Nothing
If myColors.Count = 0 Then
Dim names() As String = System.Enum.GetNames(GetType(System.Drawing.KnownColor))
For Each aColorName In names
If aColorName.StartsWith("Active") _
Or aColorName.StartsWith("Button") _
Or aColorName.StartsWith("Window") _
Or aColorName.StartsWith("Inactive") _
Or aColorName.StartsWith("HighlightText") _
Or aColorName.StartsWith("Control") _
Or aColorName.StartsWith("Scroll") _
Or aColorName.StartsWith("Menu") _
Or aColorName.StartsWith("Gradient") _
Or aColorName.StartsWith("App") _
Or aColorName.StartsWith("Desktop") _
Or aColorName.StartsWith("GrayText") _
Or aColorName.StartsWith("HotTrack") _
Or aColorName.StartsWith("Transparent") _
Or aColorName.StartsWith("Info") Then
Else
AddColor(Color.FromName(aColorName))
End If
Next
Else
Me.Items.AddRange(myColorsIndices.ToArray)
End If
Catch
Finally
Me.EndUpdate()
End Try
' Add any initialization after the InitializeComponent() call.
End Sub
Public Function AddColor(clr As Color) As Integer
myColors.Add(clr)
Dim idx As Integer = myColors.Count - 1
myColorsIndices.Add(idx)
Me.Items.Add(idx)
Return idx
End Function
''' <summary>
''' Returns a named color if one matches else it returns the passed color
''' </summary>
Public Function GetKnownColor(ByVal c As Color, Optional ByVal tolerance As Double = 0) As Color
For Each clr As Color In myColors
If ColorDistance(c, clr) <= tolerance Then
Return clr
End If
Next
Return c
End Function
''' <summary>
''' Returns index if one matches
''' </summary>
Public Function ContainsColor(ByVal c As Color) As Integer
Dim idx As Integer = 0
For Each clr As Color In myColors
If c.ToArgb = clr.ToArgb Then
Return idx
End If
idx += 1
Next
Return -1
End Function
Sub ColorCombo_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SelectedIndexChanged
If SelectedIndex >= 0 Then
mSelectedColor = myColors.Item(SelectedIndex)
End If
End Sub
Public Property SelectedColor() As Color
Get
'If mSelectedColor.Name = "Transparent" Then
' Return Color.Black
'End If
Return mSelectedColor
End Get
Set(ByVal value As Color)
Try
Dim smallestDist As Double = 255
Dim currentDist As Double = 0
Dim bestMatch As Integer = 0
Dim idx As Integer = -1
For Each c As Color In myColors
idx += 1
currentDist = ColorDistance(c, value)
If currentDist < smallestDist Then
smallestDist = currentDist
bestMatch = idx
End If
Next
If Me.Items.Count >= bestMatch Then
Me.SelectedIndex = bestMatch
End If
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Set
End Property
Private Function ColorDistance(ByRef clrA As Color, ByRef clrB As Color) As Double
Dim r As Long, g As Long, b As Long
r = CShort(clrA.R) - CShort(clrB.R)
g = CShort(clrA.G) - CShort(clrB.G)
b = CShort(clrA.B) - CShort(clrB.B)
Return Math.Sqrt(r * r + g * g + b * b)
End Function
End Class
Since you're adding the Color selection to the ComboBox.Items collection, the Form Designer serializes this this collection, adding all items to the Form.Designer.vb file. This also happens when you add Items a ComboBox using the Properties pane in the Designer: same effect.
You can instead set the DataSource of the ComboBox: it's faster and the object you add are not serialized. I also suggest not to add these values in the Control Constructor, but in the OnHandleCreated() override: the values are loaded only when the Control Handle is created, at run-time, so you don't load (not so useful) collections of items in the designer.
Since the handle can be recreated at run-time, more than once, there's a check for that (to avoid building the collection more than once).
Here, I'm using the ColorConverter's GetStandardValues() method to build a collection of known colors, excluding from the enumeration colors that have the IsSystemColor property set.
The collection is store in an array of Color objects, here named supportedColors.
You can also filter the collection returned by [Enum].GetValues() to get the same result, e.g.:
Dim colors As Color() = [Enum].GetValues(GetType(KnownColor)).OfType(Of KnownColor)().
Where(Function(kc) kc > 26 AndAlso kc < 168).
Select(function(kc) Color.FromKnownColor(kc)).ToArray()
SystemColors have Indexes < 27 and > 167 (I suggest not to rely on these values).
I've made a few changes to Custom Control:
When a Control is derived from an existing class, we don't subscribe to the events (e.g., DrawItem), we override the methods that rise the events (e.g., OnDrawItem()), then call base (MyBase) to rise the event (eventually, we can also not do that, if necessary). We are always one step ahead this way.
The drawing part needed some refactoring:
The Item's background actually was drawn 3 times
Disposable object should be declared with a Using statement, so we don't forget to dispose of them: very important when it comes to Graphics objects.
Replaced Graphics.DrawString() with TextRenderer.DrawText, to respect the original drawing.
Simplified the calculations: it's important to be as fast as possible here.
Thus also remove all Try/Catch blocks: costly and not really needed (don't use Try/Catch blocks when drawing, a few If conditions and some constraints - e.g., Math.Min(Math.Max()) - are better).
Also overridden OnMeasureItem() to change the height of the Items, set to Font.Height + 4 (pretty standard).
Other stuff you can see in the source code.
I've changed the SelectedColor custom property to be more reliable and to make it work with both OnSelectedIndexChanged() and OnSelectionChangeCommitted().
All Items represent a Color, so you can get the Color selected as, e.g.:
Private Sub ColorCombo1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ColorCombo1.SelectionChangeCommitted
SomeControl.BackColor = DirectCast(ColorCombo1.SelectedItem, Color)
' Or
SomeControl.BackColor = ColorCombo1.SelectedColor
End Sub
Modified the ComboBox Custom Control:
Remove what you have in Public Sub New and InitializeComponent(), it's not needed anymore.
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms
Public Class ColorCombo
Inherits ComboBox
Private mSelectedColor As Color = Color.Empty
Private supportedColors As Color() = Nothing
Public Sub New()
DropDownStyle = ComboBoxStyle.DropDownList
DrawMode = DrawMode.OwnerDrawVariable
FlatStyle = FlatStyle.Flat
FormattingEnabled = False
' Set these just to show that the background color is important here
ForeColor = Color.White
BackColor = Color.FromArgb(32, 32, 32)
End Sub
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
If DesignMode OrElse Me.Items.Count > 0 Then Return
supportedColors = New ColorConverter().GetStandardValues().OfType(Of Color)().
Where(Function(c) Not c.IsSystemColor).ToArray()
' Preserves a previous selection if any
Dim tmpCurrentColor = mSelectedColor
Me.DisplayMember = "Name"
Me.DataSource = supportedColors
If Not tmpCurrentColor.Equals(Color.Empty) Then
mSelectedColor = tmpCurrentColor
SelectedColor = mSelectedColor
End If
End Sub
Private flags As TextFormatFlags = TextFormatFlags.NoPadding Or TextFormatFlags.VerticalCenter
Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
e.DrawBackground()
If e.Index < 0 Then Return
Dim itemColor = supportedColors(e.Index)
Dim colorRect = New Rectangle(e.Bounds.X + 1, e.Bounds.Y + 1, e.Bounds.Height - 2, e.Bounds.Height - 2)
Using colorBrush As New SolidBrush(itemColor)
e.Graphics.FillRectangle(colorBrush, colorRect)
Dim textRect = New Rectangle(New Point(colorRect.Right + 6, e.Bounds.Y), e.Bounds.Size)
TextRenderer.DrawText(e.Graphics, itemColor.Name, e.Font, textRect, e.ForeColor, Color.Transparent, flags)
End Using
e.DrawFocusRectangle()
MyBase.OnDrawItem(e)
End Sub
Protected Overrides Sub OnMeasureItem(e As MeasureItemEventArgs)
e.ItemHeight = Font.Height + 4
MyBase.OnMeasureItem(e)
End Sub
Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
If SelectedIndex >= 0 Then mSelectedColor = supportedColors(SelectedIndex)
MyBase.OnSelectedIndexChanged(e)
End Sub
Protected Overrides Sub OnSelectionChangeCommitted(e As EventArgs)
mSelectedColor = supportedColors(SelectedIndex)
MyBase.OnSelectionChangeCommitted(e)
End Sub
Public Property SelectedColor As Color
Get
Return mSelectedColor
End Get
Set
mSelectedColor = Value
If Not IsHandleCreated Then Return
If mSelectedColor.IsKnownColor Then
SelectedItem = mSelectedColor
Else
If supportedColors Is Nothing Then Return
Dim smallestDist As Double = 255
Dim currentDist As Double = 0
Dim bestMatch As Integer = 0
Dim idx As Integer = -1
For Each c As Color In supportedColors
idx += 1
currentDist = ColorDistance(c, Value)
If currentDist < smallestDist Then
smallestDist = currentDist
bestMatch = idx
End If
Next
If supportedColors.Count >= bestMatch Then
mSelectedColor = supportedColors(bestMatch)
SelectedItem = mSelectedColor
End If
End If
End Set
End Property
Private Function ColorDistance(clrA As Color, clrB As Color) As Double
Dim r As Integer = CInt(clrA.R) - clrB.R
Dim g As Integer = CInt(clrA.G) - clrB.G
Dim b As Integer = CInt(clrA.B) - clrB.B
Return Math.Sqrt(r * r + g * g + b * b)
End Function
Public Function GetKnownColor(c As Color, Optional ByVal tolerance As Double = 0) As Color
For Each clr As Color In supportedColors
If ColorDistance(c, clr) <= tolerance Then Return clr
Next
Return c
End Function
Public Function ContainsColor(c As Color) As Integer
Dim idx As Integer = 0
For Each clr As Color In Me.Items
If c.ToArgb = clr.ToArgb Then Return idx
idx += 1
Next
Return -1
End Function
End Class
This is how it works:
I have been banging my head against the wall trying to figure out how to make numbers not repeat from a specific list that I have created. Can someone please help? Once a number is chosen I dont want it to be chosen again. Seems like numbers.Remove(number) isnt working
Private Sub GetMoneyRand()
If randomLog.Count = numberList.Count Then
MsgBox("No more number for random")
Return
End If
For i As Integer = 1 To 100
Dim rndDummy As Integer = CInt(numMax.Value * Rnd())
lblRandomNumber.Text = rndDummy
Threading.Thread.Sleep(30)
Application.DoEvents()
Next
Randomize()
Dim r As New Random
Dim numbers As New List(Of Integer)
numbers.AddRange(New Integer() {1, 16, 31, 46, 61, 10, 15, 14, 75, 33, 11, 19, 25, 44, 50, 72, 2, 44, 20, 30})
Dim number As Integer = numbers(r.Next(0, numbers.Count))
For x As Integer = 1 To 20
numbers.Remove(number)
Next
randomLog.Add(number)
lblRandomNumber.Text = number
numberList(number).BackColor = Color.LightBlue
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
To create a list with unique random numbers use the .Contains method of List(of T) before adding the new random to the list.
Private numbers As New List(Of Integer) From {1, 16, 31, 46, 61, 10, 15, 14, 75, 33, 11, 19, 25, 44, 50, 72, 2, 44, 20, 30}
Private r As New Random
Private Sub AddRandomsToList()
Dim i = r.Next(0, 21)
If numbers.Contains(i) Then
MessageBox.Show("Sorry that number is already in the list. Try Again.")
Else
numbers.Add(i)
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
AddRandomsToList()
End Sub
To remove duplicates from an existing list use the .Distinct extension method. It will return a new list of unique elements when you call .ToList
Private numbers As New List(Of Integer) From {1, 16, 1, 46, 61, 16, 15, 14, 61, 46, 11, 19, 25, 46, 50, 50, 2, 44, 20, 30}
Private r As New Random
Private Sub RemoveDuplicate()
Dim UniqueNumbers = numbers.Distinct().ToList
For Each i In UniqueNumbers
Debug.Print(i.ToString)
Next
End Sub
You should be using a stack or a queue. They both remove items as they are used.
Private numbers As Integer() = {1, 16, 31, 46, 61, 10, 15, 14, 75, 33, 11, 19, 25, 44, 50, 72, 2, 44, 20, 30}
Private rng As New Random
Private Sub OutputNumbersInRandomOrder()
Dim randomisedNumbers As New Queue(Of Integer)(numbers.OrderBy(Function(n) rng.NextDouble()))
Do Until randomisedNumbers.Count = 0
Dim number = randomisedNumbers.Dequeue()
Console.WriteLine(number)
Loop
End Sub
Each time you call Dequeue, the first number is removed from the list and returned. You can do this as many times as you like, creating a new queue each time the previous one is empty, e.g.
Private numbers As Integer() = {1, 16, 31, 46, 61, 10, 15, 14, 75, 33, 11, 19, 25, 44, 50, 72, 2, 44, 20, 30}
Private randomisedNumbers As Queue(Of Integer)
Private rng As New Random
Private Function GetRandomNumber() As Integer
If randomisedNumbers Is Nothing OrElse randomisedNumbers.Count = 0 Then
randomisedNumbers = New Queue(Of Integer)(numbers.OrderBy(Function(n) rng.NextDouble()))
End If
Return randomisedNumbers.Dequeue()
End Function
You can do the same thing with a Stack(Of Integer) and calling Pop. The only difference is that a stack takes items from the other end - LIFO instead of FIFO. As the items are randomised and all added at the same time, there's really no difference in the outcome, especially given that calling OrderByDescending would reverse the outcomes of the two types anyway. To illustrate:
Dim numbers = {1, 2, 3, 4, 5}
Dim q1 As New Queue(Of Integer)(numbers)
Dim s1 As New Stack(Of Integer)(numbers)
Console.WriteLine("q1:")
Do Until q1.Count = 0
Console.WriteLine(q1.Dequeue())
Loop
Console.WriteLine("s1:")
Do Until s1.Count = 0
Console.WriteLine(s1.Pop())
Loop
Array.Reverse(numbers)
Dim q2 As New Queue(Of Integer)(numbers)
Dim s2 As New Stack(Of Integer)(numbers)
Console.WriteLine("q2:")
Do Until q2.Count = 0
Console.WriteLine(q2.Dequeue())
Loop
Console.WriteLine("s2:")
Do Until s2.Count = 0
Console.WriteLine(s2.Pop())
Loop
Output:
q1:
1
2
3
4
5
s1:
5
4
3
2
1
q2:
5
4
3
2
1
s2:
1
2
3
4
5
I'm making a fun little game just because and it involves customizable computer parts. I made a class for the CPU and included the needed variables in order to construct a CPU object. I have a function that takes the constructed objects (such as Intel i5-4770) and assigns values to them. I have a little shop where you can purchase new hardware, I'm trying to set a label to the name of the object so it titles what your buying. Example: Label1.text = i5_4770.name but i get the following error:
Additional information: Object reference not set to an instance of an object.
It cant be NULL because i have given it a value.
here's my code:
Public Class Cracking4CashMain
'Instantiate Objects
Public Celeron_E3400 As CPU
Public Pentium_D830 As CPU
Public Pentium4 As CPU
Public AMD_A65400 As CPU
Public Celeron_G1840 As CPU
Public AMD_A66400 As CPU
Public Pentium_G3258 As CPU
Public AMD_FX4300 As CPU
Public Pentium_G3450 As CPU
Public AMD_A106800 As CPU
Public i5_4430 As CPU
Public i7_4770 As CPU
Public i7_5930k As CPU
Public i7_5960x As CPU
Private Sub Cracking4CashMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Momsbasement.Visible = True
MomsRoom.Visible = False
YourHouse.Visible = False
officeBuilding.Visible = False
ovalOffice.Visible = False
'initializeObjects()
backgroundCheck()
shopInfo()
End Sub
Private Sub initializeObjects()
Celeron_E3400.setValues(2.6, 1, "Celeron E3400 Processor", 1, 0, 1, 0, 16.99)
Pentium_D830.setValues(3.0, 2, "Intel Pentium D 830 Smithfield Dual Core", 1, 0, 2, 0, 17.99)
Pentium4.setValues(2.93, 1, "Intel Pentium 4 521 Prescott", 1, 0, 1, 0, 19.99)
AMD_A65400.setValues(3.6, 2, "AMD A6-5400k Trinity Dual-Core", 1, 0, 1, 0, 50.0)
Celeron_G1840.setValues(2.8, 2, "Intel Celeron G1840 Haswell Dual-Core", 0.256, 2, 2, 1, 46.99)
AMD_A66400.setValues(3.9, 2, "AMD A6-6400k Richland Dual-Core", 1, 0, 1, 0, 62.99)
Pentium_G3258.setValues(3.2, 2, "Intel Pentium G3258 Haswell Dual-Core", 0, 3, 0, 3, 69.99)
AMD_FX4300.setValues(3.8, 4, "AMD FX-4300 Vishera Quad-Core", 2, 4, 2, 1, 99.99)
Pentium_G3450.setValues(3.4, 2, "Intel Pentium G3450 Haswell Dual Core", 0.256, 3, 2, 1, 86.99)
AMD_A106800.setValues(4.1, 4, "AMD A10-6800k Richland", 4, 0, 1, 0, 129.99)
i5_4430.setValues(3.0, 4, "Intel Core i5-4430 Haswell Quad-Core", 0, 6, 0, 1, 184.99)
i7_4770.setValues(3.4, 4, "Intel Core i7-4770 Haswell Quad-Core", 0, 8, 0, 1, 309.99)
i7_5930k.setValues(3.5, 6, "Intel Core i7-5930k Haswell-E 6-Core", 0.256, 15, 6, 1, 564.99)
i7_5960x.setValues(3.0, 8, "Intel Core i7-5960x Haswell-E 8-Core", 0.256, 20, 8, 1, 1049.99)
End Sub
Private Sub backgroundCheck()
If (Momsbasement.Visible = True) Then
monitor.Parent = Momsbasement
PictureBox1.Parent = Momsbasement
ElseIf (MomsRoom.Visible = True) Then
monitor.Parent = MomsRoom
PictureBox1.Parent = MomsRoom
ElseIf (YourHouse.Visible = True) Then
monitor.Parent = YourHouse
PictureBox1.Parent = YourHouse
ElseIf (officeBuilding.Visible = True) Then
monitor.Parent = officeBuilding
PictureBox1.Parent = officeBuilding
ElseIf (ovalOffice.Visible = True) Then
monitor.Parent = ovalOffice
PictureBox1.Parent = ovalOffice
End If
End Sub
Private Sub Cracking4CashMain_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
Cracking4CashLogin.Close()
End Sub
Private Sub monitor_Click(sender As Object, e As EventArgs) Handles monitor.Click
End Sub
Private Sub shopInfo()
Label1.Text = i5_4430.name
End Sub
End Class
Class:
Public Class CPU
Public price As Double
Public GHz As Double
Public cores As Integer
Public L2Cache As Double
Public L3Cache As Double
Public numL2 As Integer
Public numL3 As Integer
Public name As String
Public Sub setValues(ByVal GH As Double, ByVal core As Integer, ByVal n As String, ByVal l2 As Double, ByVal l3 As Double, ByVal nl2 As Integer, ByVal nl3 As Integer, ByVal p As Double)
GHz = GH
cores = core
L2Cache = l2
L3Cache = l3
numL2 = nl2
numL3 = nl3
price = p
name = n
End Sub
End Class
The problem is that you are not creating instances of your CPU class, you need New to do that. Here is one way to do that. In your CPU class, change the name of the setValues method to New
Public Sub New(GH As Double, core As Integer, n As String, l2 As Double, _
l3 As Double, nl2 As Integer, nl3 As Integer, p As Double)
'The rest of your setValues code goes here
End Sub
Now you can change your initializeObjects method to create new CPU objects and set the values at the same time.
Private Sub initializeObjects()
Celeron_E3400 = New CPU(2.6, 1, "Celeron E3400 Processor", 1, 0, 1, 0, 16.99)
'etc.
End Sub