简体   繁体   中英

How to create an arbitrary System.Drawing.Color out of a string?

I have a set of unique strings, and I wish to show them with a color. The strings repeat every here and there so I need the coloring to be consistent, not random.

One approach would be to randomize the color and save it in Dictionary or something like that so I can use the same color again.

Another approach would be to come up with a simple algorithm/logic that somehow turns a string into a System.Drawing.Color .

However, I'd like to keep it to a set of predefined colors, so that I don't end up having not-so-great colors. Let's call this List<Color> allowedColors .

I tried Convert.ToByte() and figured I would use the byte for the R, G and B components of Color , but that did not work because the conversion does not work that way.

A string is just a simple string String foo = "bar"; . The relationship between the color and the string does not matter as long as it is consistent, ie, every time the program is ran it should equal to the same color and the colors should generally be different for each string (and yes there will be duplicate colors because there are more strings than colors and it's not a one-to-one mapping).

Those strings come from a source I do not control. They are unique, but vary. Each time the program is started and if the same string comes up, it should be the same color.

So, I think I'm looking for some sort of string to byte transformation, which when overlaps the byte range starts over, and finally the byte is mapped to RGB and sent to Color.FromArgb() .

If you have a set of known unique strings and a set of predefined colors, just use a dictionary:

Dictionary<string, Color> StringColors = new Dictionary<string, Color>()
{
    {"string1", Colors.Red},
    {"string2", Colors.Green},
    {"string3", Colors.Blue},
};

And then it's as simple as:

string theString = "string2";
var MyColor = StringColors[theString];

I think the simplest approach is simply to assign each string the next available color in your AvailableColors list, and save that mapping, the first time you make it, to a dictionary. This can be saved to disk using serialization and and reused in later executions. Here's some (updated) sample code:

public Color[] AvailableColors = new Color[] { Colors.Red, Colors.Blue, Colors.Green};         
private int _nextColorIndex = 0;
public Dictionary<string,Color> ColorMappings = new Dictionary<string,Color>();
public Color GetNextColor () 
{
    Color nextColor = AvailableColors[_nextColorIndex];
    _nextColorIndex++;
    if (_nextColorIndex == AvailableColors.Length)
        _nextColorIndex = 0; // Restart colors and reuse.
    return nextColor;
}

public void AssignColor (string myString)
{
    ColorMappings.Add(myString, GetNextColor());
}

You'll have to add appropriate handling for when you run out of strings, of course, and maybe concurrency locks around GetNextColor if you're doing it multithreaded, but it's a start.

You can make a list of colors using the FramArgb method:

var allowedColors = new List<Color>();
allowedColors.Add(Color.FromArgb(255, 0, 0));

Or you can manage a mapping from strings to colors with a dictionary:

var colorMap = new Dictionary<string, Color>();
colorMap.Add("red", Color.FromArgb(255, 0, 0));

In many cases, this would be considered an over engineered solution, but at any rate it's an example of encapsulation in C#:

class AppString
{
  private string text;
  private Color color;

  public AppString(string text, Color color)
  {
    this.text = text;
    if(allowedColors.Contains(color))
    {
      this.color = color;
    }
    else
    {
      throw new Exception("invalid color");
    }
  }

  // This lets you use an AppString most places where you used a regular string.
  public static implicit operator string(AppString appString) 
  { 
        return appString.text;
  }

  // This lets you use an AppString most places where you used a Color.
  public static implicit operator Color(AppString appString) 
  { 
        return appString.color;
  }

  // OR if you don't prefer overloading the implicit cast, a standard pattern
  // is to use a Value property.
  public string Value { get { return this.text; } }
  public Color Color { get { return this.color; } }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM