ゲームエフェクトデザイナーのブログ | A Real-Time VFX Artist's Blog

About Making Materials on UE, Making Tools with C#, etc

Netflixでの英語学習に英語対応の日本アニメを視聴してみる

英語学習のために動画配信サービスを選択するなら「Netflix」が最も良いかと思います。
英語音声/字幕に対応した動画が多いのもありますが、なんと言ってもGoogle Chromeで利用できる「LLN」が非常に便利だからです。

おすすめの設定は「訳を非表示」をONにしておくことです。

f:id:moko_03_25:20200404162247p:plain

これで日本語訳はボケた状態で表示され‥

f:id:moko_03_25:20200404163859j:plain

日本語訳の部分をクリックすると綺麗に表示されるので答え合わせができます。

f:id:moko_03_25:20200404163906j:plain

SWORD ART ONLINE」1話より ©川原 礫 / KADOKAWA アスキー・メディアワークス / SAO Project

これで英語の勉強が捗る訳ですが‥じゃあ「英語初心者向けの作品は何か?」と思って色々調べると「FRIENDS」とか「FULL HOUSE」を始めとした「Sitcom(Situation comedy)」と呼ばれるホームコメディがよく筆頭に挙げられます。

確かに、比較的簡単な英語でアメリカの生活に根差す文化や日常会話を学ぶ目的としては最適と思いますが、笑いを誘う小洒落た言い回しの応酬がひたすら続くため、純粋にシンプルな英文の学習に向いているかというと、それには不向きな一面もあるかと思います。

一方、Nexflixでは日本の人気アニメが英語音声/英語字幕に対応していたりします。

( ↓ 対応していたのに削除されたものも沢山ありますね‥悲しみ。。)

この日本のアニメの英語対応ですが、残念ながら英語音声と英語字幕が一致しないものばかりです(一致しているものもあるかも知れませんが)。これは下記のような感じがします。

・英語字幕 ‥ 日本語のセリフに近い形で英文に訳されたもの
・英語音声 ‥ 音声収録に伴いより自然な言い回しになったもの

ドイツの海外ドラマ「DARK」も英語音声と英語字幕が一致しませんが、元々英語じゃないコンテンツは翻訳フローが違うのかも知れません。

音声と字幕が一致しないという面はとても残念ですが‥反面、元の日本語のセリフに近い形の英文が表示されるという面では英語初学者の自分にも文章が読み易くてとても良いように思いました。「LLN」も月額が発生するプロ版では機械翻訳の表示が可能になるようですが、元のセリフをそのまま変換したもの方が学習には向いてるのですよね。

それから「LLN」では画面右側に字幕が一覧されますが、マウスドラッグで範囲選択が可能なので、気になった文章はクリップボードにコピーしてGoogle翻訳や今話題の「DeepL」に貼り付けてチェックすることもできます。

f:id:moko_03_25:20200404174140j:plain

SWORD ART ONLINE」1話より ©川原 礫 / KADOKAWA アスキー・メディアワークス / SAO Project
https://www.deepl.com/home

「LLN」では字幕内の単語をクリックするとその場で訳を表示してくれますが、フレーズは自力で調べる必要があるので、こうしてコピペできるのは非常に便利です。

‥という訳で、とりあえず今まで観たことが無かった「ソード・アート・オンライン」をシーズン1(全25話)・シーズン2(全24話)をざっと視聴しましたが、登場する英文が初心者である自分には丁度良い難易度でした。

日本が舞台のアニメだと「いただきます」や「ただいま」など日本の文化ならではのセリフや「総務省〇〇局」「埼玉県埼玉市」「皇居」など日本の固有名詞がどう英訳されるかも学べる面もありますね!

次は「ヴァイオレットエヴァーガーデン」を観たいなと思っています。

簡単な英単語を組み合わせたフレーズ

英語が難しい理由は沢山ありますが、その1つがこちら‥

一見簡単そうなアニメやゲームの英文を読んでも全く知らないフレーズのオンパレードで、1つずつ調べながらだと一向に進まなくて絶望したりします。

とは言え‥文法ルールで解決できる問題では無いので、こればかりはとにかくイメージや使用場面などと一緒に脳内に刷り込ませていくしか無いなと。。

‥という訳で、過去にメモっていたものを並べてみたいと思います。

