カテゴリー
Software Utility

[最新作]ALPH 開発過程 | AmpiTa Project

概要

 アフィリエイトのリンクを作成する『Kattene』では、下図のようなリンクを作れます。


 しばらく使ってきたのですが、どうも雲行きが怪しくなってきました。

 Wordpressの公式サイトで見ると『最終更新日: 11か月前』でした。


 普段は見ないのですが、インストール済のプラグインを確認してみたら、実はWordpressの現在の使用環境ではテストされていないことがわかりました。

 現在のテーマは『Twenty-Twenty』なので、それを変更すれば良いのかもしれませんが、いまさらテーマ変更というのも大仕事なので、Katteneの使用を中止する方向で検討に入りました。




Katteneの利便性を高める

 Katteneはタグ入力が必要なプラグインでしたので、多少の使い勝手の悪さがありました。

 それを克服するために、Kattene専用のタグ自動生成ソフトウェアを開発しました。

 作ったのは2020年で、特に修正を加えることも無く現在も使っています。

 特徴としては、アフィリエイトリンクをどこかから調達してくるだけで、タグ作成は自動で行われます。URLさえ間違えていなければ、タグ入力ミスによる表示エラーということはなくなります。

【参考】Kattene専用タグ生成『Kattene Text Maker』




踏襲システム開発

 アフィリエイト生活をしている訳ではないので使用頻度が高い訳ではないのですが、せっかくアフィリエイトリンクを設置するのであれば正常に動作して欲しいので、従来のインターフェイスを踏襲したシステムを開発することにしました。

 概ね、データ登録方法は同じにして、諸々の配置などもだいたい同じ位置にして、類似のシステムを開発することにしました。

 『Kattene Text Maker』はWordpressのプラグイン『Kattene』に合わせて作りましたが、こんどはプラグインを利用しない形でのアフィリエイトリンクを計画しました。




HTMLタグのプロトタイピング

 何が良いかはわからないので、とりあえずいくつかのHTMLタグを作ってみて、どれが良いかを選ぶことにしました。

 プロトタイピングですので、壊すためのたたき台をつくって、ダメ出ししながら修正していきます。

 実物(試作)があるので、使用感がわかりやすくなっています。




HTMLプロトタイピング1

 Katteneをオマージュというか、複製したような形です。

 似ていますが、これはカラムではなくテーブルを使っているので、スマホで見た時に画像と文字は横並びです。カラムを使うと縦組みに変更できるのですが、そうなるとスタイルシートが必要になりますのでやめました。

AmpiTa DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
一部の自動レシピが使えないほかは、上位機種に近い内容です。
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。

 上記のアフィリエイトリンク枠のHTMLタグ(コード)は以下の通りです。


<div align="center">
<table  border="0"  width="100%" style="border-color: white; border: none;">
<tr align="center">
<td rowspan="2" width="20%" align="center">
<a href="https://amzn.to/3Ub5ZSM" target="_blank">
<img src="https://www.ampita.jp/wp-content/uploads/2022/09/top_level_logo.png" alt="AmpiTa" title="AmpiTa" width="120" height="120">
</td>
<td  colspan="3" width="80%"  align="left"  valign="top">
<b>DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B</b>
<br>
一部の自動レシピが使えないほかは、上位機種に近い内容です。<br>
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
</td></tr>
<tr align="center" valign="bottom">
<td width="25%">
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://amzn.to/3Ub5ZSM','_blank')">アマゾン</button></td>
<td width="25%">
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://a.r10.to/hMWSz4','_blank')">楽天市場</button></td>
<td width="25%">
<button type="button" style="background-color:#cce3ff; width:100%; padding: 10px; " onclick="window.open('https://www.ampita.jp','_blank')">ヤフーショッピング</button></td></tr></table><br></div>




HTMLプロトタイピング2

 次のプランとして、ボタンを横並びではなく縦並びにしたらどうかと考えました。

 最終的には解消されますが、この時点では代表画像がない、説明文がセンタリングされてしまっているなどの課題がありました。

 縦並びは見た目に良いのですが、パソコンで見た時に間延びするような感じがしました。

DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
一部の自動レシピが使えないほかは、上位機種に近い内容です。
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。

 上記のアフィリエイトリンク枠のHTMLタグ(コード)は以下の通りです。

<div align="center">
<table  border="0"  width="100%" style="">
<tr align="center">
<td>
<a href="https://a.r10.to/hMWSz4" target="_blank">
<b>DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B</b></a>
<br>
一部の自動レシピが使えないほかは、上位機種に近い内容です。<br>
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
</td></tr>
<tr align="center" valign="bottom">
<td>
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://amzn.to/3Ub5ZSM','_blank')">アマゾン</button>
</td></tr>
<tr align="center" valign="bottom">
<td>
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://a.r10.to/hMWSz4','_blank')">楽天市場</button>
</td></tr>
<tr align="center" valign="bottom">
<td>
<button type="button" style="background-color:#cce3ff; width:100%; padding: 10px; " onclick="window.open('https://www.ampita.jp','_blank')">ヤフーショッピング</button>
</td></tr></table></div>




