のにっき

初めてのラノベ ~ 漫画よりラノベをおすすめする理由 ~

今回は、ラノベを読んだことない人に

ラノベを読んでもらえるように、PRしようと思います。

次回以降でジャンルごとに作品紹介をしていこうと思うのですが、

今回は、ラノベ自体の良さをご紹介したいと思います。

 

漫画と比較したときのラノベの良さ

 コスパが抜群にいい

ラノベの値段は差がありますが、だいたい 漫画2冊ぐらいです。

しかし、読み終わるまでにかかる時間はだいたい漫画10冊ぐらい!

もちろん個人差がありますが、

漫画よりもお値段以上に楽しめるのは大きなメリットだと思います。

作者の書きたいものが詰まりに詰まってる

漫画よりもラノベのほうが、作者のエゴが詰まっている印象です。

訳のわからないこねくり回した設定や、突拍子もないストーリー展開。

 ラノベは漫画と違って細かい設定まで文字で説明できるので、

作者の頭の中の書きたいことを全部書いているような感じです。

漫画よりもとっつきにくいのは確かですが、

漫画よりも作者のエゴが詰まっている分、相性がいい作品は

どっぷりはまれる面白さラノベにはあります。

自分の脳内補完で自分好みの作品になる

ラノベは文字だけの描写な上に、小説よりも地の文が少ない印象です。

会話の描写が多いので背景描写・状況描写がとても少ないです。

しかも、ファンタジー要素が多いと今がどんな状況なのか、

なんとなくしか分からないことが多いです。

だからこそ、自分の脳内で勝手に状況描写を補完するのですが、

自然と自分が面白いと思う描写に補完するので自分好みの作品になっていきます。

作者の頭の中を予想・補完してその後の文章とぴったりハマった時は、

漫画では味わえないスッキリ爽快感を味わうことができます。

こんな人はラノベを読め

 漫画を読み直すのが好きな人

読み直すのが好きな人は、漫画の中の深い部分まで楽しみたい人だと思います。

だからこそ、文字だけのラノベでも

作者の深い部分まで楽しめる度量のある人が多いと思います。

小説を読むのが好きな人・または読もうとして断念した人

私は小説も好きで読みますが、

ラノベは小説とは全く違った読みやすさと面白さがあります。

ですが、ラノベの第一歩として「文字を読む事に抵抗がない」事が大事です。

小説に手を出せる人は文字抵抗は少ないと思いますので、

ラノベにも手を出せると思います。

初めてラノベを読む方へ

色々なラノベの1巻だけ読みまくろう

ラノベの1巻はパンフレットだと思え!!

ラノベは漫画よりも好き嫌いに個人差ができるものだと思います。

だからこそ、あなたが面白い!と思うラノベが見つかるまで

1巻だけ読んでみる。という読み方をおすすめします。

1巻あれば、その作品の設定やストーリーが大体わかります。

その上で、ピンときた作品だけ続きを読むようにしましょう。

ピンとこない作品を読み進めるほど苦痛なものはないですから。。。

完結済み、もしくは10巻以上出ているラノベを買おう

ラノベは漫画と違って「1巻出るのに1年ぐらい」かかります。

また、新刊が出たときに内容を確認しようとして

1から読み直すのがとてつもなくダルイ」です!

つまり、ラノベは一気に読めないとつらいものがあります。

理想は完結している作品を読むことですが、

2,3巻ぐらいの作品は読みごたえがないうえに、

完結まで何年かかるかわからないので

10巻ぐらい出ている作品を読むことをおすすめします。

AmazonPrime加入者は無料で読みまくろう

www.amazon.co.jp

Prime会員は、無料で有名なタイトルのラノベを読むことができます。

有名どころも結構無料で読めますので、評価が高めのやつを読んでみてください。

 

【VS】リストボックスの背景色をノードごとに変更する

Windowsフォームアプリのリストボックスです。
リストボックスの背景色を変更するのは意外とめんどくさかったので
手法をまとめようと思います。

フォームを作ってみた

f:id:apuridasuo:20200729131910p:plain
図:背景色を変更させたListBox