(It's)a shame(that~) (~について)残念です
(same)as usual / as always / as ever いつも通り
a bit too far 少しやり過ぎる
a series of ~ 一連の~
absolute disaster 全然ダメ(絶対的な災難)
all sorts of ~ あらゆる種類の~
all the time いつも
all together みんなで一緒に, 全部合わせて, 同時に
allow me to do~ ~させてください(let me~より丁寧な言い方)
Apparently, ~ どうやら~らしい
apropos of nothing 突然だけど
as a matter of fact 実のところ
at all ぜんぜん, さっぱり
at face value 表面そのままの意味
at large 逃亡中, 野放し
at the rate someone is going このペースだと
at will 気の向くままに, 思いのままに, 自由自在に
back down 引き下がる
bat an eyelash まばたき一つ
be ashamed of~ ~を恥ずかしがる
be aware  知っている, 気付いている
be better off もっと良くなる
be far too 形容詞 あまりにも~すぎる
be fixing to~ ~するつもり(予定)
be supposed to 〜 〜することになっている, ~するはず
blink of an eye 一瞬
But of course もちろん = Of course
Buzz off. うるさい, どっかいけ
by anyone's standards 誰がどう見ても
can only end one way 先は見えている(行きつくところは1つだけ)
can't afford to lose ~ ~を失うことはできない
can't make heads nor tails of ~が何だかさっぱり分からない
carry out 実行(遂行)する
Catch on? 分かった?
certain 名詞 某〇〇
city folk 都会人
city-state 都市国家
close combat 接近戦
cold shoulder 冷たい態度
come along 一緒に来る
come and get it 食事の用意ができたよ
common sight  ありふれた光景, よく見かける
Copy that. 了解
cover a multitude of sins 多くの(悪い)事をおおい隠す
cut a deal 協定/契約を結ぶ, 取引する
cut it out いい加減にして
cut straight to the point 単刀直入に言う
disagree with 体調を崩す
Don’t let it get to you. ま、気にするなよ
don't go easy on 手加減しない
don't need to concern yourself あなたには関係無い(あなた自身、関与する必要は無い)
Don't tell me~ ~と言わないよね?
drive a hard bargain 商談がうまい, ひどく値切る
dying to + 動詞 ~したくてたまらない
elephant in the room 触れてはいけないもの(タブー)
eons ago 大昔に
even though ~にも関わらず~
fall apart ひっくり返る, バラバラになる, 崩壊する
fall on deaf ears 聞き流される, 無視される
fashion ~ ~を作る ※fashionは流行のファッション
fast friend 親友
figure it out 計算する => 解決する
fireside chat 暖炉を囲んでする(ような)談話
first off まず最初に、とりあえず
for a while しばらくの間
for crying out loud 何てこった, これは呆れた, 全くもう
For God’s sake まったくいい加減にしてくれ
For goodness' sake まったくいい加減にしてくれ
from a distance 遠くから
from time to time 時々
full well 十分に
get back to~ ~に戻る
get carried away 調子に乗る, 夢中になる and~で調子に乗って~した またはwith~で~に夢中になる
get even あいこになる, 五分五分になる
get going さあ行こう
get home 家に帰る
get involved 巻き込まれる involved=関わる, 参加する
get this far こんなに遠くまで来る=ここまで成し遂げる
get used to~ ~に慣れる
give ~ quite a turn ~をひどく驚かせる
give you a heads up 前もって知らせる
go a long way 大きな効果を発揮する
go ahead どうぞ
go back and forth 行ったり来たりする
go out (明かりや火が)消える
Good god(s). なんてことだ
Good grief やれやれ, まったく
Goodness knows 神のみぞ知る
greener pastures より良い環境
had better +動詞の原形 ~した方がいい
hand-to-hand combat 白兵戦
happen to 動詞 たまたま~する 疑問文で「ひょっとして~?」になる
hard luck 不幸
have anything to do with~ ~に関わりがある
have nothing to do with~ ~に関係ない
head-on 真正面から, 面と向かって
hear ya (ya=you) 言いたいことは分かる
heave-ho よいしょ
help out 手伝う
Here's looking at you 君の瞳に乾杯(映画カサブランカのフレーズ)
hold down 押さえる, 組みつく
Hold it right there. ちょっと待ちなさい
hold your horses はやる心を抑えて, 落ち着いて
Hot diggity! やった!
how dare you よくもまあ~できるものだ
I beg your pardon. ごめんなさい(I'm sorry よりも丁寧)
I don't appreciate~ ~はやめて頂きたい(感謝しません)
I fear that ~ 残念ながら~のようだ
I guess not 違うみたい
i hate to do~ ~するのは嫌だけど, ~したくないけど
I mean / You mean つまり(つなぎ言葉)
I will thank you to~ ~してくれるとありがたい
I wonder if ~かな?
I’m a little off 少し調子が悪い
if you don't mind もし差し支えなければ
I'll bet~ きっと~だ(賭けてもいい)
I'm afraid ~ ~を恐れている, 残念ながら~, ~のようだ
I'm afraid not. 残念ながら‥
I'm on pins and needles. そわそわする
I'm stuck. 身動きが取れない, お手上げだ
impossible to tell 分からない / 定かではない
in progress 進行中
in search of ~ ~を探し求めて
in some small way ささやかながら
in the end 最終的に
inner nature 本質
Isn't it obvious? 当たり前でしょう, 決まってるじゃん
Isn't it, though? そうでしょう?(=Do you agree?)
It depends on you あなた次第だ
it would seem そのようだ
It’s settled. これで決まりだ
It's no excuse 全く言い訳にならない
It's no use 仕方がない, 無駄だ
just because~ ただ~なだけで
just say the word いつでも言ってね
keep an eye out 見張る, 警戒する
keep something from ~ ~に隠し事をする
knock it off いい加減にして
know full well 十分に理解している
lack of foresight 先見性の欠如 = 見通しの甘さ
lay on 置く, 用意する, 傷付ける
leave it to me 私に任せて
leave it to~ ~に任せろ
leave out~ ~を忘れる
less of ~ ~を見下す
let down 失望する, 裏切る
let it go to one’s head うぬぼれるな, 調子に乗るな
let's see. えーっと(複数人で話しているとき)
letup / let-up ゆるみ, 休止
light source 光源
like no other 他には無い, 唯一無二の
little wonder さほど不思議ではない
live up to に応える, にふさわしい
living tissue 生きている(生体)組織
lock away しまい込む
look down on~ ~を見下す, 見くびる
look first 最初に検討する
look out 気を付ける / 用心する
made out 作り上げる
make fun of ~ ~をからかう
make it sound~ ~のようなことを言う
make it this far ここまでやり遂げる
make progress 進展する
make sense 理に適う, 筋が通っている
make sure 確認する
Mind you, よく聞いてくれ
much too 形容詞 あまりにも~すぎる(名詞を装飾する場合は too much 名詞 になる)
my icon 私の憧れの人
naked eye 肉眼, 裸眼
night falls 夜になる
no longer もはや~ではない
no point 意味が無い no point ~ing ~していても意味がない
No way! ありえない!, とんでもない!
nodding off うたた寝, 居眠り
nose into でしゃばる, 首を突っ込む
not hald bad そんなに悪くない, なかなかのもの
not last long 長続きしない
of all days よりによって today of all days = よりによって今日
of them all 全ての中で~
on one's way out ~ ~を出る途中
on one's way to ~ ~へ行く途中
on the agenda 議題に予定されている
on top of that 挙句の果てに
One good turn deserves another. 一つの良い行為はもう一つの良い行為を受けるに値する(ことわざ)
one of you 誰か一人
orderly fashion 整然と行う
out there 外 / 屋外, 世の中
Out with it! 言ってしまえ!, 話せ!
over my head チンプンカンプン
over time 時間とともに
pay no attention to~ ~に注意を払わない
perk up 元気を出す
pick on ~をいじめる
piece of cake 簡単, 楽勝
play dumb とぼける
point out 指示する, 指摘する
Pray ~ どうか~(pray = 祈る)
pride and joy 自慢の宝
pull yourself together 気を取り直して, しっかりして
put it all together 全てをまとめる, 冷静さを取り戻す
put it that way そんな風に言う
right off すぐに, 直ちに
rule over 支配する
run into~ ~に偶然出会う, ~とばったり会う
run off 走り去る, 逃げ去る
second thought 考え直す, 気が変わる, 二の足を踏む
See? 分かった?
set off 出発する, 作動する, 打ち上げる, 引き金になる, 逆鱗に触れる, 着想を与える, 引き立たせる, 相殺する, 区切る
short on staff / short of staff 人手が足りない
shut down 停止, 休止
Some might say~ 誰かが~と言うかも知れない
sooner or later 遅かれ早かれ
spot you out あなたを見つけ出す
stand for を表す
stand on your way あなたの行く手を遮る
starry-eyed うっとりしている(目がキラキラしている)
step aside 脇へ寄る=身を引く
sticking out 突き出ている
such a big deal そんな大したこと
tag along ついて行く, 付き添う
talk one's ear off 一方的に喋る
thank heavens ~ ~で良かった, ~でありがたい
That should do it. それで十分
That's more like it. そうこなくっちゃ
the daylights out of ~をひどく~する
The very idea. ひどい ※good ideaの逆の意味になる
The world's only~ 世界で唯一の~
then and only then その時になって初めて
think highly of each other お互いに尊敬している
This is gone far enough. これはやり過ぎだ
this won't do. これは良くないな
Tip-top 最高の, 万全の
to my surprise 驚いたことに
to this end その目標に向かって = そのために
too bad 残念
tuck you in 寝かしつける
turn to ~に頼る
upper hand 優位, 優勢
upside down 逆さまに
upsy-daisy よいしょ
wash up 疲れ果てさせる, ボロボロにする
way out 出口, 脱出方法, 解決法
what in the world 一体全体
What is he up to? 彼は何をしているのか?
Whatever~ 一体何を~, どんなに~でも
what's cooking どうしたの?
what's the use of ~ing? ~して何になるのか?
where one left off 中断したところ(‥から再開する、など)
whip up ~ ~を作る ※whipは鞭のウィップ
Why not ~ なぜ~しないのか?, もちろん~する, ~してみては?
-wise ~のように(manhood-wise = 男らしい)
with pleasure 喜んで, かしこまりました
Without a doubt. 疑いない(間違いない)
work out 解決する, 解明する, 練習する, 算出する, 抜け出る, 切り拓く
worth one's salt 給料に値する働きをする = 有能である
would that work うまくいく
You bet. もちろん
you don't say ほんとに?, まじか
you name it ありとあらゆるもの
You up there (上にいる)そこのあなた
You've got it all wrong. あなたは全く誤解している
比較級 and 比較級 ますます~

 

これらフレーズはその時プレイしていたゲームや観たアニメで登場してたまたま知った&調べたものだけをピックアップしています。それでも大量に遭遇しました。

ただ並べただけでは見辛いので、ゆくゆくは分類していきたいところです。。

C# フォームで動画再生

Windows Media Playerのコントロールを利用する形で試してみました。
f:id:moko_03_25:20200329023827p:plain

利用すると言えどもやらないといけないことは色々あります。
・動画を開くボタンを追加、アイコンを作成して設定
・ショートカットキーによる再生/停止、コマ送り/戻し
・ショートカットキーによる動画サイズ変更
・フルスクリーン時にショートカットキーを受け付ける
・ボリューム設定の記憶と復元
・リピート再生(未実装)
・動画ファイルのドラッグ&ドロップ対応(こちらは継承しての拡張が必要なため未実装)
区間再生(UIが絡んで悩ましいため現状未実装)

以前調べたときのものはこちら。
effect.hatenablog.com


以下はお世話になった記事(感謝です!)。
AxWindowsMediaPlayer | C# プログラミング解説
c#.netでWindowsMediaPlayerコントロールを使って動画プレイヤーを作成する。 - 中堅プログラマーの備忘録
axWindowsMediaPlayerでコマ送りをするには?

試した際のソースコードはこちらのような感じ。

using System;
using System.IO;
using System.Windows.Forms;
using WMPLib;

namespace VideoPlayer
{
	public partial class Form1 : Form, IMessageFilter
	{
		string videoPath, videoTitle;
		WMPPlayState videoState;
		int srcWidth = 0;
		int srcHeight = 0;
		double loopSta = 0.0;
		double loopEnd = 0.0;
		bool ready = false;

		public Form1()
		{
			InitializeComponent();
			//wmpVideo.uiMode = "none";

			this.KeyPreview = true;
			wmpVideo.AllowDrop = true;
			wmpVideo.enableContextMenu = false;
		}

		// ロード時
		private void Form1_Load(object sender, EventArgs e)
		{
			// アプリケーションの設定を読み込む
			Properties.Settings.Default.Reload();

			try
			{
				wmpVideo.settings.mute = Properties.Settings.Default.isMute;
				wmpVideo.settings.volume = Properties.Settings.Default.volume;
			}
			catch (Exception)
			{

			}
		}

		// 終了時
		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			try
			{
				Properties.Settings.Default.isMute = wmpVideo.settings.mute;
				Properties.Settings.Default.volume = wmpVideo.settings.volume;
			}
			catch (Exception)
			{

			}			

			// アプリケーションの設定を保存する
			Properties.Settings.Default.Save();
		}

		// フルスクリーンモード時にキーを受け付けるためのもの
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			Application.AddMessageFilter(this);
		}
		protected override void OnFormClosing(FormClosingEventArgs e)
		{
			base.OnFormClosing(e);
			Application.RemoveMessageFilter(this);
		}
		public bool PreFilterMessage(ref Message m)
		{
			const int WM_KEYDOWN = 0x100;
			if (m.Msg == WM_KEYDOWN)
			{
				Keys keyCode = (Keys)m.WParam & Keys.KeyCode;
				if (keyCode == Keys.Escape)
				{
					this.wmpVideo.fullScreen = false;
					this.ActiveControl = this.wmpVideo;
					return true;
				}
				else if (keyCode == Keys.D1)
				{
					this.wmpVideo.fullScreen = false;
					this.ActiveControl = this.wmpVideo;
					changeScreen(1);
					return true;
				}
				else if (keyCode == Keys.D2)
				{
					this.wmpVideo.fullScreen = false;
					this.ActiveControl = this.wmpVideo;
					changeScreen(2);
					return true;
				}
				else if (keyCode == Keys.D3)
				{
					this.wmpVideo.fullScreen = false;
					this.ActiveControl = this.wmpVideo;
					changeScreen(3);
					return true;
				}
			}
			return false;
		}

		// ショートカットキー
		private void WmpVideo_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
		{
			if (ready)
			{
				// 動画の状態を更新
				videoState = wmpVideo.playState;

				// スペースキー
				if (e.KeyCode == Keys.Space)
				{
					if ("wmppsPlaying" == videoState.ToString())
					{
						wmpVideo.Ctlcontrols.pause();
					}
					else if ("wmppsPaused" == videoState.ToString())
					{
						wmpVideo.Ctlcontrols.play();
					}
				}
				else if (e.KeyCode == Keys.E)
				{
					// 一時停止
					wmpVideo.Ctlcontrols.pause();

					// コマ送り
					((IWMPControls2)wmpVideo.Ctlcontrols).step(1);
				}
				else if (e.KeyCode == Keys.W)
				{
					// 一時停止
					wmpVideo.Ctlcontrols.pause();

					// コマ戻し
					((IWMPControls2)wmpVideo.Ctlcontrols).step(-1);
				}
				else if (e.KeyCode == Keys.OemOpenBrackets)
				{
					// 現在の再生位置を取得
					loopSta = wmpVideo.Ctlcontrols.currentPosition;
				}
				else if (e.KeyCode == Keys.OemCloseBrackets)
				{
					// 現在の再生位置を取得
					loopEnd = wmpVideo.Ctlcontrols.currentPosition;
				}
				else if (e.KeyCode == Keys.D1)
				{
					changeScreen(1);
				}
				else if (e.KeyCode == Keys.D2)
				{
					changeScreen(2);
				}
				else if (e.KeyCode == Keys.D3)
				{
					changeScreen(3);
				}
				else if (e.KeyCode == Keys.D4)
				{
					// フルスクリーン
					wmpVideo.fullScreen = true;
				}
			}
		}

		// ドラッグ&ドロップ
		private void Form1_DragEnter(object sender, DragEventArgs e)
		{
			// コントロール内にドラッグされたとき実行される
			if (e.Data.GetDataPresent(DataFormats.FileDrop))
				// ドラッグされたデータ形式を調べ、ファイルのときはコピーとする
				e.Effect = DragDropEffects.Copy;
			else
				// ファイル以外は受け付けない
				e.Effect = DragDropEffects.None;
		}
		private void Form1_DragDrop(object sender, DragEventArgs e)
		{
			// コントロール内にドロップされたとき実行される
			// ドロップされたすべてのファイル名を取得する
			string[] fileName =
				(string[])e.Data.GetData(DataFormats.FileDrop, false);
			
			// 動画のファイルパスを取得
			videoPath = fileName[0];
			videoTitle = Path.GetFileName(videoPath);

			setUpValue();
		}

		// マウスクリックで再生/一時停止をトグル
		private void WmpVideo_ClickEvent(object sender, AxWMPLib._WMPOCXEvents_ClickEvent e)
		{
			if (ready)
			{
				// 動画の状態を更新
				videoState = wmpVideo.playState;

				if ("wmppsPlaying" == videoState.ToString())
				{
					//wmpVideo.Ctlcontrols.pause();
				}
				else if ("wmppsPaused" == videoState.ToString())
				{
					//wmpVideo.Ctlcontrols.play();
				}

				//srcWidth = wmpVideo.currentMedia.imageSourceWidth;
				//srcHeight = wmpVideo.currentMedia.imageSourceHeight;
				//MessageBox.Show(srcWidth.ToString() + " : " + srcHeight.ToString() + "\r\n" +
					//"Form " + this.Width.ToString() + " : " + this.Height.ToString() + "\r\n" +
					//"Screen" + wmpVideo.Width.ToString() + " : " + wmpVideo.Height.ToString());
			}
		}

		// ボタンのアイコン差し替え
		private void BtnOpenVideo_MouseEnter(object sender, EventArgs e)
		{
			btnOpenVideo.BackgroundImage = Properties.Resources.Icon_Open_on;
		}
		private void BtnOpenVideo_MouseLeave(object sender, EventArgs e)
		{
			btnOpenVideo.BackgroundImage = Properties.Resources.Icon_Open;
		}

		// 開くボタン
		private void BtnOpenVideo_Click(object sender, EventArgs e)
		{
			OpenFileDialog openFileDialog = new OpenFileDialog() { Multiselect = false, Filter = "MP4 File|*.mp4|All File|*.*" };
			if (openFileDialog.ShowDialog() == DialogResult.OK)
			{
				videoPath = openFileDialog.FileName;
				videoTitle = openFileDialog.SafeFileName;

				setUpValue();
			}
		}

		// 動画を開いた際の準備
		public void setUpValue()
		{
			wmpVideo.URL = videoPath;
			this.Text = videoTitle;
			ready = true;
		}

		// 動画サイズを変える
		public void changeScreen(int sizeID)
		{
			wmpVideo.fullScreen = false;
			wmpVideo.stretchToFit = true;

			srcWidth = wmpVideo.currentMedia.imageSourceWidth;
			srcHeight = wmpVideo.currentMedia.imageSourceHeight;

			switch (sizeID)
			{
				case 1:
					this.Width = (srcWidth / 2) + 16;
					this.Height = (srcHeight / 2) + 39;
					break;

				case 2:
					this.Width = (srcWidth) + 16;
					this.Height = (srcHeight) + 39;
					break;

				case 3:
					this.Width = (srcWidth * 2) + 16;
					this.Height = (srcHeight * 2) + 39;
					break;

				default:
					break;
			}
		}
	}
}

