65.9K
CodeProject 正在变化。 阅读更多。
Home

一个近乎自组织的标签云

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (14投票s)

2010年1月4日

CPOL

11分钟阅读

viewsIcon

37825

downloadIcon

870

在标签云中显示和使用项目进行数据输入。

图 1:标签云控件

引言

我经常在网站上看到标签云,但我需要在 Windows 窗体中使用它们。因此,我开发了一个可以轻松添加到窗体中的控件。它将帮助您根据重要性可视化文本或集合中的字符串。除此之外,您还可以单击项目以将其用于数据输入。每次点击都会增加项目的重要性,并可能改变云中项目的视图,因为它们都与云中所有其他项目相关联。

背景

字符串(我也称它们为“项目”)存储在 XML 文件中。XML 文件设计非常简单。每个项目都存储在一个 Tag 中,该 Tag 具有三个属性:TextOccurrenceLast。示例

<Tag Text="ABC of programming" Occurrence="5" Last="633923147566312334" />

Text 包含项目的文本,Occurrence 存储项目被使用的频率(或项目在文本中出现的次数),Last 包含上次访问的时间(以 DateTime.Ticks 表示)。我实现了对名为“Tags.xml”的默认 XML 文件的访问,该文件位于程序目录中。当然,您可以加载和保存任何用户创建的标签文件。

为了演示控件的使用,我编写了一个包装器,它向您展示了控件的大部分功能。请注意,该包装器在 GUI 编程方面并非杰作。它的唯一目的是展示与标签云相关的一些效果。

在截图中(图 2),“读取默认标签 XML”按钮已被按下,其效果是默认文件“Tags.xml”的内容显示在标签云中。在右侧,您可以看到云中可以显示的项目数量:“云中显示的项目数量”,以及所有正在使用的项目数量:“所有项目数量”。在我们的示例中,可以显示 34 个项目。标签云中显示的项目数量取决于控件的大小(您可以在包装器中以“+10”的步长更改它)以及项目权重(即它们的出现频率)之间的复杂交互。

项目权重通过五种不同的字体样式和颜色可视化。您可以通过设置控件的属性来更改它们(稍后描述)。包装器演示了如何通过“设置输出设计 1”更改最不重要项目的输出设计,以及通过“设置输出设计 3”更改中等重要项目的输出设计。您可以使用“设置标准输出设计”重置为默认值。

图 2:嵌入在 TagCloudWrapper 中的 TagCloud 控件

除此之外,您还可以更改控件的背景颜色(默认值为 Color.Azure)和标签的外观。设置属性“Underline on”会在鼠标悬停时显示项目下划线,设置“Frame on”会在项目周围显示框架(这也是单击项目时的捕获区域)。

图 3:开启框架的标签云控件

点击项目会触发事件。您可以在包装器的“标签信息”区域中看到这一点:点击的文本显示在“文本”文本框中,出现次数显示在“出现次数”文本框中。每次点击项目都会使其权重增加 1,并且根据其他项目,它会改变其在云中的输出设计(或者不会!)。是否属于某个输出设计是通过统计方法计算的,取决于所有项目的总体平均值和标准差。您还可以找到“”和“最少”点击的项目以及“最年轻”和“最老”点击的项目。

在“一些标签操作”区域中,您可以研究如何添加项目(请研究源代码,了解那里实际发生了什么),并且您可以“清除所有项目”。使用“添加此项目”,您可以向云中添加一个项目。它必须在按钮左侧的文本框中进行编辑。添加新项目时,其权重(出现次数)将设置为所有项目的平均值,以使其真正出现。如果它从权重 1 开始,则可能不会显示,因为其他项目会占据主导地位。

要操作云控件的内容,您可以右键单击项目打开上下文菜单。您可以添加新项目、删除项目或更改项目文本。

图 4:标签云控件中的上下文菜单

在云中显示标签的另一种方法是打开文本文件或 HTML 文件。这在“从文本和 HTML 文件读取标签”区域中进行了演示。那里的三个按钮演示了打开文本或 HTML 文件,评估其中的重要标签,并在云控件中显示标签。由于英语(或德语)中有许多填充词,我添加了两个文件:ExcludeList-en.txtExcludeList-de.txt,它们包含一些在构建云词列表时不会被考虑的词。这些词包括:I、you、are、if、them、here、about、never... 该列表会根据预期的语言读取。在我的示例中,它是英语和德语(没有法语、西班牙语、意大利语......抱歉)。我知道这些列表不完整,所以您可以随意添加或删除词,甚至为所需的语言设计一个排除列表。当尝试显示 HTML 文件时,会使用另一个排除列表:ExcludeList-html.txt。它包含一些 HTML 和网页设计的语法(但也不完整)。

此外,云控件具有拖放功能。您可以获取任何文本或 HTML 文件并将其拖放到控件上。请注意不要使用过大的文件。我实现了一些检查以避免加载错误的文件格式,因此您可能会收到类似这样的消息

图 5:拖放失败