上図が、実際に作成したフォームの画像になります。
ノード背景を1つずつ変更させることで、見やすい背景色になってます。
背景色を変更させるためには、
プロパティ設定イベント組み込みを行う必要があります。

プロパティ設定

DrawMode切り替え
f:id:apuridasuo:20200729132246p:plain
図:切り替え後のプロパティ画面(プロパティ)

上図のように、背景色を変更したいListBoxのプロパティ設定の項目
「 DrawMode = OwnerDrawFixed 」
に変更します。
この設定を変更することで、後に記述します「 DrawItem
イベントを有効にすることが出来ます。

DrawItemイベント設定
f:id:apuridasuo:20200729132912p:plain
図:切り替え後のプロパティ画面(イベント)

上図のように、イベントを設定します。
※関数名は任意で構いません
※関数の内容は後に記述します

イベント関数組み込み

フォーム起動時にリストボックスにノードを入れる処理
/***********************************************************************
    【Ev】フォーム起動時イベント
***********************************************************************/
private void Form1_Load(object sender, EventArgs e)
{
    //リストにノード追加
    listBox1.Items.Clear();
    string[] setNd = new string[] 
        {"ノードA","ノードB","ノードC","ノードD","ノードE",
            "ノードF","ノードG","ノードH","ノードI","ノードJ" };
    listBox1.Items.AddRange(setNd);
}
リストボックス描画イベント内容
/***********************************************************************
    【Ev】リストボックスノード描写処理
***********************************************************************/
private void ListBox_Cmn_DrawItem(object sender, DrawItemEventArgs e)
{
    // 背景描画
    e.DrawBackground();
    // 描画許可判定
    if (e.Index < 0)
    {
        return;
    }
    // 描画用変数設定
    Brush NdClrWd = new SolidBrush(e.ForeColor);
    string NdWord = ((ListBox)sender).Items[e.Index].ToString();
    // 奇数行の場合は背景色を変更し、縞々に見えるようにする
    Color backcolor;
    if (e.Index % 2 == 0)
    {
        backcolor = Color.FromArgb(220, 220, 220);
    }
    else
    {
        backcolor = Color.FromArgb(255, 255, 255);
    }
    // ノード作成
    e = new DrawItemEventArgs(e.Graphics, e.Font, e.Bounds, e.Index, e.State, e.ForeColor, backcolor);
    e.DrawBackground();
    e.Graphics.DrawString(NdWord, e.Font, NdClrWd, e.Bounds, StringFormat.GenericDefault);
    NdClrWd.Dispose();
    e.DrawFocusRectangle();
}

このようにイベント内容を組み込むと、
画像のように背景色が縞々になります。
// 奇数行の場合は背景色を変更し、縞々に見えるようにする
この部分を自由に変更することで、自分好みの形式を設定することが出来ます。
DrawItem」イベントはListBoxのノードが変更されるたびに呼ばれるイベントなので、
常に最新のノードに対する描画が行われます。
描画処理を忘れることが無いのでぜひ、ご活用ください。

最近同じ夢ばかり見る。。。

ブログに書くことでもないのですが、

とても不思議で誰かに言いたい!

だけど知り合いに報告すると正気を疑われそうなので書かせてください。

 怖い現象

ここ半年で覚えているだけでも10回以上、同じ内容の夢を見ます。

いつもは見た夢なんて忘れるし、

今までの人生で

また同じ夢だ・・・っ!」ってなったことがなかったので少し怖いです。

 

 夢の内容

・大学生として生活している

・周りの環境は学生の頃だけど、何故か今働いている会社員でもある

・時期は、大学卒業する1年前(就活が始まるぐらい)

・場面は、友達に授業の代返を頼みながら

 (あれ?この授業結構休んでるけど、単位に必要な出席数って大丈夫かな?)

   と自問自答しているところから始まってる

・その後、就活について思いを馳せて、

 (今働いてるけど俺の身分は会社員なの?学生なの?)

 (プログラマとして経験積んでるから頑張れば結構いいとこいけるかもなー)

  と、学生なのに意味のわからない自問自答をする