「C#」の記事一覧

C#.NET frameworkを使ったWindows Forms Aplicationと、制作時のちょっとしたTIPSメモのメニューになります。

作ったツール


C# リスト管理できるテキストエディタ「List Fusen」を制作&リリース
C# UE4のアセットの命名規則チェックツールを作ってみた
C# 線グラデーション画像を作成するツール
BMP画像に保存された色の値を調べる
C# よく使う文字列をコピペするための補助ツール
C# ファイルパス・フォルダパスをリストアップするツール
C# タスクスケジューラへタスクを登録するツール
C# UE4のフォルダカラーを設定するリストを作成するツール
C# 英単語を覚えるためのツール「English Words Check Tool」を公開しました!
リスト管理できるテキストエディタ「List Fusen」がバージョン2になりました!
Windows用タスク管理アプリ『TaskQuest』について
Tenpu Gazo Maker をリリースしました!


入門


C#のはじめ方
C# ソリューションの基本的なファイル構成について
C# WindowsFormのコントロールの概要

C# Formの主なプロパティ
C# Labelの主なプロパティ
C# ComboBoxの主なプロパティ
C# DataGridViewの主なプロパティと関数
C# TreeViewの主なプロパティ
C# PictureBoxの主なプロパティ


入門の次のステップ


C# 初心者の次のステップ
GitHubでのツールやソース公開について(CGアーティスト向け)
ライセンスについてのメモ
C#でWPFを始める
C#を覚えてからC++を始めたときのメモ