HTMLプロトタイピング3

 次のプランでは、画像を右側に持って来てみました。

 ボタン3つと画像1つで、横幅を4等分なので『td width=”25%”』としています。
 その0.25幅の枠内にボタンは100%幅で設置しています。

DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
一部の自動レシピが使えないほかは、上位機種に近い内容です。
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
AmpiTa

 上記のアフィリエイトリンク枠のHTMLタグ(コード)は以下の通りです。

<div align="center">
<table  border="0"  width="100%" style="">
<tr align="center">
<td  colspan="3" width="90%"  align="left"  valign="top">
<b>DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B</b>
<br>
一部の自動レシピが使えないほかは、上位機種に近い内容です。<br>
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
</td>
<td rowspan="2" width="10%" align="center">
<a href="https://amzn.to/3Ub5ZSM" target="_blank">
<img src="https://www.ampita.jp/wp-content/uploads/2022/09/top_level_logo.png" alt="AmpiTa" title="AmpiTa" width="120" height="120">
</td></tr>
<tr align="center" valign="bottom">
<td width="25%">
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://amzn.to/3Ub5ZSM','_blank')">アマゾン</button>
</td>
<td width="25%">
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://a.r10.to/hMWSz4','_blank')">楽天市場</button>
</td>
<td width="25%">
<button type="button" style="background-color:#cce3ff; width:100%; padding: 10px; " onclick="window.open('https://www.ampita.jp','_blank')">ヤフーショッピング</button>
</td></tr>
<tr align="center">
</tr>
</table>
</div>




HTMLプロトタイピング4

 これが最終案になったものです。

 右側には画像、または画像+テキストのリンク専用iframeを配置できるようにしました。

 ボタンは縦並びで、タグを書き換えれば無尽蔵に増やすことができるようにしています。

 残念ながらカラムではないのでスマホでの体裁は少し悪いです。

 Katteneでは画像しか表示できなかったところを、価格まで表示可能な画像+テキストとしたことで、ページの記事を読んでいる人にとってはわかりやすい表示になったと思います。

DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
一部の自動レシピが使えないほかは、上位機種に近い内容です。
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。

 上記のアフィリエイトリンク枠のHTMLタグ(コード)は以下の通りです。

<div align="center">
<table  border="0"  width="100%" style="">
<tr align="center">
<td width="65%" align="left" valign="top">
<b>DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B</b>
<br>
一部の自動レシピが使えないほかは、上位機種に近い内容です。<br>
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
</td>
<td rowspan="4" width="35%" align="center">
<iframe sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=s30104406-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B08K2WGJC3&linkId=a7dc171c3cc07dcba4d1c87d71e72fab"></iframe>
</td></tr>
<tr align="center" valign="bottom">
<td>
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://amzn.to/3Ub5ZSM','_blank')">アマゾン</button>
</td></tr>
<tr align="center" valign="bottom">
<td>
<button type="button" style="background-color:#cce3ff; width:100%;padding: 10px; " onclick="window.open('https://a.r10.to/hMWSz4','_blank')">楽天市場</button>
</td></tr>
<tr align="center" valign="bottom">
<td>
<button type="button" style="background-color:#cce3ff; width:100%; padding: 10px; " onclick="window.open('https://www.ampita.jp','_blank')">ヤフーショッピング</button>
</td></tr></table></div>




ソフトウェア開発(Visual Studio 2022)

 開発言語はC#、環境はマイクロソフトのビジュアルスタディオ2022を使いました。

【参考】Microsoft: Visual Studio 2022


 Visual Studio2022を起動して『新しいプロジェクトの作成』を選び、リストから『Windows フォーム アプリケーション(.NET Framework)』を選択しました。


 保存先のフォルダ名やプロジェクト名などを決定すると開発環境が提供されます。

 1か所だけ即時変更しました。
 『構成マネージャー』の『アクティブ ソリューション プラットフォーム』は『x64』に変更しています。




画面デザイン

 画面は1枚で全機能を構成するデザインとしました。

 最上段にプレビューを設け、ここは下段にある設定部分を反映して色や文字などを確認する部分としました。


Preview

 プレビュー枠はテキストボックスがタイトル用と説明文用で2つ、ボタンが4つ、ピクチャーボックスが1つあります。

 タイトル用は1行のみの設定、文字は太字(Bold)の設定です。

 説明文は Multiline を True にして複数行表示、 Scrollbars は Vertical (縦)だけ表示する設定にしてあります。

 ボタンは標準で Visible を False として非表示、URLの入力を検出した際に True に変更することにしてあります。