・最後に、今の会社の残件を思い出しながら

(あれ?俺って会社で働いてるよね?なんで大学生なの?)

  と現実を思い出しつつ起床する

 

以上が夢の内容です。

細かい内容は覚えていないのですが、

頭の中のやり取りは忘れずに記憶に残っていて上記の内容を毎回考えています。

 

もしこれを見た

精神科医等の専門的な方がいらっしゃいましたら、

私は正常なのかコメントで教えていただけるととても嬉しいです。

 

以上、どうか温かい目でよろしくお願いいたします。

【C#】修飾子ごとに出来る事 ※. private、public、static 編

今日、後輩に「staticって何ですか?」と聞かれて、激テンパったので調べてみました。
結果として、口で説明することは私には無理だ。とさじを投げたのですが、
各修飾子の挙動をまとめることで後輩に何とか説明できました。
ブログのネタになりそうでしたのでまとめます。

構文エラーで挙動を確認してみた

C#でクラス内に各修飾子の変数を定義し、クラスを跨いで 変数にアクセスした時に、構文エラーが出るものをまとめてみました

確認用コード

▼ 変数を定義したクラス

namespace WindowsFormsApp1
{
    class Cmn_Script
    {
        //テスト用クラス
        private string Hensu_Private;
        public string Hensu_Public;
        public static string Hensu_Static;

        //メソッドから変数をいじる用
        public void SetHensu_Public()
        {
            Hensu_Private = "";
            Hensu_Public = "";
            Hensu_Static = "";
        }
        public static void SetHensu_Static()
        {
            Hensu_Private = "";
            Hensu_Public = "";
            Hensu_Static = "";
        }
    }
}

▼ 変数をいじる関数を定義したクラス

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        // A)クラスを直接いじる
        private void Event_Test_A()
        {
            Cmn_Script.Hensu_Private = "";
            Cmn_Script.Hensu_Public = "";
            Cmn_Script.Hensu_Static = "";
        }
        // B)クラス型変数を作って中身をいじる   
        private void Event_Test_B()
        {
            Cmn_Script Cls_Set = new Cmn_Script();
            Cls_Set.Hensu_Private = "";
            Cls_Set.Hensu_Public = "";
            Cls_Set.Hensu_Static = "";
        }
        // C)クラス内メソッドを作って中身をいじる   
        private void Event_Test_C()
        {
            Cmn_Script.SetHensu_Public();
            Cmn_Script.SetHensu_Static();
            Cmn_Script Cls_Set = new Cmn_Script();
            Cls_Set.SetHensu_Public();
            Cls_Set.SetHensu_Static();
        }
    }
}

こんな感じでソースを組みました。
Windowsフォームアプリ内で作成したのでクラス名が変なのは気にしないでください。
同一namespace内の別クラスからアクセスしている。という事が重要です。

実際の構文エラー

エディターの画像をそのまま貼り付けます。

f:id:apuridasuo:20200717234954p:plain
図:エディター画像
画像のとなっている部分が構文エラーになっています。
構文エラーになるという事は、修飾子のルールにのっとっていない。という事です。
つまり、エラーの有無で修飾子の特性が分かってきます。

エラーから見える修飾子の特性

エラー情報から各修飾子の特性を見ていきます

①. Static(ソース上:SetHensu_Static)

Static変数は、「 A)クラスを直接いじる 」場合と、
同一クラスのメソッドからいじる 」場合にのみエラーになっていません。
つまり、Static変数の特性は
・同一クラスからのアクセスは可能
・クラスへ直接アクセスしてからのアクセス時は可能
という事です。
このおかげで、Static変数は大きな特性がありました。
クラス型の変数を作ろうが、クラスに直接アクセスしようが同じ値になる
という特性です。
他の修飾子の変数は、クラス型の変数(ソース上:Cls_Set)を作ると、
その変数ごとに値が変わっていくと思います。
Static変数はそれを許しません。
どんな状況でもアクセスできるけど、どんな状況でも同じ値になる
というのが特性の様です。

②. Private(ソース上:Hensu_Private)