テキスト


C#で正規表現による置換を行う
C# TreeViewのノードに対応した文字列をTextBoxに表示する
C# XMLファイルを読み込んでTreeViewにノードを追加する
C# XMLへの階層構造の保存メモ1(基本編)
C# XMLへの階層構造の保存メモ2(TreeView編)
C# XMLへの階層構造の保存メモ3(TreeView編)
C# TreeViewの親子階層内で指定のノードを選択する
C# テキストの暗号化と複合の方法について
C# RPG風にテキストメッセージを1文字ずつ表示させる
C# WordドキュメントをMarkdownに変換したい


ファイル


C#でサブフォルダをリストアップ
C#でサブフォルダの総サイズのリストアップ(ListBox編)
C#でサブフォルダの総サイズのリストアップ(DataGridView編)


データベース


C# Listの中身をDataGridViewに追加する方法
C# DataGridViewでの値のコピー&ペーストの実装
C# DataGridViewの表示がおかしくなった時の対処法
C# DataGridViewのソートとフィルタのサンプル
C# DataGridViewにDataTableをデザイナでバインドしている際のフィルタのサンプル
C# DataGridViewにDataTableをデザイナでバインドしている際に列を名前で指定する
C# DataGridViewの列の値に0から始まる番号を入力する
C# タスクをリスト管理するツールの基礎となるサンプルデータを公開


