地上の洞窟

どこにも行かず、液晶と「にらめっこ」し続ける人の物語。

サイト案内

このブログでは、地上に住まう地底人のようなものが
RGSS3の素材を配布してたり、プログラムの話をしたりしています


このブログについて 「地上の洞窟」についてもう少し深く語っています。
RGSS3素材 RPGツクールVXAce」で使えるRGSS3の素材を配布しています。
Compact Audio Player 小さな音楽プレーヤーを配布しています。


更新履歴


2024/08/12

2024/08/07

2024/08/05

2024/05/19

2024/03/02

2024/01/23

【C#】アプリケーションの位置を記憶

アプリケーションの位置を記憶させたい

よく使うアプリケーションは、決まった位置にあると便利。
しかし.NET Frameworkにウィンドウの位置を記憶させるといった設定は無さそうなので
「終了時にアプリケーションの位置を記録」
「起動時にアプリケーションの位置を記録した終了時の位置に移動」
という処理を実装する必要がある。

やり方

アプリケーションの位置というのは、要するに表示しているフォームの位置である。
位置の取得・設定はSystem.Windows.Forms.Controlのプロパティ「Left」「Top」から行う。

終了時: 位置の記憶

FormClosedイベント辺りで取得し、設定ファイルに書き込めばいい。
(設定ファイルへの書き込み処理は各アプリケーションごとにそれぞれあると思うので割愛)
(今回はConfig.StartLocationX, Config.StartLocationYという仮プロパティに記録を行う)

起動時: 位置の設定

初期化時やLayoutイベント辺り*1でプロパティを設定すればいい。
ただし、起動時の位置を設定する場合は併せてStartPositionプロパティをFormStartPosition.Manualに設定する必要がある。

実装

public class TestForm : Form
{
    public TestForm()
    {
        // 起動時
        Left = Config.StartLocationX;
        Top = Config.StartLocationY;
        StartPosition = FormStartPosition.Manual;

        // 終了時
        FormClosed += (s, e) =>
        {
            Config.StartLocationX = Left;
            Config.StartLocationY = Top;
        };
    }
}

画面外へ出てしまう場合の対処

モニター構成の変更などにより、記憶された位置が画面外になってしまう場合がある。
その場合、起動したのに何も表示されないと言ったことが起こる。
ユーザーは大変に混乱するだろうし、画面内への移動も一手間かかる。
そういう場合はプログラム側で位置を修正してあげる方が気が利いていると言えるだろう。

対処法は色々あるが、一つはフォームが表示されているモニターを取得し、そのモニター内の領域に収まるように位置を調整することだろう。
記憶された位置をSystem.Windows.Forms.Screen.FromPoint(Point point)に渡し、フォーム表示予定地のモニターを取得する。
表示領域をScreen.WorkingAreaで取得し、領域内に収まるように値を修正する。

// 起動時
var startX = Config.StartLocationX;
var startY = Config.StartLocationY;
var screen = Screen.FromPoint(new Point(startX, startY));
var area = screen.WorkingArea;

startX = Math.Max(startX, area.Left);
startX = Math.Min(startX, area.Right - this.Width);
startY = Math.Max(startY, area.Top);
startY = Math.Min(startY, area.Bottom - this.Height);

Left = startX;
Top = startY;
StartPosition = FormStartPosition.Manual;

*1:Layoutで実行するのは微妙だった、フォームの最小化最大時にも呼び出されてしまう

Compact Audio Player

小さいけど高機能を目指した「音楽再生ソフト」です。

  • 音声ファイルの再生
  • 再生デバイスを指定して再生
  • イコライザー機能
  • プレイリストの作成、編集、再生

動作環境

本ソフトウェアの使用により発生した損害について、作者は一切の責任を負いかねます。
自己責任での使用をお願いします。

ダウンロード

github.com

配布はGithubにて行っています。各バージョンのAssets内からダウンロード可能です。

更新履歴

2024/08/12 - v1.0.2 「常に手前に表示の設定追加、不具合修正」

  • メニュー[設定][常に前面に表示]を追加
  • ウィンドウの最小化→最大化を行った際、起動時の位置へ移動してしまう不具合の修正
  • メニュー[ヘルプ][バージョン情報]で表示されるウィンドウの位置を修正

2024/08/07 - v1.0.1 「アプリケーションの位置記憶」

  • アプリケーションの位置を記憶するようにした
  • その他、一部の処理を最適化

2024/08/05 - v1.0.0 「公開開始!」

  • 思わせぶりにlangフォルダがありますが、多言語対応はできてません。その内やります

【C#】配列内の要素を移動したい

配列内の要素を移動したい。具体的には

0 1 2 3 4

という並びがあったとしたら、
この内の0番目の要素を2がある位置へ持っていき、その他の順番は保持しておきたい。
つまりは、以下の様にしたい。

1 2 0 3 4

実践