Privateの変数を追ってみると、とても分かりやすい挙動になっています。
同一クラス内のメソッド以外からのアクセスは全てエラーになっています。
また、同一クラス内のメソッドでも
staticのメソッドのアクセスもエラーになっている点に注目です!
つまり、
同一クラス内からのみアクセス可能。かつ、
クラス型の変数を作れば、変数ごとに値も変わっていく
という特性になります。

③. Public(ソース上:Hensu_Public)

PublicはStaticとPrivateの自由な部分を併せ持った感じですね。
Staticのメソッド 」、「 A)クラスを直接いじる
つまり、
クラス型変数を作って、その中で変数をいじることで
クラス変数ごとに別々の値を持ち、自由にアクセスできる。

しかし、
自由に値を変えれるため、クラスを直接アクセスする方法は禁止されている。

以上です。
全然違う説明を行っていたら大変申し訳ございません。
素人の独学だと細かい知識がうっすらし過ぎていて恥ずかしい限りです。
違っている部分があれば、ご指摘いただけると
本当に勉強になりますので嬉しいです。

【C#】フォルダの高速コピー

今回は、フォルダの高速コピーをご紹介します。
フォルダのコピーとは、
サブフォルダも含めたすべてのファイルをコピーする
やり方になります。
再帰処理と並列処理を同関数で行っているので、
勉強中の方は処理の動きをご参考いただければ嬉しいです!

参考サイト

基本的な構文はこのサイトを参考にしました。
並列処理を追加したら高速になるなーの考えでちょっとだけ改造してます。
dobon.net

ソースコード

        /// <summary>
        /// サブフォルダを含むフォルダのコピー
        /// </summary>
        /// <param name="CopyFldName">コピーするフォルダパス</param>
        /// <param name="PasteFldName">コピー先のフォルダパス</param>
        public static void Set_CopyDirectory(string CopyFldName, string PasteFldName)
        {
            //コピー先のディレクトリがないときは作成
            if (!Directory.Exists(PasteFldName))
            {
                Directory.CreateDirectory(PasteFldName);              
                File.SetAttributes(PasteFldName, File.GetAttributes(CopyFldName));
            }
            //コピー先のディレクトリ名の末尾に"\"をつける
            if (PasteFldName[PasteFldName.Length - 1] != Path.DirectorySeparatorChar)
            {
                PasteFldName = PasteFldName + Path.DirectorySeparatorChar;
            }
            //コピー元のディレクトリにあるファイルをコピー ※ここで並列処理
            string[] files = Directory.GetFiles(CopyFldName);
            Parallel.ForEach(files, (file) =>
            {
                File.Copy(file, PasteFldName + Path.GetFileName(file), true);
            });
            //コピー元のディレクトリにあるディレクトリについて、再帰的に呼び出す
            string[] dirs = Directory.GetDirectories(CopyFldName);
            foreach (string dir in dirs)
            {
                Set_CopyDirectory(dir, PasteFldName + Path.GetFileName(dir));
            }
        }

以上がコピー処理を行う関数になります。
サブフォルダを考慮して再帰処理を行っている点と、
ファイルのコピーに並列処理を行っている点です。

以上、フォルダの高速コピーでした。 

【C#】自作アプリの自動アップデート機能

社内用にアプリを作成して配布するとき、
配布後にアップデートするのがとても面倒だったりしませんか?
作って終わりじゃないのが業務改善のメンドクサイ所ですよね。。。
今回は、自作アプリの自動アップデート機能の組み方をご紹介します。

前提条件

配布された人たちが全員アクセスできる共有フォルダがあることが条件
※このフォルダを配布先にしておくと便利

組み込み方法

アプリ内定数

まずは、作成するアプリ内に以下の定数を定義します

// バージョン情報
public const string Df_BasePath = @"アプリを置くフォルダのパス";
public const string Df_Version= "01_000";

Df_BasePath
最新バージョンのアプリを配布するフォルダのパスを記入します。
Df_Version
今、作成中のバージョンを記入します。
※このバージョンが「 Df_BasePath 」のパス内にあるファイルと一致していなかったら
 バージョンアップ処理を行う仕様になります。

