如何创建一个表示颜色的随机十六进制字符串?

49

我正在生成一些需要用十六进制字符串表示颜色的图表。

例如:

<dataseries name="ford" color="FF00FF" />

我正在动态创建这些数据系列,因此我希望随机生成每个数据系列的十六进制代码。

那么,最好的方法是什么?


我刚刚注意到我的示例没有出现。我猜那是因为它是一个XML字符串...哦,没关系,因为答案很好用。 - rahkim
1
@rahkim - 更新了问题以修复错误,并添加了更有意义的标题。 - John Rasch
6个回答

156

最简单的方法是使用 String.Format 函数,并使用十六进制格式作为参数。

var random = new Random();
var color = String.Format("#{0:X6}", random.Next(0x1000000)); // = "#A197B9"

2
请纠正我,但是使用该代码,您永远不会生成0xFFFFFF的值,因为您传递给Next方法的整数是非包含性上限。因此,您需要使用random.Next(0x1000000)才能返回0xFFFFFF。 - Chris Dunaway
1
有一件有趣的事情;如果我在设置颜色时设置断点,每次通过我的循环都会产生不同的颜色。如果我让它自己运行,asp页面会给我所有相同的颜色。 - rahkim
1
@rahkim:这是因为生成器的种子是时钟时间。在循环中,每个随机数生成得非常快,以至于它们都使用相同的种子。当你打破循环时,足够的时间过去了,可以使用新的种子。尝试在整个循环中重复使用随机对象。 - James
太好了!我需要一个无井号的随机十六进制生成器,现在一切都很完美。 - vmex151
15
在 C# 6 中使用字符串插值,可以这样写:var color = $"#{random.Next(0x1000000):X6}";其中,变量 color 将得到一个随机的六位十六进制颜色值。 - Iain M Norman
显示剩余5条评论

21

Samuel的回答是实现这个功能的最佳方法,只需确保如果你在循环内生成颜色,不要每次都实例化一个新的Random对象,因为new Random()会使用系统时钟来种子生成器。你的循环将运行得比时钟快,因此你会一遍又一遍地生成几个相同的颜色,因为random被种子化了相同的值。

代码应该类似于:

int numColors = 10;
var colors = new List<string>();
var random = new Random(); // Make sure this is out of the loop!
for (int i = 0; i < numColors; i++) 
{
    colors.Add(String.Format("#{0:X6}", random.Next(0x1000000)));
}

替代:

int numColors = 10;
var colors = new List<string>();
for (int i = 0; i < numColors; i++) 
{
    var random = new Random(); // Don't put this here!
    colors.Add(String.Format("#{0:X6}", random.Next(0x1000000)));
}

1
这就解释了为什么在使用断点时,rahkim会得到随机颜色。哈哈 - Samuel
这甚至没有在我的脑海中出现过。 你把颜色添加到列表中是有原因的吗?只是好的实践,还是我漏掉了什么? - rahkim
这只是一个例子,因为我不确定他是如何分配它们的。 - John Rasch

19

在我看来,纯随机的颜色可能不是首选,因为你需要人眼可以区分的颜色。

那么预设一些颜色并随机选择它们呢?

也许你可以在一些开源绘图库中找到更好的答案。


这可能是首选的方法,但也许 OP 有其他原因需要完全随机的颜色。 - Samuel
我考虑到这一点,因为有些颜色可能会混合在一起。但我不确定要预设多少个,因为我可能会有很多系列。 - rahkim
混合预设和随机可能会有所帮助。仔细预设约10种好看的颜色。如果需要更多,则采用随机方式。一般来说,对于过于色彩丰富的图表,未经训练的眼睛很容易感到困惑,因此实际使用哪些颜色并不是非常重要。 - Canton

14
一个生成漂亮颜色组的好方法是使用固定的饱和度和亮度,然后变化色调。
  1. 将饱和度和亮度设置为你喜欢的值,比如50%的饱和度和90%的亮度。
  2. 现在将360度的色调分成你想要的不同颜色数量的间隔。
  3. 使用该间隔来选择HSV颜色,并使用固定的S和V。
这样就可以得到一组漂亮的颜色,它们看起来都来自同一个“集合”——都是粉彩色、浓烈色或米白色等等。如果你有Color.FromHSV()函数,那么这个方法很容易实现。
但是,当你需要太多的颜色时,这种方法可能无法工作,因为颜色会变得难以区分。不过,无论如何,这都可能是一个问题。
伪代码如下:
Sat = 0.5 * 255 //assuming we want range 0-255...
Brightness = 0.9 * 255
NumberOfColours = 7
HueSeparation = 360 / 7
Colors = []
for (i = 0 ; i< NumberOfColours; i++)
     Colors.Add(Color.FromHSV(HueSeparation * i, Sat, Brightness)
或者
n = 7
Colors = [Color.FromHSV(x*360/n, 128, 230) for x in range(n)]

(我确实喜欢列表推导式...)


5
Random rand = new Random(); // specify a seed
int r = rand.Next(0x1000000); 
Console.WriteLine("#{0:X6}", r);

1
这个无法处理低值。0x00FFFF 转换成 #FFFF,这与 #00FFFF 不同。 - Samuel

4
我注意到你(Rahkim)在Greg的帖子上评论说,你希望能将他的想法(保持饱和度和值恒定,只变化色调...这是个好主意)转化为代码。你可以!或者说,已经有人为你做好了!
我在Splinter网站上找到了一篇博客文章介绍如何使用C#将HSV转换为RGB颜色,当然还有更多其他的方法。通过这种方式,你可能会得到一组更美丽的颜色,而不是完全随机选择它们。
此外,这种方法使得获取一组漂亮的颜色变得简单...因为色调从0到359,你可以像下面这样设置你的色调:
Hue = (PreviousHue + 50) % 360;

我选择了50,因为它无法被360整除,所以如果你超过360,不会立即开始重复色调。你需要根据你期望的颜色数量来玩弄这个值,以获得理想的分离效果。
这样你就不必担心代码随机选择了两种非常接近的颜色,而还有很多未使用的“色相”空间。

我喜欢这个。它给了我一些灵活性。 - rahkim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接