Title

 タイトル枠は3行で構成し、最上段にはURL入力欄を設けています。
 テキストボックスは ImeMode を Disable として半角英数のみ受け付けました。
 その左に在るラジオボタンは二者択一式として、片方は『画像+テキスト』などの iframe に対応するURL、他方は画像リンクに対応するURLを入力する際に使用します。

 タイトルは普通のテキストボックスです。

 説明文のテキストボックスは Multiline が True で ScrollBars が Vertical という以外は普通のテキストボックスです。


Button

 ウェブ画面には、自動設定では最大4個のボタンを表示できます。HTMLタグを直接編集すれば100個でも設置は可能です。

 ボタン1~4の設定はそれぞれ同じ方法であり、URL欄は IME を半角英数にロックしたテキストボックスを使用しています。

 ボタンに表示されるラベルは任意で変更可能だが、プリセットした内容を反映させたい場合はラジオボタンから選択する方法としました。

 ボタンのフォント色と背景色は16進数で設定可能、その16進数はテキストボックスに入力することとしました。


Setup

 セットアップ欄は、自身の決めた諸設定を毎回使用できるようにいくつかの項目を保持しています。

 入力欄は数値等であれば半角英数に限定し、ボタンのラベル欄は自由(NoControl)に入力できるようにしました。

 フォントサイズはHTMLで指定可能な『em』という倍率を指定する方法とポイント指定の両対応しました。

 表示は左右2つの枠に分かれるので、それぞれの比率を自由に設定できるようにしました。ここは『%』で決定するか、ポイント指定の両対応しました。

 ボタンラベル、フォントカラー、背景色は5つのラジオボタンに対応し、5つの設定欄を設けました。


Function

 このソフトウェアの機能を動かす方法は原則的にボタン操作です。一部は入力欄を離れた時に自動的に動作します。

 HTMLタグを出力するには『Edit』ボタンを使います。

 入力内容を初期設定に戻すための『Clear』ボタンもあります。

 セットアップ欄の内容を保存するボタン、保存してある内容を呼び出すボタンもあります。本ソフトウェアで標準としているセットアップ内容を呼び出す機能もあります。


ToolTip

 画面に表示されませんが、ToolTipもデザイン画面で設定してあります。




Main_Load

 筆者(開発者)は情報系の学校出身ではありません。情報系の勤務経験もありません。

 完全独学なので、最初に何をするのか知りません。

 したがいまして、自己流です。

 最初にするのはデザイン画面のフォームをダブルクリックしてコードエディタを開くという操作です。

 ダブルクリックで自動的に作られるのは『private void Main_Load(object sender, EventArgs e)』でした。

 特に記述すべきことはないので、フォームの名称をここで決定することにしました。命令は『this.Text』です。

private void Main_Load(object sender, EventArgs e)
{this.Text = "ALPH | Affiliate Link to Paste for HTML tags. | Provided by AmpiTa Project";}




Main_Shown

 フォームの Load とよく似ていますが、微妙にタイミングが違う Shown もよく使いますので、ここで入力できるように設定します。

 デザイン画面でフォームをクリックした状態で、プロパティウインドウに注目します。

 そこには雷マークがあり、それをクリックするとたくさんの機能が表示されます。

 最初にダブルクリックしたことで Load は使える状態になっていますが、それ以外は未使用状態です。

 下の方にある Shown をダブルクリックすると使えるようになります。


 この Shown の発生順ですが、Load ⇒ Activated ⇒ Shownの順番です。

 厳密に使い分けしている訳ではないのですが、筆者の場合は Load イベントでは固定的なことや他のフォームと関係することを処理しています。
 そのあとで Shown イベントでドロップダウンリストなどの初期設定をしています。

 あくまで独学なので、本質的に間違えているかもしれません。

 今回は Shown で以下の命令を出しました。

private void Main_Shown(object sender, EventArgs e)
{
    var sfd_Text_File = System.AppDomain.CurrentDomain.BaseDirectory + "\\" + "Affiliate_Setting.txt";
    if (System.IO.File.Exists(sfd_Text_File))
        { Load_Settings(); }
    else
        {
            Initializing();
            Save_Settings();
        }          
    StartUp();
}


 まず var で指定した sfd_Text_File というのは、セットアップファイルの保存場所です。このソフトウェアでは、ソフトが保存されているフォルダ(ディレクトリ)にセットアップファイル(Affiliate_Setting.txt)も保存します。

 『 System.AppDomain.CurrentDomain.BaseDirectory 』が本ソフトウェアの所在(パス)を示してくれます。そのあとに¥マーク、そしてファイル名と続く事でフルパスになります。


 取得したフルパスを用いて、ファイルが存在するか否かを確認します。
 if は『もしも』で、最初の『{}』内が True の場合、 else 以降の『{}』内が False の場合です。

 『 System.IO.File.Exists 』でファイルが存在するか否かを問い合わせています。

 ファイルが存在する場合は『Load_Settings』というイベントを呼び出します。

 ファイルが存在しない場合は『Initializing』というイベントで本ソフトウェアが既定する標準値を各欄に代入した後、その内容を保存するイベント『Save_Settings』を発生させています。


 セットアップ欄を埋めたのち、他の設定をするために『StartUp』を呼び出します。