アプリ起動時の処理

アプリ起動時に以下の処理を行います
①.「 Df_BasePath 」フォルダ存在判定
②.自分のバージョンと配布先のバージョンの一致判定
③.バージョンアップ処理

/*************************************************************************
    【例】フォーム起動時イベント
**************************************************************************/
private void Form1_Load(object sender, EventArgs e)
{
    // ①.フォルダ存在判定  
    if (IsFolderSonzai_Out(Df_BasePath))
    {
        // ②.自分のバージョンと配布先のバージョンの一致判定  
        string basePath = GetAllFileInFolder(Df_BasePath, "exe")[0];
        if (GetFileNameInPath(basePath, true).Split('v')[1] != Df_Version)
        {
            // ③.バージョンアップ処理
            Set_AutoUpdate(Df_BasePath);
            this.Close();
        }
    }
}

以上がイベントの内容です。細かく見ていきましょう。

①.フォルダ存在判定
/// <summary>
/// フォルダ存在判定【タイムアウト付き】
/// </summary>
/// <param name="path">検索されるフォルダパス</param>
/// <returns>検索結果( True = 存在する )</returns>
public static bool IsFolderSonzai_Out(string path)
{
    int i_Wait = 1000;   // この値【ms】だけ処理待ち
    bool exists = true;
    Thread t = new Thread
    (
        new ThreadStart(delegate ()
        {
            exists = Directory.Exists(path);
        })
    );
    t.Start();
    bool completed = t.Join(i_Wait);
    if (!completed)
    {
        exists = false;
        t.Abort();
    }
    return exists;
}

こちらが関数の中身です。
Df_BasePath 」フォルダが存在しない場合はバージョンアップを行いません。
配布先は共有フォルダとなるので、タイムアウト対策は必須です。

②.自分のバージョンと配布先のバージョンの一致判定

バージョンの比較方法ですが、配布先のファイル名にはバージョンを追記しておきます。
【例】ファイル名_v01_001.exe
現バージョンは定数で取得し、最新バージョンはファイル名から取得して比較します。

③.バージョンアップ処理
/// <summary>
/// 自動アップデート処理 ※これ実行した後、自分は閉じないとダメだよ
/// </summary>
/// <param name="PathBase">配布してるフォルダのパス</param>
public static void Set_AutoUpdate(string PathBase)
{
    //ベースパス取得して現階層にコピペ
    string basePath = GetAllFileInFolder(PathBase, "exe")[0];
    string pathAft;
    pathAft = GetFileNameInPath(basePath, false);
    pathAft = GetNowFolderPath() + "\\" + pathAft;
    File.Copy(basePath, pathAft, true);
    // Batファイル出力
    string text = "";
    text += @"@echo バージョンアップ中..." + "\r\n";
    text += @"@echo off" + "\r\n";
    text += @"timeout /t 5 /nobreak > nul" + "\r\n";
    text += @"del " + System.Reflection.Assembly.GetExecutingAssembly().Location + " > nul" + "\r\n";
    text += @"start " + pathAft + "\r\n";
    text += @"del Patch.bat > nul" + "\r\n";
    text += @"exit" + "\r\n";
    StreamWriter sw = new StreamWriter("Patch.bat", false, Encoding.GetEncoding("Shift_JIS"));
    sw.Write(text);
    sw.Close();
    // exe更新
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.FileName = "Patch.bat";
    p.StartInfo.CreateNoWindow = true;
    p.Start();
    p.Close();
    p = null;
}
/// <summary>
/// ファイルのパスからファイル名を取得
/// </summary>
/// <param name="str_Path">パス</param>
/// <param name="IsKillKaku">拡張子を除くか?</param>
/// <returns></returns>
public static string GetFileNameInPath(string str_Path, bool IsKillKaku)
{
    // 「\」で分解してファイル名を取得
    string str_Ret = "";
    string[] str_Sepalate;
    str_Sepalate = str_Path.Split('\\');
    str_Ret = str_Sepalate[str_Sepalate.Length - 1];
    // 拡張子が不要なら除く
    if (IsKillKaku)
    {
        str_Sepalate = str_Ret.Split('.');
        str_Ret = str_Sepalate[0];
    }
    return str_Ret;
}
/// <summary>
/// 実行ファイルのパスを文字列で取得
/// </summary>
/// <returns>実行ファイルのパス ※ファイル名は含まない</returns>
public static string GetNowFolderPath()
{
    string str_Ret = "";
    str_Ret = System.Reflection.Assembly.GetExecutingAssembly().Location;
    str_Ret = GetFilePathFolder(str_Ret);
    return str_Ret;
}