画像 / 動画


C# PictureBoxを2つ重ねるサンプル
C# 画像にラインを引く
C# 画像にラインを引く際にShiftキーで垂直/水平に補正する
C# 画像にラインを引く際にShiftキーで45度に補正する
C# 画像に選択範囲のような枠線を引く
C# ハイトマップからノーマルマップを生成してみた
C# フォームで動画再生
動画再生プレイヤーを作りたいメモ


3D


C#で3Dモデルを表示したい場合の方法メモ
C# 多角形の3Dモデルの描画
C# 穴の空いた多角形の3Dモデルの描画
C# 穴の空いた多角形の3Dモデルにテクスチャを貼ってみた


フォーム / コントロール


C# コントロールの表示をボタンで切り替える
C# Buttonコントロールの枠線を消す方法
C# スペースやEnterキーでボタンを反応させない
C# Formから別のFormを作成する
C# フォーム作成時の最小サイズは136*39
C# スペースキー+マウスドラッグでスクロールを制御する1
C# スペースキー+マウスドラッグでスクロールを制御する2


Twitter


C# Twitterアプリを作ってみる1
C# Twitterアプリを作ってみる2

その他


C# カラー管理クラスを考える
C# Visual Studioで設定したマルチアイコンでサイズ別に古い画像が残る現象
WPF導入に良さそうな情報まとめ 
Making of TaskQuest
Making of TaskQuest<実装編>

C# スペースキー+マウスドラッグでスクロールを制御する2

前回の記事の続きです。
effect.hatenablog.com

すでに事前準備ができているので、あとはスクロールバーの制御の部分を実装するだけです。
考え方としては、PictureBox の「MouseDown」「MouseMove」「MouseUp」のイベントでマウスドラッグを判定して、ドラッグ中にスペースキーを押している状態であればPanelのスクロールバーを動かすという感じです。
「MouseMove」はただマウスを動かしているだけの時も反応してしまうので「MouseDown」と「MouseUp」を組み合わせる必要が出ます。ここは少々不便な点ではあります。