初期設定のL.S.I.

 初期設定(Shown)では呼出(Load)、保存(Save)、初期化(Initialize)の3つの機能がいきなり使われます。
 これらの機能は操作ボタンでも命令することができます。
 この3つの機能はVisual Studioに搭載されている訳ではなく、勝手につくる機能(イベント)です。したがって、ネーミングも自由なので『Load_Settings』が『Kakikomi_Shimasu』でも問題なく動作します。

 ファイルのロードですが、下のコードのようになります。テキストファイルから1行ずつ読込んで、順番に当てはめていきます。

 ファイルが存在することを確認した後に『StreamReader』でテキストファイルを読込みます。
 あとは ReadLine で1行を丸ごと読み取っては対応するテキストボックスへ入れていきます。

private void Load_Settings()
{
    var sfd_Text_File = System.AppDomain.CurrentDomain.BaseDirectory + "\\" + "Affiliate_Setting.txt";
    if (System.IO.File.Exists(sfd_Text_File))
    {
        StreamReader sr_Text_File = new StreamReader(sfd_Text_File);
        txt_Set_Title_Font_Size.Text = sr_Text_File.ReadLine();
        txt_Set_Button_Font_Size.Text = sr_Text_File.ReadLine();
        txt_Set_Table_Width_Left.Text = sr_Text_File.ReadLine();
        txt_Set_Table_Width_Right.Text = sr_Text_File.ReadLine();

        txt_Set_01_Label.Text = sr_Text_File.ReadLine();
        txt_Set_01_Font_Color.Text = sr_Text_File.ReadLine();
        txt_Set_01_Color.Text = sr_Text_File.ReadLine();
        txt_Set_02_Label.Text = sr_Text_File.ReadLine();
        txt_Set_02_Font_Color.Text = sr_Text_File.ReadLine();
        txt_Set_02_Color.Text = sr_Text_File.ReadLine();
        txt_Set_03_Label.Text = sr_Text_File.ReadLine();
        txt_Set_03_Font_Color.Text = sr_Text_File.ReadLine();
        txt_Set_03_Color.Text = sr_Text_File.ReadLine();
        txt_Set_04_Label.Text = sr_Text_File.ReadLine();
        txt_Set_04_Font_Color.Text = sr_Text_File.ReadLine();
        txt_Set_04_Color.Text = sr_Text_File.ReadLine();
        txt_Set_05_Label.Text = sr_Text_File.ReadLine();
        txt_Set_05_Font_Color.Text = sr_Text_File.ReadLine();
        txt_Set_05_Color.Text = sr_Text_File.ReadLine();
        sr_Text_File.Close();
    }
}

 そうなると、セーブするときも同じで、1行ずつ書き込んでいきます。

 こんどは『StreamWriter』を使います。WriteLineで1行ずつ書き込みます。

 読込との違いは、ファイルの存在を確認しない点です。ファイルがあれば上書き、無ければ新設します。

 最後にある『System.Diagnostics.Process.Start』では、本ソフトウェアを使用している環境においてデフォルトされている方法で、設定ファイルが保存されたフォルダを開きます。

 『Path.GetDirectoryName』はフルパスの中から、ファイル名と拡張子除いた部分、すなわち保存先フォルダ(ディレクトリ)までを取得します。

