
棒読みちゃんは、テキストを音声で読み上げてくれるソフトです。プラグインによる機能拡張に対応しており、クリップボードや、Twitterのタイムライン、ニコニコ生放送のコメント等を読み上げさせることができます。
前回:棒読みちゃんプラグインの作成法 01では、何もしない棒読みちゃんのプラグイン作成方法をご紹介しました。
今回は、RSS読み上げプラグインの作成を題材として、プラグイン設定画面の実装、読み上げ機能の実装方法をご紹介します。
実装が必要なクラス
プラグインに設定機能を持たせるには、以下4つのクラスを連携させる必要があります。
| Plugin_RSS : IPlugin | プラグインクラスです。前回骨格部分を作成しました。 |
| PluginSettings | プラグインの設定管理クラスです。 Load()メソッドで設定ファイル(Plugin_RSS.setting)から設定値を読み込みます。 プラグインクラスのメンバとしている他、設定画面管理クラスにもメンバとして持たせる必要があります。 |
| SettingFormData | プラグインの設定画面管理クラスです。設定管理クラスをメンバとして持つ他、プロパティシートクラスもメンバに持ちます。 |
| SettingPropertyGrid | 設定画面フォームに表示用のプロパティシートクラスです。設定画面の項目を持たせます。 |
また、プラグイン個別の機能として、RSS取得・解析機能を持つRSSReaderクラスも作成します。
相関図
以下にクラスの相関を示します。
プラグインクラスのBegin()処理で、設定管理クラスのLoad(Plugin_RSS.setting)メソッドをコールし、
設定ファイル()から設定を読み込みます。
次に、設定画面管理クラスを生成し、設定管理クラスを渡しておきます。
設定画面管理クラスはコンストラクタでプロパティシートクラスを生成・保持するようにしています。
ファイル構成