具体的な記述方法についてはこちらの記事を参考にさせていただきました。
codepanic.itigo.jp

という訳で無事に動作しました!

f:id:moko_03_25:20200314212815g:plain

ソ-スコードは以下のような感じです。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Sample_NoFocusedButton
{
	public partial class Form1 : Form
	{
		bool isDragging = false;
		bool downSpaceKey = false;
		Point posStart;


		public Form1()
		{
			InitializeComponent();
		}

		// フォームロード時
		private void Form1_Load(object sender, EventArgs e)
		{
			// サンプル画像を PictureBox に読み込む
			Bitmap b = new Bitmap(@"sample.png");
			pictureBox1.Image = b;
		}

		// ボタンクリック時
		private void Button1_Click(object sender, EventArgs e)
		{
			// ボタンを押した後にスペースキーでボタンをクリックさせない対処
			ActiveControl = null;
		}

		// スペースキーを押した時
		private void Form1_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Space)
			{
				pictureBox1.Cursor = Cursors.Hand;
				downSpaceKey = true;
			}
		}

		// スペースキーを離した時
		private void Form1_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Space)
			{
				pictureBox1.Cursor = Cursors.Default;
				downSpaceKey = false;
			}
		}

		// マウスクリック時
		private void PictureBox1_MouseDown(object sender, MouseEventArgs e)
		{
			isDragging = true;
			posStart = e.Location;
		}

		// マウスドラッグ時
		private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
		{
			if (isDragging && downSpaceKey)
			{
				Point pos = new Point(
					e.Location.X - posStart.X,
					e.Location.Y - posStart.Y);

				panel1.AutoScrollPosition = new Point(
					-panel1.AutoScrollPosition.X - pos.X,
					-panel1.AutoScrollPosition.Y - pos.Y);
			}
		}

		// マウスドラッグ終了時
		private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
		{
			isDragging = false;
		}
	}
}

C# スペースキー+マウスドラッグでスクロールを制御する1

フォーム上に配置したPictureBoxに大きな画像を読み込んだ際に、PictureBox内でスペースキーを押しっぱなしにしている間、マウスドラッグでスクロールバーを制御できるようにするための準備についてメモしておきたいと思います。

まずはPctureBoxで画像を表示した際に、画像が大きい場合にスクロールバーが表示されるようにします。
PictureBoxにスクロールバーが存在しないため、Panelを利用する必要があります。
具体的には以下のように設定。

・フォームにPictureBoxの親となるPanelを配置
 PictureBoxを表示したい位置/サイズにして AutoScroll を True にする
・Panel内にPictureBoxを配置
 SizeMode を AutoSize にする

次に、ボタンを押すとフォーカスがボタンに移り、スペースキーを押すとボタンが反応してしまう挙動を解消する必要があります。
この方法については前回の記事をご覧ください。

ではスペースキーを押した際にPictureBox内でのみマウスカーソルが手のひらアイコンになるようにします。
丁度システムカーソルに手のひら状態が存在するので、そちらを利用します。
具体的な方法はdobon.netさんの記事を参考にさせていただきました。
システムカーソルを取得する - .NET Tips (VB.NET,C#...)

ちなみに最初、「PictureBox1_Mouse_Enter」と「PictureBox1_Mouse_Leave」のイベントでカーソルのアイコンを変えようとしていましたがなぜかうまくいきませんでした。
そこで Form1 の KeyPreview を True にしてキーイベントをフォームが受け取るようにし、「Form1_KeyDown」と「Form1_KeyUp」で pictureBox1 のカーソルが変化するように指定することでうまくいきました。
KeyPreviewについてはこちらの記事で解説されています。
KeyPressなどのキーイベントをすべてフォームが受け取るようにする - .NET Tips (VB.NET,C#...)


実行してみると、うまく動作しています!
f:id:moko_03_25:20200314204844g:plain

ソースコードは下記のような感じです。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Sample_NoFocusedButton
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		// フォームロード時
		private void Form1_Load(object sender, EventArgs e)
		{
			// サンプル画像を PictureBox に読み込む
			Bitmap b = new Bitmap(@"sample.png");
			pictureBox1.Image = b;
		}

		// ボタンクリック時
		private void Button1_Click(object sender, EventArgs e)
		{
			// ボタンを押した後にスペースキーでボタンをクリックさせない対処
			ActiveControl = null;
		}

		// スペースキーを押した時
		private void Form1_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Space)
			{
				pictureBox1.Cursor = Cursors.Hand;
			}
		}

		// スペースキーを離した時
		private void Form1_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Space)
			{
				pictureBox1.Cursor = Cursors.Default;
			}
		}
	}
}


続きはこちら!
effect.hatenablog.com

C# スペースやEnterキーでボタンを反応させない

ボタンを押すと、TabStopを無効にしていたとしてもそのボタンにフォーカスが移りますが、するとスペースキーやEnterキーを押すとそのボタンをクリックするという困った仕様があります。
これは大体の場合に問題ですし、特にスペースキーを何かの機能のショートカットキーとして使いたい場合に厄介です。

例えば、スペースキーを押しっぱなしするとカーソルガ手のひらのアイコンになって、スクロールバーが出ているコントロールのスクロールを制御できる機能(Photoshopの手のひらツールみたいな)を実装したいと思った時に困りました。

標準のボタンではフォーカスを無効にするプロパティは表に出ておらず、ボタンコントロールを継承して無効に設定したボタンを作ってやる必要があるようです。
そこでこちらの記事と質問サイトを参考に試してみました。
フォーカスを受け取らないボタンを作成する - C#プログラミング
フォームが来ないボタン

結果から言うとダメだったのですが、一応試した際のコードを載せておきます。

試してみた時のフォームの外観はこちらのような感じ。
「button1」と「picturebox1」を配置した状態です。
f:id:moko_03_25:20200314193557p:plain