private void Save_Settings()
{
    var sfd_Text_File = System.AppDomain.CurrentDomain.BaseDirectory + "\\" + "Affiliate_Setting.txt";
    StreamWriter fileHTML = new StreamWriter(@sfd_Text_File, false, Encoding.UTF8);
    fileHTML.WriteLine(txt_Set_Title_Font_Size.Text);
    fileHTML.WriteLine(txt_Set_Button_Font_Size.Text);

    fileHTML.WriteLine(txt_Set_Table_Width_Left.Text);
    fileHTML.WriteLine(txt_Set_Table_Width_Right.Text);

    fileHTML.WriteLine(txt_Set_01_Label.Text);
    fileHTML.WriteLine(txt_Set_01_Font_Color.Text);
    fileHTML.WriteLine(txt_Set_01_Color.Text);
    fileHTML.WriteLine(txt_Set_02_Label.Text);
    fileHTML.WriteLine(txt_Set_02_Font_Color.Text);
    fileHTML.WriteLine(txt_Set_02_Color.Text);
    fileHTML.WriteLine(txt_Set_03_Label.Text);
    fileHTML.WriteLine(txt_Set_03_Font_Color.Text);
    fileHTML.WriteLine(txt_Set_03_Color.Text);
    fileHTML.WriteLine(txt_Set_04_Label.Text);
    fileHTML.WriteLine(txt_Set_04_Font_Color.Text);
    fileHTML.WriteLine(txt_Set_04_Color.Text);
    fileHTML.WriteLine(txt_Set_05_Label.Text);
    fileHTML.WriteLine(txt_Set_05_Font_Color.Text);
    fileHTML.WriteLine(txt_Set_05_Color.Text);
    fileHTML.Close();
    System.Diagnostics.Process.Start(Path.GetDirectoryName(sfd_Text_File)); 
}

 L.S.I.の3つ目の Initialize は以下のコードです。

 フォントサイズ、枠幅、ラベル名、色などを開発者が勝手に決めています。

 あくまで初期値なので、ユーザーが任意に変更して Save することができます。いわばたたき台です。

private void Initializing()
{
    txt_Set_Title_Font_Size.Text = "0.8em";
    txt_Set_Button_Font_Size.Text = "0.6em";
    txt_Set_Table_Width_Left.Text = "65%";
    txt_Set_Table_Width_Right.Text = "35%";

    txt_Set_01_Label.Text = "Amazon";
    txt_Set_01_Font_Color.Text = "#ffffff";
    txt_Set_01_Color.Text = "#e47911";
    txt_Set_02_Label.Text = "Rakuten";
    txt_Set_02_Font_Color.Text = "#ffffff";
    txt_Set_02_Color.Text = "#bf0000";
    txt_Set_03_Label.Text = "Yahoo!";
    txt_Set_03_Font_Color.Text = "#ffffff";
    txt_Set_03_Color.Text = "#ff0033";
    txt_Set_04_Label.Text = "unknown";
    txt_Set_04_Font_Color.Text = "#ffffff";
    txt_Set_04_Color.Text = "#7db9e6";
    txt_Set_05_Label.Text = "unknown";
    txt_Set_05_Font_Color.Text = "#ffffff";
    txt_Set_05_Color.Text = "#e67db9";
}




Startup

 設定値の処理が終わると、次はスタートアップ処理です。

 まず、図を表示する PictureBox は、『PictureBoxSizeMode』を Zoom にして枠サイズに合わせて画像を表示します。これはウェブ画面で見るサイズとは異なります。プレビュー用です。
 最初は PictureBox は空なので null を入れておきます。

 プレビュー関連ではテキストボックスは空、ボタンはすべて非表示を最初の状態としています。

 入力欄もとりあえずは空欄です。

 ボタン設定の中のラジオボタンのラベル、フォント色や背景色の設定についてはセットアップから読込んで代入します。

private void StartUp()
{
    pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
    pictureBox1.Image = null;
    txt_Preview_Title_name.Text = "";
    txt_Preview_Note.Text = "";

    button1.Visible = false;
    button2.Visible = false;
    button3.Visible = false;
    button4.Visible = false;

    txt_Title_Image_URL.Text = "";
    txt_Title_name.Text = "";
    txt_Title_Note.Text = "";

    txt_01_URL.Text = "";
    rdb_01_01.Text = txt_Set_01_Label.Text;
    rdb_01_02.Text = txt_Set_02_Label.Text;
    rdb_01_03.Text = txt_Set_03_Label.Text;
    rdb_01_04.Text = txt_Set_04_Label.Text;
    rdb_01_05.Text = txt_Set_05_Label.Text;
    rdb_01_01.Checked = true;
}




Title編集

 Title枠にあるテキストボックスは、枠を離れた時に自動的に内容を確認して、空欄でなければプレビューに転記します。

 テキストボックスを編集すると発生する TextChanged で転記していると、文字を入力するたびにイベントが発生して重くなるので、すべてが終わってからの Leave イベントで処理しています。

private void txt_Title_name_Leave(object sender, EventArgs e)
{ txt_Preview_Title_name.Text = txt_Title_name.Text; }


private void txt_Title_Note_Leave(object sender, EventArgs e)
{ txt_Preview_Note.Text = txt_Title_Note.Text; }

 URL欄については別の処理が発生します。

 ラジオボタンを観察して『画像』のみか『画像+テキスト』かを判断します。『画像』が選ばれているときは PictureBox に紐づけますが、そうでない場合は PictureBox に null を与えます。

 『string.IsNullOrEmpty』を使うと、その対象が空白ではないかを調べることができます。ここではテキストボックスが空欄ではないことを確認してから PictureBox にリンクを送ります。

