はじめに:操作の手応えは「目に見えること」から始まる
このツールは「動画から特定区間だけを抽出して出力する」ためのものであり、当然ながらユーザーは「どこからどこまで」を視認して操作したくなります。
再生してから「この辺りだな」と目で追い、区間を指定。すると、シークバー上にその範囲が色で反映される。
この仕組みが、このツールに“わかりやすさ”を加えてくれました。
この回では、マーカー描画機能の実装方法と生成AIとのやりとりを詳しく見ていきましょう。
マーカーとは?:シークバー上に描かれる区間インジケーター
このツールには、動画の再生位置を表すシークバー(TrackBar)があります。
その上にオーバーレイとして描画される“マーカー”が以下の3パターンに対応しています:
- 🟧 開始+終了時間あり → 指定区間全体を塗りつぶし(橙色)
- 🟧 開始時間のみ → 開始位置に縦線(橙色)
- 🟧 終了時間のみ → 終了位置に縦線(橙色)
(現在のversionでは要件変更によりこちらを変更しております。)
こうした描画は、DataGridView 上のジョブに登録された時間情報をもとに生成されています。
Copilotに指示した内容
私は生成AIに次のような指示を出しました:
💬「再生位置のバーに、開始/終了時間をマーカーとして描画したい」
💬「開始だけなら線、開始+終了なら矩形塗りつぶしで」
💬「C# 7.3なので using var は使わず、using ブロックで書いて」
Copilotは完璧に意図をくみ取り、以下のような描画コードを生成してくれました。
MarkerOverlay_Paint()
の実装例(C# 7.3対応)
private void MarkerOverlay_Paint(object sender, PaintEventArgs e)
{
if (_mediaPlayer == null || _mediaPlayer.Length <= 0) return;
double totalSeconds = _mediaPlayer.Length / 1000.0;
int width = markerOverlay.Width;
foreach (DataGridViewRow row in dgvJobs.Rows)
{
if (row.IsNewRow) continue;
bool hasStart = TimeSpan.TryParse(row.Cells[0]?.Value?.ToString(), out TimeSpan start);
bool hasEnd = TimeSpan.TryParse(row.Cells[1]?.Value?.ToString(), out TimeSpan end);
int x1 = hasStart ? (int)(start.TotalSeconds / totalSeconds * width) : -1;
int x2 = hasEnd ? (int)(end.TotalSeconds / totalSeconds * width) : -1;
if (hasStart && hasEnd && end > start)
{
using (Brush fill = new SolidBrush(Color.FromArgb(100, Color.Orange)))
{
e.Graphics.FillRectangle(fill, x1, 0, x2 - x1, markerOverlay.Height);
}
}
else if (hasStart)
{
using (Pen pen = new Pen(Color.Orange, 3))
{
e.Graphics.DrawLine(pen, x1, 0, x1, markerOverlay.Height);
}
}
else if (hasEnd)
{
using (Pen pen = new Pen(Color.Orange, 3))
{
e.Graphics.DrawLine(pen, x2, 0, x2, markerOverlay.Height);
}
}
}
}
💡
TimeSpan.Parse
は万が一無効な文字列だった場合に備え、TryParse にしています。
💡
markerOverlay
はTrackBar
と同じ座標・サイズで配置されたPanel
であり、Paint
イベントによりマーカーが描かれます。
視覚的なメリット
- 🟠 分割ジョブが「どこに設定されたか」をすぐに確認できる
- 🟠 開始時間だけ設定 → 縦線で位置が即座にわかる
- 🟠 完全な区間(開始+終了) → 濃淡つき矩形で明確に視認可能
- 🟠 再生バーとの重なりで、現在位置との比較ができる
Copilotがくれたアドバイスの一つに:
「同じオーバーレイパネル上で
Invalidate()
を使えば、スクロールや再生位置の更新時に自動で再描画できますよ」
というものがありました。
実際に、UpdateSlider()
や Scroll
イベントで markerOverlay.Invalidate()
を呼び出すことで常に更新され続けるようになりました。
スライダー移動時の連動描画(補足)
private void Slider_Scroll(object sender, EventArgs e)
{
_mediaPlayer.Time = slider.Value * 1000;
markerOverlay.Invalidate();
}
上記の処理で、スライダーを動かすたびに描画が更新され、マーカー位置と再生位置が同期して見えるようになっています。
描画の拡張案(次回以降も可能)
以下のような発展的機能も、Copilotなら対応してくれそうです:
- 再生位置そのものもマーカーとして描画する(赤線など)
- 現在選択しているジョブを強調表示(太線など)
- ジョブ行のインデックスに応じて色分け
- シークバーの上にラベル(時刻)を表示
Copilotに「マーカーを太くしてラベルを追加して」と伝えれば、すぐにコードを返してくれます。
まとめ:見える化の力とAIの柔軟さ
この回の学びは、機能の視覚化による操作性向上と、それを支える生成AIの柔軟性です。
機能 | 実現手段 | 学び |
---|---|---|
区間マーカー描画 |
Paint イベント+DataGridView |
指定区間の視認性向上 |
再描画制御 |
Invalidate() 呼び出し |
再生中/スクロール時でも更新可能 |
C# 7.3 対応 |
using (...) {} 構文 |
Copilotは言語バージョンに応じて調整可能 |
プロンプトから生成 | Copilotとの対話 | 「こうしたい」がすぐ形になる |
マーカー描画は、分割ツールとしての信頼性を視覚的に高めてくれる要素です。
生成AIがそれを忠実に構築してくれたおかげで、私はC#初心者でも安心してUIの精度向上に集中できました。
次回第6回【ジョブ管理編】
いよいよ分割処理の要となる、「ジョブの登録/編集/削除」機能の詳細に入っていきます。
- 開始時間/終了時間/ファイル名の構成
- 自動的に新しい行に移る設定
- 削除ボタンとイベント処理の組み方
- 一括出力に向けた準備ステップ