ファイル構成は右図の通りです。プロジェクト名はPlugin_RSSとしています、以降、各クラスの実装について解説します。
プラグインクラス Plugin_RSS.cs
前回作成したコードをベースに実装しています。
Begin()メソッド内のプラグイン設定関連処理は前述のとおりです。
その他の処理として、棒読みちゃん本体に表示するRSSボタンを追加しています。
End()メソッドでは設定の保存と、RSSボタンの削除を実施します。
RSSボタン押下ハンドラ(_toolStripButton_Click())内では、RSSReaderクラスを利用してRSSを取得し、読み上げタスクに追加しています。
読み上げタスクの追加は、以下のように、読み上げさせたい文章を引数としてAddTalkTask()を呼び出すだけです。
//(ボタンハンドラ内でRSSReaderクラスを利用してRSS記事を取得済み)
//lstArticle : 記事のリスト
//article : 一つの記事
//記事リストを読み上げタスク追加
foreach (Article article in lstArticle)
{
//読み上げ文字列
string talk = String.Format("{0}{1}",article.title, article.description);
//読み上げタスクに追加
Pub.AddTalkTask(talk);
}
プラグインクラスのコード全体です。
Plugin_RSS.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms; //ToolStripSeparator, Button用(参照の追加が必要)
using System.Text.RegularExpressions;
using RSSUtility;//RSSリーダークラス
using FNF.BouyomiChanApp;
using FNF.Utility;
using FNF.XmlSerializerSetting;
namespace Plugin_RSS
{
/// <summary>
/// RSS読み上げプラグイン
/// </summary>
public class Plugin_RSS : IPlugin
{
#region 独自メンバー
//プラグインの設定ファイルパス
private string _path = Base.CallAsmPath + Base.CallAsmName + ".setting";
//プラグインの設定管理クラス
private PluginSettings _setting = null;
//プラグインの設定画面管理クラス
private SettingFormData _settingFormData = null;
//棒読みちゃん本体画面に追加するGUI部品
//セパレータ
private ToolStripSeparator _toolStripSeparator = null;
//ボタン
private ToolStripButton _toolStripButton = null;
#endregion
#region IPlugin メンバー の実装
/// <summary>
/// 棒読みちゃん本体の起動時か、
/// プラグインを有効にしたタイミングで呼ばれる
/// </summary>
public void Begin()
{
//プラグインの設定管理クラス生成
this._setting = new PluginSettings();
//プラグインの設定ファイルから設定値を読み込み
this._setting.Load(this._path);
//プラグインの設定画面管理クラス生成
this._settingFormData = new SettingFormData(_setting);
//棒読みちゃん本体画面に追加するGUI部品生成
//セパレータ生成
this._toolStripSeparator = new ToolStripSeparator();
//セパレータを本体画面に追加
Pub.ToolStrip.Items.Add(this._toolStripSeparator);
//ボタン生成
//あらかじめソリューションエクスプローラ->Properties->リソース->
//イメージ->リソースの追加->既存のファイルの追加
//で、ボタン画像をプロジェクトに追加済み
this._toolStripButton = new ToolStripButton(Properties.Resources.feed);
this._toolStripButton.ToolTipText = "RSS読み上げ";
this._toolStripButton.Click += new EventHandler(_toolStripButton_Click);
//ボタンを本体画面に追加
Pub.ToolStrip.Items.Add(this._toolStripButton);
return;
}
/// <summary>
/// プラグインの備考
/// </summary>
public string Caption
{
get { return "RSSを読み上げます"; }
}
/// <summary>
/// 棒読みちゃん本体の終了時か、
/// プラグインを無効にしたタイミングで呼ばれる
/// </summary>
public void End()
{
//設定値をプラグインの設定フィルに書き込み
_setting.Save(this._path);
//棒読みちゃん本体画面に追加したGUI部品削除
if (this._toolStripSeparator != null)
{
Pub.ToolStrip.Items.Remove(this._toolStripSeparator);
this._toolStripSeparator.Dispose();
this._toolStripSeparator = null;
}
if (this._toolStripButton != null)
{
Pub.ToolStrip.Items.Remove(this._toolStripButton);
this._toolStripButton.Dispose();
this._toolStripButton = null;
}
return;
}
/// <summary>
/// プラグインの名称
/// </summary>
public string Name
{
get { return "RSS読み上げ"; }
}
/// <summary>
/// プラグインの設定画面管理クラス
/// </summary>
public ISettingFormData SettingFormData
{
get { return this._settingFormData; }
}
/// <summary>
/// プラグインのバージョン
/// </summary>
public string Version
{
//公式プラグイン(クリップボード監視、Skype読み上げetc)の
//バージョン表記に合わせて、
//"西暦/月/日付版"としておくと統一感がでるでしょう。
get { return "2012/03/12版"; }
}
#endregion
#region ボタンハンドラ
/// <summary>
/// ボタンハンドラ
/// RSSを取得・解析し、RSS記事の文章を読み上げタスクに追加する
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void _toolStripButton_Click(object sender, EventArgs e)
{
try
{
string url = this._setting.URL;
//URLチェック
if (url == "")
{
MessageBox.Show("設定画面でURLを入力して下さい");
return;
}
Regex regex =new Regex(@"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?");
Match m = regex.Match(url);
if (!m.Success)
{
MessageBox.Show("URL文字列が不正です");
return;
}
//RSSリーダー生成
RSSReader reader = new RSSReader(url);
//RSS取得
string xml = reader.Get();
if (xml == "")
{
MessageBox.Show("RSSを取得できませんでした");
return;
}
//RSS解析
//記事リストを取得
List<Article> lstArticle = reader.Parse(xml);
if (lstArticle == null)
{
MessageBox.Show("RSSを解析できませんでした");
return;
}
//記事リストを読み上げタスク追加
foreach (Article article in lstArticle)
{
//読み上げ文字列
string talk = String.Format("{0}{1}",article.title, article.description);
//読み上げタスクに追加
Pub.AddTalkTask(talk);
}
}
catch (Exception exp)
{
PrintException(exp);
}
return;
}
#endregion
#region 汎用的なメソッド いろんなアプリで使える機能 別クラスに移動した方がよいかも
/// <summary>
/// 例外情報を表示します
/// </summary>
/// <param name="exp"></param>
private void PrintException(Exception exp)
{
Console.WriteLine("Message :n" + exp.Message);
Console.WriteLine("Type :n" + exp.GetType().FullName);
Console.WriteLine("StackTrace :n" + exp.StackTrace.ToString());
}
#endregion
}
}
設定管理クラス PluginSettings.cs
読みあげたいRSSのURLを設定値として持たせています。
メンバをpublicにしておくと、Load()メソッドで自動的に設定ファイル(Plugin_RSS.setting)から読み込まれ(デシリアライズ)、
Save()メソッドで自動的に設定ファイル(Plugin_RSS.setting)に保存(シリアライズ)されます。
using FNF.XmlSerializerSetting;
namespace Plugin_RSS
{
/// <summary>
/// プラグインの設定管理クラス
/// publicなメンバが設定ファイルに保存されます
/// </summary>
public class PluginSettings : SettingsBase
{
/// <summary>
/// RSSのURL
/// </summary>
public string URL;
/// <summary>
/// 以下タイミングで呼ばれる
/// 親クラス(SettingsBase)のSave()メソッドが呼ばれた時
/// 設定画面呼び出し時
/// </summary>
public override void ReadSettings()
{
return;
}
/// <summary>
/// 親クラス(SettingsBase)のLoad()メソッドが呼ばれた時
/// 設定画面OK終了時
/// </summary>
public override void WriteSettings()
{
return;
}
}
}
設定画面管理クラス SettingFormData.cs
ISettingFormDataインタフェースを実装したクラスを作成します。
前回ご紹介したインタフェースの実装機能を利用すると便利です。
Settingメンバでreturnする設定クラスはコンストラクタで受け取るようにしています。
また、プロパティシートクラスをpubulicメンバとして持ち、コンストラクタで生成しています。
using FNF.XmlSerializerSetting;
namespace Plugin_RSS
{
/// <summary>
/// プラグインの設定画面管理クラス
/// </summary>
class SettingFormData : ISettingFormData
{
//プラグインの設定管理クラス
private PluginSettings _settings = null;
//プラグインの設定画面(プロパティシート)
//publicで見せる
public SettingPropertyGrid _settingPropertyGrid = null;
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="settings">プラグインの設定管理クラス</param>
public SettingFormData(PluginSettings settings)
{
//プラグインの設定管理クラスを受け取る
this._settings = settings;
//プラグイン設定画面(プロパティシート)を生成する
this._settingPropertyGrid = new SettingPropertyGrid(this._settings);
}
#region ISettingFormData メンバー の実装
/// <summary>
/// TreeView内のノードを開いた状態とする 設定なのだと思う。
/// </summary>
public bool ExpandAll
{
get { return false; }
}
/// <summary>
/// プラグインの設定管理クラスのgetter
/// </summary>
public SettingsBase Setting
{
get { return this._settings; }
}
/// <summary>
/// 設定画面フォームのタイトル
/// </summary>
public string Title
{
get { return "RSS読み上げプラグインの設定"; }
}
#endregion
}
}
プロパティシートクラス SettingPropertyGrid.cs
設定画面に表示する項目として、RSSのURL入力欄を定義しています。
using System.ComponentModel;
using FNF.XmlSerializerSetting;
namespace Plugin_RSS
{
/// <summary>
/// プラグインの設定画面に表示するプロパティシート
/// </summary>
public class SettingPropertyGrid : ISettingPropertyGrid
{
private PluginSettings _settings = null;
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="setting"></param>
public SettingPropertyGrid(PluginSettings setting)
{
//プラグイン設定クラスを受け取る
_settings = setting;
}
/// <summary>
/// シートのタイトル
/// </summary>
/// <returns></returns>
public string GetName() { return "RSS設定"; }
/// <summary>
/// 基本設定
/// </summary>
[Category("RSS")]
[DisplayName("01)RSSのURL")]
[Description("読みあげたいRSSのURLを設定して下さい。")]
public string URL
{
get { return this._settings.URL; }
set { this._settings.URL = value; }
}
/* ISettingPropertyGridでは設定画面での表示項目を指定できます。
[Category ("分類")]
[DisplayName("表示名")]
[Description("説明文")]
[DefaultValue(0)] //デフォルト値:強調表示されないだけ
[Browsable(false)] //PropertyGridで表示しない
[ReadOnly(true)] //PropertyGridで読み込み専用にする
string ファイル選択 →[Editor(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor))]
string フォルダ選択 →[Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(System.Drawing.Design.UITypeEditor))]
string 複数行文字列入力 →[Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
*/
}
}
RSSリーダークラス RSSReader.cs
コンストラクタでURLを受け取り、Get()でRSSを取得、Parse()でRSSを解析して記事リストにします。
Parse()メソッドは当ブログのRSS向けに実装しています、必要に応じて書き換えて下さい。
using System;
using System.Collections.Generic;
using System.Net;
using System.Xml;
namespace RSSUtility
{
/// <summary>
/// RSSリーダー
/// </summary>
class RSSReader
{
//RSSのURL
private string _url = "";
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="url"></param>
public RSSReader(string url)
{
_url = url;
}
/// <summary>
/// RSSを取得します
/// </summary>
/// <returns></returns>
public string Get()
{
string xml = "";
try
{
WebClient wc = new WebClient();
wc.Encoding = System.Text.Encoding.UTF8;
xml = wc.DownloadString(_url);
wc.Dispose();
}
catch (Exception exp)
{
PrintException(exp);
return "";
}
return xml;
}
/// <summary>
/// RSSをパースします
/// http://c-loft.com/blog のRSSでしかテストしていません
/// パースしたいRSSの構造に応じて、適宜書き換えて下さい。
/// </summary>
/// <param name="xml">パース対象XML文字列</param>
/// <returns>記事リスト または null</returns>
public List<Article> Parse(string xml)
{
List<Article> lstArticle = null;
try
{
//XML解析
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xml);
XmlElement root = xdoc.DocumentElement;
XmlNodeList nlstItem = root.SelectNodes("channel/item");
//記事リスト生成
lstArticle = new List<Article>();
//記事リスト更新
foreach (XmlNode item in nlstItem)
{
//記事
Article article = new Article();
foreach (XmlNode node in item)
{
//日付
if (node.Name == "pubDate")
{
article.date = node.InnerText;
}
//タイトル
if (node.Name == "title")
{
article.title = node.InnerText;
}
//概要
if (node.Name == "description")
{
article.description = node.InnerText;
}
}
//記事リストに格納
lstArticle.Add(article);
}
}
catch (Exception exp)
{
PrintException(exp);
return null;
}
return lstArticle;
}
/// <summary>
/// 例外情報を表示します
/// </summary>
/// <param name="exp"></param>
private void PrintException(Exception exp)
{
Console.WriteLine("Message :n" + exp.Message);
Console.WriteLine("Type :n" + exp.GetType().FullName);
Console.WriteLine("StackTrace :n" + exp.StackTrace.ToString());
}
}
}
なお、1つの記事を表すArticleクラスは以下のように定義しています。
namespace RSSUtility
{
/// <summary>
/// 記事クラス
/// </summary>
class Article
{
public string date; //日付
public string title; //タイトル
public string description; //記事内容
}
}
動作確認