▼Form1.cs

using System;
using System.Windows.Forms;

namespace Sample_NoFocusedButton
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}
	}

	public partial class NoFocusedButton : Button
	{
		public NoFocusedButton() : base()
		{
			SetStyle(ControlStyles.Selectable, false);
		}
	}
}


▼Form1.Designer.cs のButton1の生成部分をこちらのように書き換えてみたもの。

/// <summary>
/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
/// コード エディターで変更しないでください。
/// </summary>
private void InitializeComponent()
{
	this.button1 = new Sample_Sample_NoFocusedButton.NoFocusedButton();
	this.panel1 = new System.Windows.Forms.Panel();
	this.pictureBox1 = new System.Windows.Forms.PictureBox();
	this.panel1.SuspendLayout();
	((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
	this.SuspendLayout();


コメントで書かれているようにForm1.Designer.cs の内容をコードエディタで変更するのは良くないようなので、ユーザコントロールとして新規追加してビルドし、フォームデザイナ上に配置してあげる方が良いと思います。


さて、こちらは「試してダメだった」のですが、じゃあどうやって解決したかというと、下記のコードのようにアクティブコントロールNull を設定してやることでフォーカスを解除しました。
ちょっと強引な方法ですが、フォーカスが解除されて問題ない状況なら有効ではと思います。そもそもTabキーでフォーカスを変えられない別のコントロール(この事例だとpicturebox1)にフォーカスを移してやるのでもうまくいきました。

▼Form1.cs

using System;
using System.Windows.Forms;

namespace Sample_NoFocusedButton
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		private void Button1_Click(object sender, EventArgs e)
		{
			ActiveControl = null;
		}
	}
}


スマートではないですが、とりあえずそんな方法もあるということで。。
何か良い解決法をご存じの方はコメント欄で教えていただけると助かります!

C# PictureBoxを2つ重ねるサンプル

フォーム上でPictureBoxを2つ重ねて、下のレイヤーは背景用・上のレイヤーは透明にして一部だけ描画したい場合があると思います。
(画像を読み込んでトリミングするために選択範囲を描画したい場合など)

こちらが実際にスクリーンショット画像を取り込んでPictureBox1に表示し、PictureBox2で赤いラインを引くのを試してみてうまくいった状態になります。
f:id:moko_03_25:20200311232257j:plain

しかし落とし穴がいくつかあるのでメモしておきたいと思います。

まずForm1上にPictureBox1を置いて想定する位置に配置し、PictureBox2は小さくても良いのでLocationを 0, 0 にしておきます。
f:id:moko_03_25:20200311232250j:plain

またPictureBox2のBackColorは「Color.Transparent」にして背景を透明にしますが、透明にならない場合はコントロールの親子の設定が関係してくるようです。なのでフォームのロードイベントで「pictureBox2.Parent = pictureBox1;」のように設定しています。
この点に関してこちらの記事を参考にさせていただきました。
ossannt.hatenablog.com

この時、PictureBox2はPictureBox1の 0, 0 を原点とした位置に移動します。
そこで2つピッタリ重ねるために先ほど書いたようにあらかじめPictureBox2のLocationを 0, 0 に設定しています。
最初はフォームのロードイベントでLocationが 0, 0 にするよう試しましたがダメでした(もしかしたら親子付けする前に移動すれば良かっただけかも‥)。

実際のソースコードはこちらのような感じです。
PictureBox1のサイズが固定である前提の書き方になっていますが、変動する場合はPictureBox1のSizeChangedイベントでPictureBox2のサイズが連動するように書くと良いです。

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace SampleDoubleDraw
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		// 変数
		Point startPoint;
		Point endPoint;
		Bitmap canvas;
		Graphics g;
		Pen linePen;

		// Formロード時
		private void Form1_Load(object sender, EventArgs e)
		{
			LoadSampleImage();

			// PictureBox2の設定
			pictureBox2.Parent = pictureBox1;
			pictureBox2.Width = pictureBox1.Width;
			pictureBox2.Height = pictureBox1.Height;

			// サイズだけ指定して透明のキャンバスにする
			// pictureBox1のサイズで生成する
			canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);

			// ImageオブジェクトのGraphicsオブジェクトを作成
			g = Graphics.FromImage(canvas);

			// Penオブジェクトの作成
			linePen = new Pen(Color.Red, 4);

			// スタイルを指定
			linePen.DashStyle = DashStyle.Solid;
		}

		// マウスクリック時
		private void PictureBox2_MouseDown(object sender, MouseEventArgs e)
		{
			// カーソルの開始座標を取得
			startPoint = CursorPos();
		}

		// マウスドラッグ時
		private void PictureBox2_MouseMove(object sender, MouseEventArgs e)
		{
			// マウスの左ボタンが押されている場合のみ処理
			if ((Control.MouseButtons & MouseButtons.Left) == MouseButtons.Left)
			{
				// カーソルの終了座標を取得
				endPoint = CursorPos();

				// 描画
				DrawLine();
			}
		}

		// マウスドラッグ終了時
		private void PictureBox2_MouseUp(object sender, MouseEventArgs e)
		{
			// 何か処理が必要であれば書く
		}

		// 関数:ラインを描画
		private void DrawLine()
		{
			// 前回のライン描画を一旦クリア
			g.Clear(Color.Transparent);

			// ラインを描画
			g.DrawLine(linePen, startPoint, endPoint);

			// PictureBox2に表示
			pictureBox2.Image = canvas;
		}

		// 関数:カーソル位置を取得
		private Point CursorPos()
		{
			// 画面座標でカーソルの位置を取得
			Point p = Cursor.Position;
			// 画面座標からコントロール上の座標に変換
			Point cp = pictureBox2.PointToClient(p);

			return cp;
		}

		// 関数:サンプル画像を読み込んで表示
		private void LoadSampleImage()
		{
			Bitmap b = new Bitmap(@"sample.png");
			pictureBox1.Image = b;
		}
	}
}


