[RESOLVED] Problem with Color.FromName
Hi,
I've been trying to use...
Code:
Dim myColour As Color = Color.FromName(TextBox1.Text)
...to give a user a choice of colour for Form background or, for example, Pen color.
I've run into a problem because 'Color.FromName' doesn't automatically detect an unknown colour or misspelling, if the text is unknown the code just returns Black.
Using...
Code:
myColour = Color.FromName(TextBox2.Text)
Me.BackColor = myColour
...however does produce a detectable error, and it's what I've been using.
In a previous thread jmcilhinney made this suggestion:
Quote:
Originally Posted by
jmcilhinney
vb.net Code:
Dim names = {"Red", "Rid"}
For Each s In names
If [Enum].IsDefined(GetType(KnownColor), s) Then
Console.WriteLine($"There is a known colour named '{s}'.")
Else
Console.WriteLine($"There is NOT a known colour named '{s}'.")
End If
Next
I can see how that would work but I don't really want to sit and add all 140 odd 'Known' colours to the string array 'names', not least because I can't type and produce far too many typo's at the best of times.
I've been trying, without success, to find where to access a 'look-up' list to compare the text with the known colours. I'm sure there must be a list somewhere in Visual Studio because a selection is presented each time a colour is selected in design.
Poppa
Re: Problem with Color.FromName
Quote:
I've been trying, without success, to find where to access a 'look-up' list to compare the text with the known colours.
Um, the KnownColor enumeration that I just demonstrated for you. :rolleyes: You don't have to add anything to any array. You seem to have missed the principle the example was demonstrating. The line that matters there is this one:
vb.net Code:
If [Enum].IsDefined(GetType(KnownColor), s) Then
where s is the String value you want to test. In your case, that String value is TextBox1.Text so you substitute that for s, e.g.
vb.net Code:
Dim colourName = TextBox1.Text
If [Enum].IsDefined(GetType(KnownColor), colourName) Then
Dim colour = Color.FromName(colourName)
'Use colour here.
Else
'There is no such colour.
End If
Re: Problem with Color.FromName
To elaborate, Enum.IsDefined in this case returns a Boolean value showing whether a value's name exists in the KnownColor enumeration.
Behind the scenes, it is iterating over every 167 values and checking whether or not the value you passed is one of them.
Here is the relevant documentation: https://docs.microsoft.com/en-us/dot...enum.isdefined
Re: Problem with Color.FromName
Quote:
Originally Posted by
jmcilhinney
Um, the KnownColor enumeration that I just demonstrated for you. :rolleyes: You don't have to add anything to any array. You seem to have missed the principle the example was demonstrating.
Sorry John, still got problem. You're right, I did miss what you meant.
So: this is how I interpreted your post:
vb.NET Code:
Private Sub Colours()
Dim colour(2) As Color
colour(0) = Color.FromName(TextBox1.Text)
colour(1) = Color.FromName(TextBox2.Text)
For Each s In colour
If [Enum].IsDefined(GetType(KnownColor), s) Then
'Color ok
Else
StartUp()
Label3.Show()
End If
Next
pen1 = New Pen(colour(1), 1)
Me.BackColor = colour(0)
PictureBox1.BackColor = colour(0)
PictureBox1.Show()
End Sub
When I run this code I get this error at Line 7. (For reference the Line 90 as referenced in the copy below is Line 9 in the shown snippet.)
Quote:
System.InvalidOperationException
HResult=0x80131509
Message=Unknown enum type.
Source=mscorlib
StackTrace:
at System.RuntimeType.IsEnumDefined(Object value)
at System.Enum.IsDefined(Type enumType, Object value)
at Polly_Draw.Form1.Colours() in D:\~VB Trials\Polly Draw\Form1.vb:line 90
at Polly_Draw.Form1.Button2_Click() in D:\~VB Trials\Polly Draw\Form1.vb:line 68
at Polly_Draw.Form1._Lambda$__R31-3(Object a0, EventArgs a1)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at Polly_Draw.My.MyApplication.Main(String[] Args) in :line 81
This exception was originally thrown at this call stack:
[External Code]
Polly_Draw.Form1.Colours() in Form1.vb
Polly_Draw.Form1.Button2_Click() in Form1.vb
[External Code]
Which probably means that I've got it wrong again.
Poppa
PS.
Meant to say... This was with two valid colours, 'Red and Blue'.
Pop.
1 Attachment(s)
Re: Problem with Color.FromName
Do you have System.Drawing imported? I'm able to test JMcIlhinney's solution without any issues:
Code:
Imports System
Imports System.Drawing
Public Module Module1
Public Sub Main()
Dim input As String = Console.ReadLine()
If [Enum].IsDefined(GetType(KnownColor), input) Then
Console.WriteLine("{0} is a known color.", input)
Else
Console.WriteLine("{0} is not a known color.", input)
End If
End Sub
End Module
Fiddle: Live Demo
Screenshot:
Attachment 178854
Re: Problem with Color.FromName
It would help if you had Strict and Explicit on, something you've been told numerous times.
An experiment / hint
Code:
Dim colour(2) As Color
colour(0) = Color.FromName("Blue")
colour(1) = Color.FromName("red")
For Each s As String In From c In colour Select c.Name
If [Enum].IsDefined(GetType(KnownColor), s) Then
'Color ok
Stop
Else
Stop
End If
Next
Re: Problem with Color.FromName
Quote:
Originally Posted by
dbasnett
It would help if you had Strict and Explicit on, something you've been told numerous times.
I thought I had both of those 'On' by default but can't find where to check.
Poppa
Re: Problem with Color.FromName
You’re doing it wrong...
Colours(0) = Color.FroName(TextBox1.Text)
You said yourself in an earlier post that that doesn’t work, so why would it work now?
You’re supposed to be testing if a STRING color name exists in the knowncolors enum, before setting any colors.fromname
Re: Problem with Color.FromName
Update.
I realised I had a basic error, I was checking a Color, not a String, so I've changed things a bit.
vb.NET Code:
Private Sub Colours()
Dim colour(2) As Color, chk(2) As String
' Ensure the input colours start with an upper case letter.
chk(0) = TextBox1.Text
chk(1) = TextBox2.Text
chk(0) = chk(0).Substring(0, 1).ToUpper & chk(0).Substring(1)
chk(1) = chk(1).Substring(0, 1).ToUpper & chk(1).Substring(1)
For i = 0 To 1
If [Enum].IsDefined(GetType(KnownColor), chk(i)) Then
colour(i) = Color.FromName(chk(i))
Else
StartUp()
Label3.Show()
Exit Sub
End If
Next
pen1 = New Pen(colour(1), 1)
Me.BackColor = colour(0)
PictureBox1.BackColor = colour(0)
PictureBox1.Show()
End Sub
Well at least my first attempt didn't throw up any errors but it failed to recognise 'red' as a colour.
Then I tried 'Red' and that worked correctly. So I added Lines 4 to 8.
Thanks guys
Poppa
Re: [RESOLVED] Problem with Color.FromName
Why declare colours(2) and chk(2)???
You’re only using 2 elements in both. You know arrays are zero based, but you need to declare arrays with the Upperbound and not the Length...
I.e. colours(1), chk(1)
Edit: That’s how to declare and dimension an array in VB. In C languages, you do use the array Length when declaring and dimensioning...
Re: [RESOLVED] Problem with Color.FromName
If TextBox1.Text = ‘red’ this is how to change it to ‘Red’
If it already is ‘Red’ and not ‘red’, no harm done...
Code:
chk(0) = StrConv(TextBox1.Text, vbProperCase)
chk(1) = StrConv(TextBox2.Text, vbProperCase)
Re: [RESOLVED] Problem with Color.FromName
As you're using TextBoxes for inputting color names, I'd recommend using AutoComplete to avoid many errors. Here's an example...
Code:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim source As New AutoCompleteStringCollection
source.AddRange([Enum].GetNames(GetType(KnownColor)))
TextBox1.AutoCompleteCustomSource = source
TextBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend
TextBox1.AutoCompleteSource = AutoCompleteSource.CustomSource
TextBox2.AutoCompleteCustomSource = source
TextBox2.AutoCompleteMode = AutoCompleteMode.SuggestAppend
TextBox2.AutoCompleteSource = AutoCompleteSource.CustomSource
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim c1 As String = TextBox1.Text.ToLower
Dim c2 As String = TextBox2.Text.ToLower
Dim knownColorNames() As String = [Enum].GetNames(GetType(KnownColor))
Dim knownColorNamesToLower() As String = [Enum].GetNames(GetType(KnownColor)).Select(Function(n) n.ToLower).ToArray
Dim i1 As Integer = Array.IndexOf(knownColorNamesToLower, c1)
Dim i2 As Integer = Array.IndexOf(knownColorNamesToLower, c2)
If i1 > -1 AndAlso i2 > -1 Then
c1 = knownColorNames(i1)
c2 = knownColorNames(i2)
TextBox1.ForeColor = Color.FromName(c1)
TextBox1.BackColor = Color.FromName(c2)
TextBox2.ForeColor = Color.FromName(c2)
TextBox2.BackColor = Color.FromName(c1)
End If
End Sub
End Class
Re: [RESOLVED] Problem with Color.FromName
Keep in mind that the KnownColor enumeration contains values like Red, LightBlue and HighlightText. Here's a method that will match those values regardless of case while also excluding the system values:
vb.net Code:
Private Function IsColorName(name As String) As Boolean
Dim knownColorNames = [Enum].GetNames(GetType(KnownColor))
'Check for known colours, e.g. Red, LightBlue, Control.
If Not knownColorNames.Any(Function(kcn) String.Equals(kcn, name, StringComparison.OrdinalIgnoreCase)) Then
'The input does not match a known colour.
Return False
End If
Dim systemColorNames = GetType(SystemColors).GetProperties(BindingFlags.Public Or BindingFlags.Static).Select(Function(pi) pi.Name)
'Check for system colours, e.g. ButtonFace, Control, HighlightText.
If systemColorNames.Any(Function(scn) String.Equals(scn, name, StringComparison.OrdinalIgnoreCase)) Then
'The input matches a system colour.
Return False
End If
'The specified colour is known but is not part of the system.
Return True
End Function
Sample usage:
vb.net Code:
Dim colourNames = {"Red", "blue", "Groan", "control", "Window"}
For Each colourName As String In colourNames
Console.WriteLine($"{colourName}: {IsColorName(colourName)}")
Next
You may also want to allow people to enter values like "light blue". A simple option would be to just remove the spaces from the input before comparing:
vb.net Code:
Private Function IsColorName(name As String) As Boolean
name = name.Replace(" ", String.Empty)
Dim knownColorNames = [Enum].GetNames(GetType(KnownColor))
'Check for known colours, e.g. Red, LightBlue, Control.
If Not knownColorNames.Any(Function(kcn) String.Equals(kcn, name, StringComparison.OrdinalIgnoreCase)) Then
'The input does not match a known colour.
Return False
End If
Dim systemColorNames = GetType(SystemColors).GetProperties(BindingFlags.Public Or BindingFlags.Static).Select(Function(pi) pi.Name)
'Check for system colours, e.g. ButtonFace, Control, HighlightText.
If systemColorNames.Any(Function(scn) String.Equals(scn, name, StringComparison.OrdinalIgnoreCase)) Then
'The input matches a system colour.
Return False
End If
'The specified colour is known but is not part of the system.
Return True
End Function
The issue with that is that it will match "li ghtbl ue" as well as "light blue". The more rigorous option is to insert single spaces before upper-case letters within the field and property names:
vb.net Code:
Private Const SPACE As String = " "
Private Function IsColorName(name As String) As Boolean
Dim knownColorNames As IEnumerable(Of String) = [Enum].GetNames(GetType(KnownColor))
If name.Contains(SPACE) Then
'The input contains at least one space so insert spaces into the known colour names for matching.
knownColorNames = knownColorNames.Select(Function(kcn) InsertSpacesBetweenWords(kcn))
End If
'Check for known colours, e.g. Red, LightBlue, Control.
If Not knownColorNames.Any(Function(kcn) String.Equals(kcn, name, StringComparison.OrdinalIgnoreCase)) Then
'The input does not match a known colour.
Return False
End If
Dim systemColorNames = GetType(SystemColors).GetProperties(BindingFlags.Public Or BindingFlags.Static).Select(Function(pi) pi.Name)
If name.Contains(SPACE) Then
'The input contains at least one space so insert spaces into the system colour names for matching.
systemColorNames = systemColorNames.Select(Function(scn) InsertSpacesBetweenWords(scn))
End If
'Check for system colours, e.g. ButtonFace, Control, HighlightText.
If systemColorNames.Any(Function(scn) String.Equals(scn, name, StringComparison.OrdinalIgnoreCase)) Then
'The input matches a system colour.
Return False
End If
'The specified colour is known but is not part of the system.
Return True
End Function
Private Function InsertSpacesBetweenWords(text As String) As String
For i = text.Length - 1 To 1 Step -1
If Char.IsUpper(text(i)) Then
text = text.Insert(i, SPACE)
End If
Next
Return text
End Function
Sample usage:
vb.net Code:
Dim colourNames = {"Red", "blue", "Groan", "control", "Window", "light blue", "li ghtbl ue", "highlight text", "hig hlightte xt"}
For Each colourName As String In colourNames
Console.WriteLine($"{colourName}: {IsColorName(colourName)}")
Next
1 Attachment(s)
Re: [RESOLVED] Problem with Color.FromName
If you wanted to give a color preview for your color selection process, you could use an extended combobox...
Code:
Public Class colorComboBox
Inherits ComboBox
Public Sub New()
Me.DropDownStyle = ComboBoxStyle.DropDownList
Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawVariable
MyBase.Items.Clear()
MyBase.Items.AddRange([Enum].GetNames(GetType(KnownColor)).OrderBy(Function(n) Color.FromName(n).GetHue).ToArray)
End Sub
Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
Dim c As Color = Color.Empty
If e.Index <> -1 Then
c = Color.FromName(MyBase.Items(e.Index).ToString)
End If
If (e.State And DrawItemState.ComboBoxEdit) = DrawItemState.ComboBoxEdit Then
' Draw the contents of the edit area of the combo box.
e.Graphics.FillRectangle(New SolidBrush(c), New Rectangle(4, e.Bounds.Top + 1, 16, 12))
e.Graphics.DrawRectangle(Pens.Black, New Rectangle(4, e.Bounds.Top + 1, 16, 12))
e.Graphics.DrawString(If(c.Name = "0", "Empty", c.Name), Me.Font, Brushes.Black, 22, e.Bounds.Top + 1)
Else
' Draw the contents of an item in the drop down list.
e.Graphics.FillRectangle(New SolidBrush(c), New Rectangle(2, e.Bounds.Top + 2, 16, 12))
e.Graphics.DrawRectangle(Pens.Black, New Rectangle(2, e.Bounds.Top + 2, 16, 12))
e.Graphics.DrawString(c.Name, Me.Font, Brushes.Black, 20, e.Bounds.Top + 2)
' Draw the focus rectangle.
e.DrawFocusRectangle()
End If
MyBase.OnDrawItem(e)
End Sub
Public Function getSelectedColor() As Color
If MyBase.SelectedIndex > -1 Then
Return Color.FromName(MyBase.Text)
Else
Return Color.Transparent
End If
End Function
End Class
Attachment 178870
Re: [RESOLVED] Problem with Color.FromName
Quote:
Originally Posted by
.paul.
Why declare colours(2) and chk(2)???
You’re only using 2 elements in both. You know arrays are zero based, but you need to declare arrays with the Upperbound and not the Length...
I.e. colours(1), chk(1)
Oh !
I've always used length, maybe from my original BASIC language from the 1970's.
Poppa
Re: [RESOLVED] Problem with Color.FromName
Quote:
Originally Posted by
Poppa Mintin
Oh !
I've always used length, maybe from my original BASIC language from the 1970's.
Poppa
Color choice in your 70's BASIC would be easy. These days choosing knowncolors is more complicated. I'd still use my extended combobox. It avoids user error. Allowing text entry in a textbox for color choosing isn't an efficient method...
Re: [RESOLVED] Problem with Color.FromName
Quote:
Originally Posted by
.paul.
If you wanted to give a color preview for your color selection process, you could use an extended combobox...
That's a nice tips, thanks (need to spread some rep before being able to give some to you).
I wonder if I can replace the colored rectangle with an image...?? I will try that as a good exercise.
Re: [RESOLVED] Problem with Color.FromName
Quote:
Originally Posted by
.paul.
If you wanted to give a color preview for your color selection process, you could use an extended combobox...
Code:
Public Class colorComboBox
Inherits ComboBox
Public Sub New()
Me.DropDownStyle = ComboBoxStyle.DropDownList
Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawVariable
MyBase.Items.Clear()
MyBase.Items.AddRange([Enum].GetNames(GetType(KnownColor)).OrderBy(Function(n) Color.FromName(n).GetHue).ToArray)
End Sub
Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
Dim c As Color = Color.Empty
If e.Index <> -1 Then
c = Color.FromName(MyBase.Items(e.Index).ToString)
End If
If (e.State And DrawItemState.ComboBoxEdit) = DrawItemState.ComboBoxEdit Then
' Draw the contents of the edit area of the combo box.
e.Graphics.FillRectangle(New SolidBrush(c), New Rectangle(4, e.Bounds.Top + 1, 16, 12))
e.Graphics.DrawRectangle(Pens.Black, New Rectangle(4, e.Bounds.Top + 1, 16, 12))
e.Graphics.DrawString(If(c.Name = "0", "Empty", c.Name), Me.Font, Brushes.Black, 22, e.Bounds.Top + 1)
Else
' Draw the contents of an item in the drop down list.
e.Graphics.FillRectangle(New SolidBrush(c), New Rectangle(2, e.Bounds.Top + 2, 16, 12))
e.Graphics.DrawRectangle(Pens.Black, New Rectangle(2, e.Bounds.Top + 2, 16, 12))
e.Graphics.DrawString(c.Name, Me.Font, Brushes.Black, 20, e.Bounds.Top + 2)
' Draw the focus rectangle.
e.DrawFocusRectangle()
End If
MyBase.OnDrawItem(e)
End Sub
Public Function getSelectedColor() As Color
If MyBase.SelectedIndex > -1 Then
Return Color.FromName(MyBase.Text)
Else
Return Color.Transparent
End If
End Function
End Class
Attachment 178870
nice one
Re: [RESOLVED] Problem with Color.FromName
Quote:
Originally Posted by
Delaney
I wonder if I can replace the colored rectangle with an image...?? I will try that as a good exercise.
You can draw anything you choose in the DrawItem event, but it helps to have something that relates to the item, as in this case...