棒読みちゃん起動画面です。RSSボタンが追加されています。

その他タブにRSS読み上げプラグインが追加されています。
設定画面管理クラスを実装したので、設定ボタンも有効になっています。

設定画面です。プロパティシートに実装した設定項目の設定が可能です。

RSSボタンを押すとRSSを読み上げます。
以上で、設定機能と、読み上げ機能を持つプラグインが作成しました。
棒読みちゃんプラグイン作成方法のご紹介は以上です。
ところで、今回のようなdllを作成する開発の場合、動作確認方法がめんどくさいですね。
NiconamaCommentViewer(ニコ生コメントビューア)のプラグイン作成法 デバッグ編 でご紹介した方法を使うことで、
ブレークポイントで止めたり、ステップインしてりすることは可能です。
しかしながら、ソースコードを1行書き換えただけでも、ビルドしたdllファイルを、
本体プラグイン格納フォルダに置き直す必要があるのが欠点です。
そこで、dll作成プロジェクトでも、通常のプロジェクトと同じように、
デバッグ開始ボタン(or F5)を押すだけで、デバッグできるようにする方法をご紹介する予定です。

ピンバック:棒読みちゃんプラグインの作成法 01 | 夏研ブログ
Pub.ShowSettingForm()
使い方教えください!
>Zさん
初めまして。
プラグインの設定画面を開くメソッドですね。
通常、設定画面は「その他」タブの右下の工具のアイコンから表示させることができます、
そうではなく、メインの画面(「音声合成」タブ)に独自の設定ボタンを追加したい、ということでしょうか?
その場合、以下のようにして出来ます。
/// <summary> /// 棒読みちゃん本体の起動時か、 /// プラグインを有効にしたタイミングで呼ばれる /// </summary> public void Begin() { //: //略(記事掲載ソースコードの通り) //独自の設定ボタンを作成 ToolStripButton settingButton = new ToolStripButton(Properties.Resources.feed); settingButton.ToolTipText = "設定画面を開きます"; settingButton.Click += settingButton_Click; //ボタンを本体画面に追加 Pub.ToolStrip.Items.Add(settingButton); return; } /// <summary> /// ボタンクリックハンドラ /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void settingButton_Click(object sender, EventArgs e) { //設定画面を開く Pub.ShowSettingForm(this); }本当にありがとうございました!!
感動!とても勉強になりました。ヾ(*´∪`*)
ピンバック:棒読みちゃん – Site-Builder.wiki