private void txt_Title_Image_URL_Leave(object sender, EventArgs e)
{
    if (rdb_Title_Amazon.Checked)
    { pictureBox1.Image = null; }
    else
    {
        if (string.IsNullOrEmpty(txt_Title_Image_URL.Text))
        { }
        else
        { pictureBox1.ImageLocation = txt_Title_Image_URL.Text; }          
    }
 } 




Button編集

 ボタン編集では色調整があるので、色についてだけリアルタイムの変化を許容しました。

 以下の2つのコードは、内容はだいたい同じです。

 片方はボタンの背景色(BackColor)を変える指示が出ます。
 他方はフォント色(ForeColor)を変える指示です。

private void txt_01_Color_TextChanged(object sender, EventArgs e)
{
    if (txt_01_Color.TextLength == 7)
    { txt_01_Label.BackColor = ColorTranslator.FromHtml(txt_01_Color.Text);
        button1.BackColor = ColorTranslator.FromHtml(txt_01_Color.Text);
    }
}

private void txt_01_Font_Color_TextChanged(object sender, EventArgs e)
{    if (txt_01_Font_Color.TextLength == 7)
    {
        txt_01_Label.ForeColor = ColorTranslator.FromHtml(txt_01_Font_Color.Text);
        button1.ForeColor = ColorTranslator.FromHtml(txt_01_Font_Color.Text);
    }
}

 その発生は、16進数の色を入力する欄の変更(TextChanged)です。タイトル欄では Leave を使いましたが、ここでは TextChanged を使っています。

 ここで行われるのは、色設定を変更すると、そのプレビューとして同枠内にあるボタンラベルを設定するテキストボックスが変更されます。

 背景色を変えれば TextBox の BackColor が変更されます。変更するたびにすぐに色が変わるので、目的の色であるかを即座に確認できます。




HTMLタグ出力

 HTMLタグの出力機能です。