少し長くなりましたがやっていることは簡単です。
・最新バージョンのファイルを起動ファイルと同じ階層にコピペ
・Batファイルを作成→起動
 ▼Batの内容
 ・5秒後に古いバージョンのファイル(起動ファイル)を削除
 ・自分(Batファイル)を削除
・最後に、「 this.Close(); 」で起動アプリを閉じる

以上です。
アプリのアップデート対策は必須なので、
自動アップデートで無駄な管理ヘイトをためないようにしましょう!

【VBA】ADOを利用したExcelアクセス時のエラー対応

Excelの解析にADOを利用したマクロを組んで配布したのですが、
私のPCではちゃんと動くのに、一部の方のPCでは動かない。。。
エラーの内容も三者三葉という気が狂うことがありました。
解決方法が結構斬新な物でしたのでご紹介します。

エラーが起きた環境

PC環境

・Windows10 64bit
Excel 2013 32bit

エラー発生ソース

Function GetFileRead_ADO(s_FilePath As String) As Variant
    ' 変数定義
    Dim strSQL As String
    Dim var_Ret() As Variant
    Dim dbCon As ADODB.Connection
    Dim dbRes As ADODB.Recordset
    ' ADO形式でシート内容取得
    Set dbCon = New ADODB.Connection
    dbCon.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                   "Data Source=" & s_FilePath & ";" & _
                   "Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1;Readonly=False"""
    strSQL = "SELECT * FROM [_ValueManage$]"

    ' 以下割愛・・・
End Function

上記ソースの「 dbCon.Open 」の部分でエラーになっていました。
エラーの内容はバラバラでしたが、エラー発生場所は共通でした。

エラー内容

・オートメーションエラー
・プロバイダーが見つかりません。正しくインストールされていない可能性があります。
・'Open'メソッドは失敗しました

エラー対応内容

CreateObjectを使用しない

参照設定を必要としなくなるのでとても便利なのですが、
ADO利用時にCreateObjectを使用するとエラーが一生直りませんでした。。。
こればっかりは原因が分かりませんでした。
以下は、「エラー発生ソース」のように
CreateObjectを使用しないソースを前提としています。

参照追加しているか確認

とりあえず参照設定を確認しましょう。
下図のチェック項目にチェックが入っているか確認!

f:id:apuridasuo:20200626144339p:plain
図:参照追加する項目

Accsessのインストール

これが驚きだったのですが、エラーの大きな原因が
Accsessがインストールされていない」でした!!
知らないよ!エラーで言え!!!と怒ったのはいい思い出です。
たまたま社内でOfficeのライセンス話があったので各人のインストール状況が
確認出来て「え!?」となって気づけたのですが、神ひらめきだったと自負してます。
という事で、社内に配布した簡単Access導入方法を紹介します。

f:id:apuridasuo:20200626145048p:plain
図:Access導入手順

Officeの修復

Accessの導入でほぼエラー問題は解決しました。
しかし、急にエラーが再発する方がちらほら。
原因は不明なのですが、解決方法は見つかりました。

www.saka-en.com

こちらのサイト様で紹介されている 「 Officeの修復をおこなう
の項目を実行すると、エラーは直りました。
エラーになった方々は直近にVisioをアンインストールした方々ばっかりでした。
おそらくですが、Officeのアプリは色々つながっていて、
一つのアプリをアンインストールすると別のアプリにも影響するのだと思います。

以上、
ADOを利用したExcelアクセス時のトラブルシューティングでした。

P.S.
オートメーションエラー考えたやつ滅びろ!
諦めずに原因教えなさいよ!!!