マウスドラッグで選択範囲(ラバーバンド)を描画する場合に、前のフレーム結果にそのまま合成すると選択範囲の描画が残って重なっていってしまいます。そこで選択範囲を描画する前のImageを取得しておいて毎フレームPictureBoxを上書きしてから選択範囲を描画することでカバーすると、非常に重くなります。Winfows Formsは古いライブラリでありGPUを利用しないからと思われます。

この場合、OpenCLの利用やWPFに乗り換えるといった手があるようですが、今回のPictureBoxを2枚重ねる方法でかなり快適になりました。
f:id:moko_03_25:20200312021211g:plain

しかし限界を感じてきています。
そろそろWPFに手を出す時期か。。

Tenpu Gazo Maker をリリースしました!

矩形範囲でスクリーンショットを撮れて、ちょっとした画像編集が可能なツールです。 f:id:moko_03_25:20200311032315g:plain

GitHubにアップしています。
binaryフォルダ内にある「TenpuGazoMaker_v1xx.zip」にツール本体の実行ファイルが入っていますので、こちらをクリックして飛んだ先の「Download」ボタンからDLしてお使いください。

ライセンスは MIT License です。

使い方は各ボタンにカーソルを置くと表示されるツールチップをご覧ください。
不具合があったらtwitter(@moko_03_25)等でお知らせいただけると助かります!

Tenpu Gazo Maker の特徴


●画像取り込み

・デスクトップの矩形キャプチャ
 キャプチャフレームを表示して枠内を取り込めます。
 フレームをアクティブにした状態で‥
  矢印キー    ‥ 移動
  Shift + 矢印キー ‥ 10単位で移動
  Ctrl + 矢印キー  ‥ サイズ変更
  Shift + Ctrl + 矢印キー ‥ 10単位でサイズ変更

クリップボードから画像のペースト
・画像をドラッグ&ドロップで放り込み

●画像のちょっとした編集

・枠線をボタン1発で付ける(白い背景の時などに)
・選択範囲をトリミング
・選択範囲の枠を塗る
・ライン描画モードで直線を引ける
 矢印付きのラインも可能

●そのほか

・画像をクリップボードへコピー
・画像をPNGで出力
・Undo/Redo
・各アイコンはショートカットキーで実行可能

既知の不具合


・右クリックで表示するミニ設定ウインドウが消えない時がある
 ※何度かマウスカーソルを行き来すると消えますが原因不明‥

更新履歴


・2020.03.11 v.1.00 リリース!

・2020.03.12 v.1.01
 選択範囲やラインの描画の処理落ちを大幅に改善

・2020.03.13 v.1.02
 横スクロールバーが表示されない不具合を修正
 ライン描画時のみアンチエイリアスを有効化
 Ctrl+Vでクリップボードから画像を取り込むよう変更
 Ctrl+Dでキャプチャ枠から背景画像を取り込むよう変更
 Escで設定画面を表示
 設定画面の表示位置とデザインを少し修正
 ツール下部に枠線カラーと直線カラーを表示
 ツールチップの説明を拡充

・2020.03.13 v.1.03
 色設定を変えた際にツール下部のカラー表示が更新されない不具合を修正

・2020.03.14 v.1.04
 スペースキー+マウスドラッグによる表示画像のスクロールを追加

・2020.03.15 v.1.05
 選択範囲の枠の描画時に角に隙間ができる不具合を修正
 画像上で右クリックすることでミニ設定ウインドウを表示
 マウスオーバーでアイコン画像を変更

・2020.03.17 v.1.06
 ラインモード時に一度ラインを引くとカーソルが戻る不具合を修正
 英語/日本語の切り替え表示に対応(ツールチップとエラーメッセージ)

・2020.03.28 v.1.07
 画像を閉じた時にサイズ表示が残る不具合を修正
 ライン描画モードをOFFにしてもカーソルアイコンが戻らない不具合を修

・2020.09.20 v.1.08
 画像の拡大縮小機能を追加
 何も画像が無い時に画像出力を行うとクラッシュする不具合を修正
 設定画面でEnterキーを押した際にビープ音を鳴らさないよう修正 

・2021..08.30 v.1.09
 キャプチャフレームの移動とサイズ変更のショートカットを追加
 (Shift押しながらで10倍の移動とサイズ変更が可能) 

 

作者 / 著作権


moko

動作確認済みのOS


Windows10(64bit)

使用条件


本ツールはOSSオープンソース・ソフトウェア・ライセンス)です。
商用・非商用に関わらず(プライベートでもお仕事でも)ご自由にお使いください。
複製、改変、再配布も自由です。

免責事項


本ソフトウェアは予告なく機能を変更することがあります。
本ソフトウェアは動作環境を満たす全ての環境で正常に動作することを期待していますが、保証はできません。
本ソフトウェアの使用により生じたいかなる損害に関して、作者は一切の責任を負いません。

C# フォーム作成時の最小サイズは136*39

フォームオブジェクトを作成する際には、どうもサイズ制限があるようです。

こちらの図ではボタンを押したらメインフォームの下に子フォームを生成していますが、その際に大きさを30*30に指定してから生成しています。

form.Width = 30;
form.Height = 30;
form.show();

しかし136*39以下にはできません。

f:id:moko_03_25:20200310100030p:plain

なぜそんな小さいサイズが必要かというと、デスクトップキャプチャを指定した矩形範囲で実行したいからです。方法はこちらの記事を参考にさせていただきました。

どうすれば良いか悩みましたが自己解決しました。
このように、生成してからサイズを変えたら良いだけの話でした。。

form.show();
form.Width = 30;
form.Height = 30;

f:id:moko_03_25:20200310101445g:plain


どなたかのお役に立てば幸いです。