下面,您可以看到一个英文文本文件(例如:majorca_en.txt),它已被拖放到云控件上。为了在控件中显示更多项目,高度和宽度已手动扩展。

图 6:文件 majorca_en.txt 拖放成功

Using the Code

要使用云控件,您必须将“TagCloud.dll”添加到您的引用中。您可以在 TagCloudWrapper 项目中最好地看到它,该项目是解决方案的一部分。

在以下部分中,我将尝试描述“TagCloud”项目的类。

TXT处理

这个类负责读取文本或 HTML 文件。文件中的单词由一些分隔符(如“,.:";”)分隔。下一步,检查所有单词是否“需要”。需要意味着它们不属于相应的排除列表。

但是,让我们从头开始。首先,检查一个文件是文本文件、HTML 文件,还是两者都不是。一个基本的算法检查它是英文还是德文文本,以及它是文本还是 HTML

void GetFileTypeAndLanguage(string filename, 
   out bool ishtml, 
   out TagCloudControl.TextLanguage language)

根据结果,调用 (ishtml == false)

bool ReadTextFile(out SortedList<string, TagCloudControl.StringItem> sc, 
   string filename, 
   TagCloud.TagCloudControl.TextLanguage language)

或 (ishtml == true)

bool ReadHTMLFile(out SortedList<string, TagCloudControl.StringItem> sc, 
  string filename, 
  TagCloud.TagCloudControl.TextLanguage language)

被调用。此外,根据英语或德语,将适当的排除列表应用于单词。对于 HTML 文件,HTML 排除列表也将应用于过滤一些 HTML 特定的单词。结果是“所需”单词的列表,这些单词存储在 SortedList sc 中。此列表的部分内容将显示在云控件中。

关于排除列表的简短评论:如上所述,它们被称为:ExcludeList-en.txtExcludeList-de.txtExcludeList-html.txt

它们是普通的文本文件,您可以自行更改。

语法如下

Exclude:

word1, word2, word3, word4,..
wordxxx,wordyyy, wordzzz,...
...

Include:

word1, word2

ExcludeList-en.txt”的示例部分

Exclude:

a,able,about,above,ah,ain't,alas,am,an,any,anybody,
anyone,anywhere,after,again,against,ago,all,also,
although,among,and,are,around,as,at,away,
...

Include:

May,US,

您可以看到还有一个“Include”部分。它的目的是包含通常应该排除的单词。在“Exclude”部分中的单词应该用小写字母书写并用逗号分隔。由于“may”和“May”具有不同的含义,您应该在“Include”部分定义所有不应以您在那里定义的方式(即:区分大小写)书写时被排除的单词。请随意添加或删除单词。我不是以英语为母语的人,所以我想您可以进行很多改进。

TXTHandling”类中处理单词的一些方法有

int FillExcludeIncludeList(
    TagCloud.TagCloudControl.TextLanguage language, 
    bool clear)
bool WantedWord(string newword)
bool WantedHTMLWord(string newword)
bool IsRomanNumber(string number)
bool ContainsDigit(string word)
bool IsTimeSpan(string timespan)

XML处理

XMLHandling”类包含读取和写入标签文件的方法,该文件包含云的标签(项目)。“ReadTagFile”和“WriteTagFile”方法是重载的。它们提供对特定文件名或默认标签文件“Tags.xml”的访问。默认文件名由“GetDefaultFileName”方法获取。

文件格式

FileFormats”类包含一些检查文件格式的方法。检查以下一些格式

  • 图形文件格式
  • 音频文件格式
  • 视频文件格式
  • 压缩文件格式
  • 程序和开发文件格式
  • 文档文件格式
  • 系统文件格式
  • 数据库文件格式

该列表并非详尽无遗——您可以随意添加其他文件格式。文件通过读取其魔术数字以简单的方式识别。这些是字节序列,大部分位于文件的开头,可以让您大致了解它可能是什么类型的文件。在此解决方案中,这些方法用于避免“错误”文件被拖放到云控件上。

统计

Statistics”类负责提供值集合的平均值

double Mean(IEnumerable<double> values)

和标准差

double StandardDeviation(IEnumerable<double> values, out double mean)

这两个值对于将项目与其在其他项目中的上下文联系起来至关重要,以决定它是否会显示在云控件中以及它在那里具有什么权重。根据其权重,将为其分配 5 种输出设计(字体、颜色)之一。

添加项目和重命名项目

这些类是简单的对话框,当在上下文菜单中单击时显示。“AddItem”允许您向云中添加一个新项目,“RenameItem”为您提供了更改现有项目名称的可能性。

TagCloudControl

这个类是云控件管理和显示的核心类。它包含许多属性和方法来控制云控件。在下面的部分中,我将描述其中一些。理解其功能的最佳方法是研究 TagCloudWrapper 中的方法和属性调用。

我们从 属性 开始

// Sets or gets the control's back color
public Color ControlBackColor

// Sets or gets the condition for drawing a rectangle
public bool ControlTextFrame

// Sets or gets the condition for drawing
// the text strings underlined on mouse hover
public bool ControlTextUnderline

// Sets or gets the control's height.
// Due to a height change, the cloud is set and painted new
public int ControlHeight
// Sets or gets the control's width.
// Due to a width change, the cloud is set and painted new
public int ControlWidth

// Gets the most clicked text item from
// the list with text items (StringCollection)
public string MostClickedItem

// Gets the least clicked text item from
// the list with text items (StringCollection)
public string LeastClickedItem

// Gets the oldest clicked text item from
// the list with text items (StringCollection)
public string OldestClickedItem 

// Gets the youngest clicked text item from
// the list with text items (StringCollection)
public string YoungestClickedItem

// Gets the number of the items in StringCollection
public int ItemsCount 

// Gets the number of the items shown in the cloud
public int ShownItemsCount 

唯一触发的事件是鼠标单击项目时

[Description("Delegates a click onto the user control to the wrapper")]
// delegate declaration
public delegate void OnUserControlClick(string Text, double Occurrence);
// event declaration
public event OnUserControlClick clickHandler;

该事件返回云中项目的文本和出现次数。

输出设计管理的公共方法

// Sets the 5 predefined output designs
public void SetAllDesigns(bool update)
 
// Sets an output design
public bool SetDesign(int number, string font, float size, Color color)

// Overloaded, sets an output design
public bool SetDesign(int number, OutputDesign od)

字符串管理的公共方法

// Adds or replaces a text item to the list of items (StringCollection).
// If the item is new, its occurrence is set to 1,
// else its previous occurrence is incremented by 1.
// The attribute 'last' (last access) will be set to 'now'.
public void AddItem(string text)
// Overloaded, adds a text item to the list of items (StringCollection).
// The attribute 'last' (last access) will be set to 'now'.
public void AddItem(string text, double occ)
// Overloaded, adds a text item to the list of items (StringCollection).
// The attribute 'last' (last access) will be set by last.
public void AddItem(string text, double occ, long last)
// Overloaded, adds a complete list sc to the list of items (StringCollection).
public void AddItem(SortedList<string, StringItem> sc)
// Overloaded, adds or replaces a text item to the list of items (StringCollection).
// If the item exists already in StringCollection,
// the variable regardmean will be interpreted:
// - if regardmean is true and the item is not yet member of CloudCollections, 
// the occurrence will be set to the mean occurrence
// of the items in the StringCollection
// - otherwise its occurrence is incremented by 1.
// If the item does not exist, the variable regardmean will be interpreted:
// - false: the occurrence will be set to 1
// - true: the occurrence will be set to the mean occurrence
// of the items in the StringCollection.
// The attribute 'last' (last access) will be set to 'now'.
public void AddItem(string text, bool regardmean)
// Removes the item text from the item list (StringCollection).
public void RemoveItem(string text)
// Clears the list with the items (StringCollection) completely.
public void ClearAllItems()
// Returns all the items from the StringCollection.
public SortedList<string, StringItem> GetAllItems()

构建云的私有方法

这些方法都是私有的,因为它们仅在以下情况被调用:

  • 字符串被添加或从字符串集合中删除
  • 项目的权重发生变化
  • 项目的输出设计发生变化
  • 云的设计发生变化

这些方法负责构建云的内容并显示项目

private void SetCloud()
private void CopyStringsToCloud()
private int BuildCloud(ref StringItem si)

该算法的工作原理如下:项目按字母顺序排列。根据它们的权重,它们会获得一种输出设计(5 种之一)。将计算项目的文本尺寸是否适合云。如果尺寸超出右边界,则会开始新的一行。一行的高度由该行中项目的最大高度决定。当您查看图 3 时,您可以最好地理解它,其中显示了文本边界(框架开启)。新行将以相同的方式填充,并且这样做直到达到云控件的下边界。如果项目列表尚未结束,则“最弱”的项目将从应显示的项目列表中删除。“最弱”的项目是出现次数最少且长时间未被调用的项目。

现在,云控件的填充开始一个新的周期。由于已删除一个项目,其他项目的权重可能已更改。因此,输出设计可能由于新的统计计算而发生更改,并且相应地,文本尺寸也可能发生更改。整个过程是一个递归过程,旨在显示大多数“重要”项目。在这种情况下,“重要”意味着出现次数最多且最近被调用的项目。有关详细信息,请研究代码。也许可以优化,但在我的机器上,我没有性能问题。

关注点

我计划在未来的两个应用程序中使用云控件。

一方面,我想编写一个程序,对数码相机拍摄的图像进行一些基本修改。其中一个要点是重命名文件,我想我将使用标签云来获取半自动文件重命名的关键字。我计划根据我们上次假期创建一组关键字,就像图 6 示例中建议的那样。

另一方面,我还计划编写一个程序,通过提问来帮助您学习,您必须正确回答这些问题。问题是随机提出的,但我可以想象,额外提供一个包含基于主题的关键字的标签云,您可以点击这些关键字,会是一件好事。

我希望您有更多的好主意——请告诉我!

历史

  • 初始版本 1.0:2009 年 12 月。
© . All rights reserved.