private void HTML_Edit()
{
    int intLinksCount = 1;
    if (string.IsNullOrEmpty(txt_01_URL.Text))
    {
        MessageBox.Show(" 第1ボタンは必須です。これを埋めなければファイルは出力されません。", "AmpiTa Project");
        return; }
    else
    { intLinksCount = intLinksCount + 1; }
    if (string.IsNullOrEmpty(txt_02_URL.Text))
    { }
    else
    { intLinksCount = intLinksCount + 1; }
    if (string.IsNullOrEmpty(txt_03_URL.Text))
    { }
    else
    { intLinksCount = intLinksCount + 1; }
    if (string.IsNullOrEmpty(txt_04_URL.Text))
    { }
    else
    { intLinksCount = intLinksCount + 1; }

    try
    {
        var sfd_Text_File = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\" + "Affiliate" + DateTime.Now.ToString("yyMMddHHmmss") + ".txt";
        StreamWriter fileHTML = new StreamWriter(@sfd_Text_File, false, Encoding.UTF8);
        fileHTML.WriteLine("<div align=\"center\">");
        fileHTML.WriteLine("<table  border=\"0\" width=\"100%\" style=\"font-size: 1.0em\">");
        fileHTML.WriteLine("<tr align=\"center\">");
        fileHTML.WriteLine("<td width=\""+ txt_Set_Table_Width_Left.Text +"\" align=\"left\" valign=\"top\" style=\"font-size: " + txt_Set_Title_Font_Size .Text + "\">");
        fileHTML.WriteLine("<b>");
        if (string.IsNullOrEmpty(txt_Preview_Title_name.Text))
        { }
        else
        { fileHTML.WriteLine(txt_Preview_Title_name.Text); }
        fileHTML.WriteLine("</b>");
        fileHTML.WriteLine("<br>");
        if (string.IsNullOrEmpty(txt_Preview_Note.Text))
        { }
        else
        {
            string strNote = txt_Preview_Note.Text;
            //strNote=strNote.Trim();
            strNote = strNote.Replace("\r\n", "<br>");
            strNote = strNote.Replace("\n", "<br>");
            fileHTML.WriteLine(strNote); 
        }
        fileHTML.WriteLine("</td>");
        fileHTML.WriteLine("");
        fileHTML.WriteLine("<td rowspan=\"" + intLinksCount + "\" width=\""+ txt_Set_Table_Width_Right.Text + "\" align=\"center\">");
        if (string.IsNullOrEmpty(txt_Title_Image_URL.Text))
        { }
        else
        {
            if (rdb_Title_Amazon.Checked == true)
            { fileHTML.WriteLine(txt_Title_Image_URL.Text); }
            else
            {
        fileHTML.WriteLine("<a href=\"" + txt_01_URL.Text + "\" target=\"_blank\">");
        fileHTML.WriteLine("<img src=\"" + txt_Title_Image_URL.Text + "\" alt=\"AmpiTa\" width=\"120\" height=\"120\">");
            }
        }
        fileHTML.WriteLine("</td>");
        fileHTML.WriteLine("</tr>");
        fileHTML.WriteLine("");
        fileHTML.WriteLine("<tr align=\"center\" valign=\"bottom\">");
        fileHTML.WriteLine("<td>");
        fileHTML.WriteLine(
            "<button type=\"button\" " + "style=\"" +
            "color: " + txt_01_Font_Color.Text + ";" +
            "background-color:" + txt_01_Color.Text + "; " +
            "width:100%; padding: 6px; " +
            "font-size: " + txt_Set_Button_Font_Size.Text + "; \" " +
            "onclick=\"window.open('" + txt_01_URL.Text + "','_blank')\";>");
        fileHTML.WriteLine(txt_01_Label.Text);
        fileHTML.WriteLine("</button>");
        fileHTML.WriteLine("</td>");
        fileHTML.WriteLine("</tr>");
        if (string.IsNullOrEmpty(txt_02_URL.Text))
        { }
        else
        {
            fileHTML.WriteLine("<tr align=\"center\" valign=\"bottom\">");
            fileHTML.WriteLine("<td>");
            fileHTML.WriteLine(
        "<button type=\"button\" " + "style=\"" +
        "color: " + txt_02_Font_Color.Text + ";" +
        "background-color:" + txt_02_Color.Text + "; " +
        "width:100%; padding: 6px; " +
        "font-size: " + txt_Set_Button_Font_Size.Text + "; \" " +
        "onclick=\"window.open('" + txt_02_URL.Text + "','_blank')\";>");
            fileHTML.WriteLine(txt_02_Label.Text);
            fileHTML.WriteLine("</button>");
            fileHTML.WriteLine("</td>");
            fileHTML.WriteLine("</tr>");
        }
        if (string.IsNullOrEmpty(txt_03_URL.Text))
        { }
        else
        {
            fileHTML.WriteLine("<tr align=\"center\" valign=\"bottom\">");
            fileHTML.WriteLine("<td>");
            fileHTML.WriteLine(
        "<button type=\"button\" " + "style=\"" +
        "color: " + txt_03_Font_Color.Text + ";" +
        "background-color:" + txt_03_Color.Text + "; " +
        "width:100%; padding: 6px; " +
        "font-size: " + txt_Set_Button_Font_Size.Text + "; \" " +
        "onclick=\"window.open('" + txt_03_URL.Text + "','_blank')\";>");
            fileHTML.WriteLine(txt_03_Label.Text);
            fileHTML.WriteLine("</button>");
            fileHTML.WriteLine("</td>");
            fileHTML.WriteLine("</tr>");
        }
        if (string.IsNullOrEmpty(txt_04_URL.Text))
        { }
        else
        {
            fileHTML.WriteLine("<tr align=\"center\" valign=\"bottom\">");
            fileHTML.WriteLine("<td>");
            fileHTML.WriteLine(
        "<button type=\"button\" " + "style=\"" +
        "color: " + txt_04_Font_Color.Text + ";" +
        "background-color:" + txt_04_Color.Text + "; " +
        "width:100%; padding: 6px; " +
        "font-size: " + txt_Set_Button_Font_Size.Text + "; \" " +
        "onclick=\"window.open('" + txt_04_URL.Text + "','_blank')\";>");
            fileHTML.WriteLine(txt_04_Label.Text);
            fileHTML.WriteLine("</button>");
            fileHTML.WriteLine("</td>");
            fileHTML.WriteLine("</tr>");
        }
        fileHTML.WriteLine("");
        fileHTML.WriteLine("</table>");
        fileHTML.WriteLine("</div>");
        fileHTML.Close();

        StreamReader sr_Text_File = new StreamReader(sfd_Text_File);
        Clipboard.SetDataObject(sr_Text_File.ReadToEnd (), true);
        sr_Text_File.Close();
    }
    catch (Exception er)
    {
        MessageBox.Show("出力に失敗しました。\r\n\n" + "例外処理:\r\n" + er.Message + "\r\n" + er.HResult + "\r\n\n"+"例外発生場所:"+"\r\n" + er.Source + "\r\n\n" + er.TargetSite, "AmpiTa Project");
        Console.WriteLine(er.Message); 
    }
}

 冒頭では必須入力である第1項目が空欄であった場合の処理を入れています。

 つづいて、行数に応じて発生する調整のために何行使われているのか確認しています。