そういうメソッドはあるのかもしれないが、ちょっとC#初心者すぎて見つけられなかったので、適当なメソッドを自作してみた。

private void Move<T>(IList<T> list, int baseIndex, int targetIndex)
{
    var i = baseIndex;
    var moveItem = list[baseIndex];
    if (baseIndex < targetIndex)
    {
        while (i < targetIndex) list[i] = list[++i];
    }
    else
    {
        while (i > targetIndex) list[i] = list[--i];
    }
    list[targetIndex] = moveItem;
}

ちゃんとあってる?(算数があやしい人)

【C#】エクスプローラー順(自然順)の並び替え

ファイルを名前順で並べたい

これは適当なフォルダをエクスプローラーで表示したもの。名前順で並んでいる。
このフォルダのファイルをSystem.IO.Directory.GetFiles(string path)で取得しファイル名を列挙すると、以下の様になる。

hoge1.wav
hoge15.wav
hoge2.wav
hoge4.wav
hoge3.wav

エクスプローラーの表示とは違う順番で並んでいる。
半角の数字から並べて、全角の数字は後で並べたというような順番だ。

普通にソートしてみる

じゃあ、並び替えをすればいいじゃないかとArray.Sortを実行してみると、これまた以下の様になる。

hoge1.wav
hoge15.wav
hoge2.wav
hoge3.wav
hoge4.wav

惜しい。惜しいけど違う。
恐らく全角数字と半角数字での比較もされるようになったのだろうが、二桁の数字をまとめて認識して、この中で15は最後だな、とするような気の利いたことはしてくれない。
同じ番目の文字同士でのみ比較している、所謂「辞書順」というやつだろうか。

自然順で並べる

「辞書式順序」をベースに、二桁以上の数字はまとめて認識して並び替えるようにしたものを
「自然順」と言うようだ。
この自然順の並び替えはWindowsAPIに標準で存在し、以下の様にして簡単に比較クラス(IComparer<string>)を作成できる。

public class NaturalStringComparer : IComparer<string>
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    public static extern int StrCmpLogicalW(string psz1, string psz2);

    public int Compare(string a, string b) => StrCmpLogicalW(a, b);
}

これをArray.SortIEnumerable.OrderByなどに渡して使う。

// Array.Sort
Array.Sort(array, new NaturalStringComparer());

// IEnumerable.OrderBy
array = array.OrderBy(f => f, new NaturalStringComparer()).ToArray();

すると、このようにエクスプローラーと同じ並び順になる。めでたしめでたし。*1

hoge1.wav
hoge2.wav
hoge3.wav
hoge4.wav
hoge15.wav

*1:ただし、今後Windowsの仕様次第でこの並び順が変わる可能性もあるので、並び替え専用のアプリケーションやアルゴリズムには使っちゃやーよ的なことが公式のドキュメントに書いてある

新札のデザイン

お札が変わる

www.npb.go.jp

7月3日から紙幣が変わったそうな。まだ実物は拝んでないのだけれども。
Twitterとかで散々ダサいと言われていたフォントやデザインはそのまんま。
ちょっと残念な気もするが、今後はこいつらがダサくても欲しい物TOP3を占めるだろう。
「ダサくていらないなら貰ってしんぜようぞ!」

ただ、ダサいの一言で片づけるのは乱暴だし言葉不足な気がする。
ではこの新札はなぜダサいと言われてしまうのか、自分なりの分析を記していく。
(ボコボコな批判になってしまったので、新しいお札最高!って人は見ない事推奨。)

続きを読む

【RGSS3】トラベルポイント

トラベルポイントUI
知ってる場所へテレポートができる(ルーラ!

登録された場所へテレポートする画面を追加します。
(動作には「CraftLib」スクリプトが必要です)

スクリプトコマンド一覧

TravelPoint.set(map_id, x, y, name = nil)

マップID、X座標、Y座標、登録名(任意)を指定して、テレポート先を登録します。

TravelPoint.set(6, 21, 33)
TravelPoint.set_player(name = nil)

プレイヤーが現在いる位置をテレポート先として登録します。

TravelPoint.set_player("現在地")
TravelPoint.set_player_target_direction(direction, name = nil)

現在プレイヤーがいる位置から、一歩進んだ地点より、
direction方向に進んだ場所をテレポート先として登録します。

TravelPoint.set_player_target_direction(2)
TravelPoint.delete(map_id, x, y, name)

指定したテレポート先の登録を削除します。
nilを指定した場合、その項目は検索対象にしません。

TravelPoint.delete(5, nil, nil, nil) # マップID:5の登録を全て削除
SceneManager.call(TravelPoint::Scene_TravelPoint)

テレポート先の表示・指定を行うシーンへと遷移します。

SceneManager.call(TravelPoint::Scene_TravelPoint)


更新履歴 バージョン 内容
2024/05/19 v1.0.0 初版

→スクリプト一覧へ

続きを読む