int intLinksCount = 1;
if (string.IsNullOrEmpty(txt_01_URL.Text))
{
MessageBox.Show(" 第1ボタンは必須です。これを埋めなければファイルは出力されません。", "AmpiTa Project");
return; }
else
{ intLinksCount = intLinksCount + 1; }
if (string.IsNullOrEmpty(txt_02_URL.Text))
{ }
else
{ intLinksCount = intLinksCount + 1; }
if (string.IsNullOrEmpty(txt_03_URL.Text))
{ }
else
{ intLinksCount = intLinksCount + 1; }
if (string.IsNullOrEmpty(txt_04_URL.Text))
{ }
else
{ intLinksCount = intLinksCount + 1; }

 そのあとの try 以降で本格的な処理が始まります。

 『System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)』でデスクトップのパスを取得しています。

 『DateTime.Now.ToString(“yyMMddHHmmss”)』では日時をファイル名に反映させて重複を防止しようとしています。
 2022年12月24日13時14分15秒なら『221224131415』となります。

try
{
    var sfd_Text_File = System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\" + "Affiliate" + DateTime.Now.ToString("yyMMddHHmmss") + ".txt";
    StreamWriter fileHTML = new StreamWriter(@sfd_Text_File, false, Encoding.UTF8);

 このあとは、HTMLのルールに従ってタグ入力していくだけです。プロトタイピングで問題箇所を削った結果のHTMLタグになるように作られていきます。

 最後に『fileHTML.Close』と書いてファイルを閉じます。同時に保存されます。

 そのあとで出て来る下のコードは、完成したばかりのファイルを読込んでクリップボードにコピーしています。

StreamReader sr_Text_File = new StreamReader(sfd_Text_File);
Clipboard.SetDataObject(sr_Text_File.ReadToEnd (), true);
sr_Text_File.Close();

 この構文は try で始めたので『}』で閉めたあとで、エラーをキャッチする catch の構文が入ります。

 エラーメッセージを出すことしか書いていません。特に処理を試みるより、訂正してもらった方が早いと考えたためです。




実行

 実行ボタンの処理は『HTML_Edit(); 』しか書いてありません。前述の『HTML_Edit』を呼び出して終わりです。

private void btn_Edit_Click(object sender, EventArgs e)
{ HTML_Edit(); }




仕上がり


 上図の実機を動かしてみてわかりました。

 プラグイン『AMP』が入っていると、スマホで動作しないことがあります。

 実はこの『AMP』は他のプログラムの動作も阻害しています。問い合わせフォームに『Contact Form 7』を使っていますが、これも『AMP』を有効にしていると動作しないので、無効にしています。

 今回、HTMLのボタン実装など見た目はしっかりパソコンもスマホも同じなのですが、スマホではボタンを押してもリンクは開きません。
 開かないときに『AMP』を無効にすれば正常動作します。




実物

 下に見えている(はず)のものが、本ソフトウェアから出力された実物のアフィリエイトリンクです。

DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
 一部の自動レシピが使えないほかは、上位機種に近い内容です。
 デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
一部の自動レシピが使えないほかは、上位機種に近い内容です。
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

デロンギ|Delonghi 全自動コーヒーマシン ディナミカ ブラック ECAM35055B [全自動 /ミル付き]
価格:198000円(税込、送料別) (2022/9/14時点)


 上の例は、右側に在る画像にテキストデータも付いたものです。
 下の例は、右側が画像だけのものです。
 画像とテキストが付いている例ですと、どうしても縦長になってしまいますが、価格も表示できるので、その点はメリットになるのではないかと思います。

DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
一部の自動レシピが使えないほかは、上位機種に近い内容です。
デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。
AmpiTa

 開発者として、最もエレガントに仕上がると思う方法は、Wordpressのカラム機能を使い、左右2枠のカラムに左側はALPHのシングル機能で作った表(Table)を、右側にはAmazonや楽天の画像付きテキストバナーを配置する方法です。
 以下に例示します。この設定はカラム70:30の2枠、表示は中央揃え、両枠ともカスタムHTMLを埋め込んで左枠にはALPHで作ったHTMLタグ、右枠にはAmazonから取得したiframeを入力しています。カラムと表組みの違いは、外枠がないことです。そして、スマホで見た時に上下組みになることです。

DeLonghi ディナミカ ミルクタンク付 全自動コーヒーマシン ECAM35055B
 一部の自動レシピが使えないほかは、上位機種に近い内容です。
 デロンギの全自動の中で最もコスパが高いミルクコンテナ付きの機種だと思います。


 本物のソフトウェアはこちらからダウンロードできます。




おわりに

 今回、アフィリエイト用のHTMLタグを自動的に生成するソフトウェアの開発をしてみました。

 思いついて24時間以内にはソフトが完成していたので、比較的簡単な方だと思います。

 わずか1日の作業が、今後の作業時間短縮につながると、それだけの価値が生まれますが、はたしてどの程度まで利用するかわかりません。

 このソフトウェアはVectorで公開しています。よかったらダウンロードしてみてください。

 最後までお読みいただき、ありがとうございました。


ソフトウェア開発実績はこちら