X



トップページ独身男性
660コメント436KB

System.out.println("またJavaの季節がやってきた!" + 2);

■ このスレッドは過去ログ倉庫に格納されています
0001おれさま ◆6CTEZS59O00a
垢版 |
2018/09/13(木) 10:42:14.49
去年の今頃Java学習開始するも挫折
しかし不屈の闘志をめらめらと燃やしながら
そびえ立つ岩壁にいどむため、再びこの地にやってきたのだ!

プログラミング歴は独学Cチョビッツ+独学VBA少々


きょうかしょ
https://www.amazon.co.jp/dp/484433638X
スッキリわかるJava入門 第2版 (スッキリシリーズ)
0344おれさま ◆6CTEZS59O00a
垢版 |
2018/11/26(月) 05:22:35.23
結局、スイッチON/OFFの世界をどうやってうまく利用していくかなんだろうな
すごいもんだ
0345おれさま ◆6CTEZS59O00a
垢版 |
2018/11/26(月) 05:39:25.97
ちなみにだけど

if ((artA & r) == 0b0001) { } ○

if (artA & r == 0b0001) { } ×(エラー)

なので注意
0347おれさま ◆6CTEZS59O00a
垢版 |
2018/11/27(火) 11:51:09.28
public class Program
{
 public static void Main(string[] args)
 {
  for (var i = 0; ; i++)
  {
   int num = new Random(i).Next(1000);
   Console.WriteLine(num);
   if (num == 500)
   {
    break;
   }
  }
 }
}

乱数生成して遊んでた
乱数好き
Randomクラスのコンストラクタに渡す引数は「シード値」といって
これが同じだと生成される乱数は変らない
ここはJavaとは違うよね確か。
まぁそういうわけでシード値を次々に変えていくために
カウンター変数をシード値として流用

練習コードを書くときに乱数を使うとちょっと動きのあるコードを書けるので面白い
0349おれさま ◆6CTEZS59O00a
垢版 |
2018/11/28(水) 10:12:28.84
シード値はJavaでも同じかな
シード値のデフォルトが違うかもしれない
めんどうなんで調べないけど
0350おれさま ◆6CTEZS59O00a
垢版 |
2018/11/28(水) 10:48:40.10
スッキリわかるSQL入門 第2版 ドリル222問付き! (スッキリシリーズ)
中山清喬

ぽちった
0351おれさま ◆6CTEZS59O00a
垢版 |
2018/11/28(水) 21:36:57.44
5章やってたんだけどラムダ式が結構出てくる
先に押さえておきたくて10章に一時的に出張中

この辺はJavaでは薄くしかやってないので
しっかりやらないと理解できない
delegateから始める
0352おれさま ◆6CTEZS59O00a
垢版 |
2018/12/01(土) 07:36:12.73
VBAのちょっとしたのを組まなければならなくなってちょいと中断
さっさと終わらせたい
0355おれさま ◆6CTEZS59O00a
垢版 |
2018/12/01(土) 14:08:34.12
いつもやらかすのは

Range(Cells(i, j), Cells(k, l))

みたいにRangeの指定をCellsを使ってやるケース

このとき、
With ThisWorkbook.Worksheets("なんとか")
で囲ってるなら
Cellsの前にもドットが必要なんだけど、これを忘れる
そしてそれに気づかない
今日もやらかしてしばし作業がとまった
0356おれさま ◆6CTEZS59O00a
垢版 |
2018/12/01(土) 15:23:44.31
C#

Splitクラス

区切り文字はchar型なのでシングルクオーテーションを使わないといけない
string型のダブルクオーテーションを使うとエラー

すぐ忘れる

あと、区切り文字で new[] を使わない時は { } をつかってはダメ
0357おれさま ◆6CTEZS59O00a
垢版 |
2018/12/01(土) 16:55:30.57
正規表現

\d{2,4} ○
\d{2, 4} ×

なんとスペース入れるとダメ
今気づいた
こういうのって実際にコードを打ち込んでみて失敗しないと気づけない
あと、おれはそんな記憶力良くないんで、実際にコード打たないと覚えた気になってて
実際は覚えてないということになる

めんどうだけど、とにかくできる限り全てのコードを打って試していこう
テキストのコードを自分なりに少し変えて試す

いや、これがまためんどくさいのだが、ためになる
0358おれさま ◆6CTEZS59O00a
垢版 |
2018/12/02(日) 08:13:23.33
命令文の中に「:」が入ってくるようなクラスを説明する時に
Console.WriteLineの中に「:」を入れるのはやめて欲しいわ
そうでなくてもできる限り記号を入れないで欲しい
例えば

Console.WriteLine($"位置:{m.Index} 長さ:{m.Length}");

とかいうコード

Console.WriteLine($"位置は{m.Index} 長さは{m.Length}");

でいいだろ
このコードでは「:」は混同の原因になりにくいかもしれないけど
例えば三項演算子とか入ってきたりした場合とか
0359おれさま ◆6CTEZS59O00a
垢版 |
2018/12/02(日) 09:45:34.92
ふぅ 5章の重さは半端ないわぁ
2周目なんだけどしっかりやってるとなかなか進まない
1周目で理解しそびれた部分押さえるのが精一杯
0360おれさま ◆6CTEZS59O00a
垢版 |
2018/12/02(日) 10:03:46.50
せめて9章までやらないと基本分野網羅できない感じする
ここまでやると
コレクション
オブジェクト指向の各分野
を大体押さえることができそう

新版のスッキリSQLも届いたのでちょくちょく目を通していこうかな

GUIアプリをC#でつくるための参考書も買ってあるので
のぞいてみたんだけど、JavaのSwingで作るよりずいぶん簡単そうな感じがする
クラス定義の後ろの方に「:」があるようなコードが書いてあったのだが
これはまだやってない分野だ
自動で作られたコードを隅々まで理解できるようになりたいので
独習の方を先に進めることにする
0361おれさま ◆6CTEZS59O00a
垢版 |
2018/12/03(月) 13:06:46.85
5章2周目クリア
もう一周ぐらいやらないとダメなことは分かっているが
復習はまたあとにして6章に進む
0362おれさま ◆6CTEZS59O00a
垢版 |
2018/12/04(火) 13:59:18.21
Dictionary で使っている Red-Black tree だけど、なるほどなぁ
これは foreach で取り出すとき、できるだけ左側の下の方から探索していくのか
こういうアルゴリズムって面白いな
0363おれさま ◆6CTEZS59O00a
垢版 |
2018/12/04(火) 14:01:24.00
>>358の「:」はインターフェースの実装だったようだ
この辺はJavaと記述が違うからC系から引き継いだものかな
0364おれさま ◆6CTEZS59O00a
垢版 |
2018/12/04(火) 15:12:33.74
コレクションも配列もSortの規則を変えるにはラムダ式を使おう!

var l = new List<int>() { 100, 200 };
l.Sort((x, y) => (-x) - (-y));
Console.WriteLine(string.Join(",", l));

var ary = new[] { 100, 200 };
Array.Sort(ary, (x, y) => (-x) - (-y));
Console.WriteLine(string.Join(",", ary));
0367おれさま ◆6CTEZS59O00a
垢版 |
2018/12/07(金) 05:06:13.54
すっきりとちがって独習はたまに誤解を招きそうな表現があるんで気をつけないといけない
おまえらぐらいだとこの程度の説明でわかるだろ?あ?
みたいなのを感じる
が、おれは残念ながら分からない
この説明端折りすぎてんなと思ったらコードいろいろ書いて確認してる
0368おれさま ◆6CTEZS59O00a
垢版 |
2018/12/07(金) 08:57:32.42
C#ではインスタンス経由でstaticメンバにアクセスできないのか
Javaだとスッキリ入門で複数の勇者インスタンスが、共有のお金にアクセスするために
static int maney を定義していたが、ああいうのはだめなのか

独習278ページ
「クラスメソッドはオブジェクト経由では呼び出さない」
0369おれさま ◆6CTEZS59O00a
垢版 |
2018/12/07(金) 10:20:09.17
Mathクラスがなぜ静的クラスなのかを説明している文だけど
関連した機能を一つのクラスにまとめることでわかりやすいから、
みたいな説明がされている

これって説明になってないと思う

そうじゃなくて、このような数学的な処理ってのは
引数を渡して即座に処理をして結果を返せば足りるんで
いちいちデータをフィールドに格納しておく必要はないから
ってのが最大の理由じゃないの

そもそもインスタンス化の最大の利点はインスタンスごとに
異なるフィールド値を格納しておくことができる点でしょ

そこを説明してないのってちょっとあれだと思うんだけどどうなんだろうか
ちがうんかね
独習287ページ
0370おれさま ◆6CTEZS59O00a
垢版 |
2018/12/08(土) 03:39:21.77
値型の値渡し
参照型の値渡し
値型の参照渡し
参照型の参照渡し

今読んでてちょい混乱したけどもうおk
「値渡しはコピー」で
「参照渡しはこれをみてね」
みたいな理解でいけた

これCでもやったような記憶があるがデジャブだろうか

面倒だがひとつひとつテストコードを自分で書いて確かめてみようか
0371おれさま ◆6CTEZS59O00a
垢版 |
2018/12/08(土) 11:56:46.33
自作のJavaプログラムだけど、ちょっと前から動かなくなってた
どうやらJDKのパージョンアップにともなって仮想マシンにアクセスできなくなっていた
ユーザー側の問題になるんだけど、バージョンアップ程度で環境変数やらいじらせるのっていまいちだな
やっぱwindowsアプリつくるならC系なのかね
0372おれさま ◆6CTEZS59O00a
垢版 |
2018/12/09(日) 07:36:37.58
素数かどうか調べるプログラムに感心した

平方根となる小数を切り捨てて整数にする
この整数の値になるまで2から順に除算をして
余りが0になるものがあるか調べる
ヒットする場合は素数ではない

var prime = true;
for (var i = 2; i <= Math.Floor(Math.Sqrt(num)); i++)
{
 if (num % i == 0)
 {
  prime = false;
  break;
 }
}

中学校の数学で必死こいてやってた作業と全く同じだ
「真ん中」まで調べる的な
0373おれさま ◆6CTEZS59O00a
垢版 |
2018/12/09(日) 07:49:41.09
IEnumerable<>を戻り値として使うイテレーター構文は
foreachを簡単に使えるようにするために利用される
(foreachを使えるようにIEnumerableインターフェースを実装するのは大変なので)

ポイントは
yield return (と、yield break)
0374おれさま ◆6CTEZS59O00a
垢版 |
2018/12/09(日) 15:59:29.32
独習318ページの3.@の解答
readonlyと書いてあるけどprivateだよなこれ
いちいちここに書いてないけど誤植がちらほらある
誤植だと思い違いしてるケースも考えられるので実際困る
0376おれさま ◆6CTEZS59O00a
垢版 |
2018/12/11(火) 14:39:54.48
インデクサーの説明わかりにくいなあ
インスタンス名[index] でインスタンスを利用したいときに使うみたいな感じか
フィールドが配列の時に使うとうまい具合に組み合わさって利用価値があるみたいな
0377おれさま ◆6CTEZS59O00a
垢版 |
2018/12/11(火) 15:00:20.81
インスタンス名[ ] の形式で利用したいなら自由に使えるようなものなので
例えば[ ]の中が要素番号的なものでなくても使えると。

class Test
{
 public string this[string st]
 {
  get { return st; }
 }

}
class Program
{
 public static void Main(string[] args)
 {
  var t = new Test();
  Console.WriteLine(t["aaa"]);//結果「aaa」
 }
}
0378おれさま ◆6CTEZS59O00a
垢版 |
2018/12/11(火) 15:02:25.81
で、フィールドが配列の時に、インデクサーを組み合わせて使うと
真価を発揮できると(まるで真価を発揮できてない例だが・・・・

class Test
{
 string[] ary = new string[3];
 public string this[int index]
 {
  set { ary[index] = value; }
  get { return ary[index]; }
 }

}
class Program
{
 public static void Main(string[] args)
 {
  var t = new Test();
  t[0] = "aaa";
  Console.WriteLine(t[0]);//結果「aaa」
 }
}
0379おれさま ◆6CTEZS59O00a
垢版 |
2018/12/11(火) 15:31:09.84
this[string st]
this[int index]
の部分が大事で、こういう使い方をすると便利だなと思うような場面で使えば良いのかな
特にインスタンスを配列ライクに使いたい場合
インスタンスをforで回しながら何かをインスタンス内のどこかに代入していきたいとか
0380おれさま ◆6CTEZS59O00a
垢版 |
2018/12/13(木) 14:28:36.18
忙しくなってきて時間裂けなくなってきたけど
少しずつでもいいんでやっていこうと思う
0381わがはい ◆0BMoNHqNlM
垢版 |
2018/12/14(金) 21:36:14.76
マッマに新しいPC買ってもらっただで
今までは簡単なアプリをGooglePlayにリリースしてきたけど、ようやく本格的なアプリが作れそうや

あとは今運営してる比較サイトもAjaxで非同期にデータベースとアクセスできるようにしたい
Googleが提供してるFireBase使えば、サーバーサイドの開発する必要すらないみたいやな
便利な時代になったで
0382おれさま ◆6CTEZS59O00a
垢版 |
2018/12/15(土) 08:52:59.06
ぐぐるさんは優秀なapi無料で公開してくれてるからありがたいんだけど
セキュリティ固めてる環境からアクセスするようコードに仕込んでると
そのうち担当者から怒られそうなのがネック
0383おれさま ◆6CTEZS59O00a
垢版 |
2018/12/16(日) 13:50:25.94
ふぅ 8章まで終わった
覚えてるのかと言われたらスッカスカだが一応理解はした
スッカスカで先に進むと理解できなくなりそうだが
ここは敢えて進むのだ
0384おれさま ◆6CTEZS59O00a
垢版 |
2018/12/17(月) 10:25:03.37
>>343は列挙型で使うようだ
「<<」演算子を使うと、色ごとに2進数を割り当てる時に、
1をズラしたものを簡単に定義できる

int r = 1;     //0b0001 赤(1)
int g = 1 << 1; //0b0010 緑(2)
int b = 1 << 2; //0b0100 青(4)
int w = 1 << 3; //0b1000 白(8)

こんな風に
0385おれさま ◆6CTEZS59O00a
垢版 |
2018/12/18(火) 12:39:07.59
ちょいGUIに寄り道する
入門本買ってあるので簡単なものを作れるようにしていく
Javaの時と同じ流れでやっていく
0386おれさま ◆6CTEZS59O00a
垢版 |
2018/12/18(火) 12:50:19.99
slnファイルをクリックするとそのソリューションがVisual Studioで立ち上がる

ふむふむ
0387おれさま ◆6CTEZS59O00a
垢版 |
2018/12/18(火) 13:20:24.31
違う本読むとまたそれはそれで勉強になるわぁ
Visual Studioの使い方適当にやってたけどいろいろと説明してくれててありがたい

オブジェクト指向がどういう流れで生まれてきたのかとか、
この辺は著者によっていろんな説明してくるけど、この本の説明は頭にすっと入る
データベースの誕生に関連させてオブジェクト指向の誕生を説くあたり

別のプログラムを組む時に、他のプログラムから一部借用してきたりとか、そういう再利用のしやすさ
0388おれさま ◆6CTEZS59O00a
垢版 |
2018/12/18(火) 13:39:17.87
ふーむ
これはVBEのフォーム組むのとすごーく似てるね
VBAのプロパティってC#のプロパティと同じものなのか
オブジェクト指向のインスタンスやプロパティ、メソッドをコードからじゃなくて
VisualStudioのGUIを使って説明するとか斬新だわ

あと、デザイン画面でぽんぽんとコントロールを貼り付けていくと
勝手にコードが背後で生成されていくわけなんだけど
このコードも理解したいな
JavaでSwingで試してた時は全部自分で書いてたわけで
C#では相当楽できるんだが、仕組みは分かっておきたい
パーシャルクラスとかさっき勉強したばかりのを使ってて復習にもよさそう
0389おれさま ◆6CTEZS59O00a
垢版 |
2018/12/18(火) 13:54:22.10
Program.csがMainメソッドを持つ主か
ここからスレッドを走らせ
編集対象となっているForm1.csのForm1クラスのインスタンス生成
Form1クラスのコンストラクタがInitializeComponentメソッドを呼ぶ
これはデザイン用に用意されているForm1.Designer.csにあるメソッドで
ちょうど、Swingでコンストラクタの最初の方に書いていたようなコントロールの配置とかが書いてある
各コントロールの実際の動きはForm1にメソッドとして記述していくわけか
Javaでのイベント系の処理とどの程度類似してるか
そっくりというわけではなさそうだ
0390おれさま ◆6CTEZS59O00a
垢版 |
2018/12/18(火) 15:28:42.09
この辺を理解するには独習の最後の最後を読んだほうが良さそうだ
いろいろ調べてみたんだけど、マルチキャストデリゲートなのかな
それだけでは説明できない要素が加わっているようなので、これを理解するには
独習の最後、ほんとに最後なんだよなこれ、ここを読むほうがよさそう

で、明日読もう
今日は終わり
0391おれさま ◆6CTEZS59O00a
垢版 |
2018/12/20(木) 21:18:18.08
public delegate void MyEventHandler(object sender, EventArgs e);

class Program
{
 public event MyEventHandler myEvent;

 public void handler(object o, EventArgs e)
 {
  Console.WriteLine("handler called");
 }

 public static void Main(string[] args)
 {
  Program target = new Program();
  target.myEvent += target.handler;//+= new MyEventHandler(target.handler)も可

  target.myEvent(target, EventArgs.Empty);
 }
}

eventを使った簡単な例

new使ってデリゲートに代入する方法を忘れてた
ネットで調べるとこの書き方を使ってるものが多かったので何だこりゃと思ったんだけど
よくよく独習読み直したら最初の方に書いてあった

target.myEvent(target, EventArgs.Empty); に相当するコードは
windowsアプリでボタンとかをデザイン画面で作った時に自動生成されるコードには見当たらない
ボタンを押したときに内部的にこのコードと同じ機能が働くことで
デリゲートに代入されているメソッドが実行されるという流れなのか

object o
EventArgs e
この2つの引数もわかりにくい
oはイベントの呼び出し元のインスタンスを意味するみたいだ
EventArgsはまだよく分からない
0392おれさま ◆6CTEZS59O00a
垢版 |
2018/12/20(木) 21:29:42.81
o は 「イベントを発生させたオブジェクト」

と書いた方がよかった

EventArgs e は 「ハンドラに渡す引数」
上の例だと渡すべき引数がないのでEventArgsクラスのEmptyプロパティがついている

ここ↓を参考にしてるんだけど、おれにとっては一番わかりやすい
http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_013/csharp_abc01.html
EventArgs eについてもここ↓
http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_013/csharp_abc02.html
で理解出来そうだ
0393おれさま ◆6CTEZS59O00a
垢版 |
2018/12/20(木) 22:02:43.05
なんとなくだけど、分かった気がする
ハンドラ、つまり、実際に実行されるメソッドなんだけど、これに情報を渡したい時がある
このとき、場合によってどういう情報を渡したいのかは様々なので、
自分でクラスを作ってそこに情報を記録してわたせということか。
その際、EventArgsクラスを継承してクラスを作る事になる

その例となるコードが上に上げたURL2個目に書いてある

では、これがwindowsアプリを作った時に自動生成されるコードにどういう形で反映されているかだ

e に何を情報として詰め込んで渡しているかは、自動生成されたコードには書かれていない
これはボタンとかのAPIが内部的にやってるようだ

ここでよくよく考えてみると、JavaのSwingでも同じような e が出てきた
例えば>>109
右クリしたときのmouseClickedメソッドはMouseEvent eを引数として受けとるわけだけど
この e を使って、showメソッドに e.getComponent(), e.getX(), e.getY() という引数をわたしている
この getComponent(), getX(), getY() こそが内部的に e に格納されいる情報というわけか
まぁここでは情報というかメソッドではあるんだけど、e について用意されたものなわけだ

同じ事をC#でやろうとしても、ちょっと勝手が違う
0394おれさま ◆6CTEZS59O00a
垢版 |
2018/12/20(木) 22:13:25.62
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(51, 12);
this.label1.TabIndex = 0;
this.label1.Text = "こんにちは";
this.label1.DoubleClick += new System.EventHandler(this.label1_DoubleClick);


private void label1_DoubleClick(object sender, EventArgs e)
{
 label1.Text = "ダブルクリックされました";
 MessageBox.Show(sender.ToString() + "\n" + e.ToString());//@
}


これは、「こんにちは」と書かれたラベルをデザイン画面で作った時に自動生成されたコード
ラベルをダブルクリックしたときに「ダブルクリックされました」とラベルの表示が変るようにしてある

ここに、今問題としている引数2つ、senderとeの内容をToString()で表示させる一行を加えた@
@の結果はこう↓
System.Windows.Forms.Label, Text: ダブルクリックされました
System.Windows.Forms.MouseEventArgs
0395おれさま ◆6CTEZS59O00a
垢版 |
2018/12/20(木) 22:24:51.24
Javaでは e と打ったあと、自動補完システムが e について使えるフィールドやメソッドを
示してくれた
C#でもインテリセンスが示してくれるんだけど、
Objectクラスのメンバのようなものしか表示されていないようだ
そこで、この一行を@の代りに使ってみる

MessageBox.Show(sender.ToString() + "\n" + ((MouseEventArgs)e).Clicks);

これは、((MouseEventArgs)e). まで書いたときに、インテリセンスが羅列した候補からClicksを選んだ場合だ
このようにMouseEventArgsでキャストすることで、Javaと同じように e の実際のメンバが表示できた
要は、基底クラスのEventArgsのままだとメンバが表示されないので
派生クラスのMouseEventArgsにキャストし直したというわけだ
e がどのクラスなのかは、>>394でやったようにToString()を使って知ることができる

ちなみに、結果は

System.Windows.Forms.Label, Text: ダブルクリックされました

2

とでる
e から、クリックの回数である 2 という情報を引き出せたことになる

一応満足した
0396おれさま ◆6CTEZS59O00a
垢版 |
2018/12/21(金) 02:45:55.79
((MouseEventArgs)e).X
((MouseEventArgs)e).Y
相対座標もこれで取得できる
ラベルの左上が原点かな?たぶん

C#はこの辺の理解全くなしでGUIアプリを組めるという点では楽だな
その反面理解なしに進んでしまうから、そのうち壁にぶつかりそうだけど

これまでコンソールアプリだとVisualStudioの画面に、
windowsアプリだとMessageBox.Show()でメッセージボックスに
文字情報を出力してきたけど
これからはフォーム上に作ったテキストボックスに出力する方がよさそうだ
こぴぺもできるしね

ここにコード貼るときにタブというかスペースを加工しないと
うまくインデントを表現できなかったので、正規表現使えるエディタで置換してた
ただ、ちょっと使いづらい
そこで、この加工をする専用のwindowsアプリを自分で作ってみようかなとか思ってる
簡単そうだし役に立ちそう
0397おれさま ◆6CTEZS59O00a
垢版 |
2018/12/21(金) 14:46:10.20
でけた〜
初のC#アプリ
やっぱりC#は簡単に作れるなぁ

正規表現でちょっと迷ったところがあったけど
サブマッチパターンに名前を付けて処理することで解決した
0398おれさま ◆6CTEZS59O00a
垢版 |
2018/12/21(金) 15:23:30.36
private void button1_Click(object sender, EventArgs e)
{
 string textBox1Value = textBox1.Text;
 var rgx = new Regex(@"(?<wideSpaces>^( )*)(( ){4})", RegexOptions.Multiline);

 while (rgx.IsMatch(textBox1Value))
 {
  textBox1Value = rgx.Replace(textBox1Value, "${wideSpaces} ");
 }

 textBox2.Text = textBox1Value;
}

目的は、
マルチラインのtextBox1に表示されているコードの全てのインデント(半角スペース4個)を
全角スペース1個に置換し、結果をtextBox2に表示させること

方法はいろいろあると思うけど、こういう流れでやった

マルチラインモードの正規表現で文字列先頭にある半角スペース4個セットを検索して、
これを全角スペース1個に置換。
半角スペース4個セットは複数並んでいる場合もあるため、一度では処理できない

そこで、whileで半角スペース4個セットがなくなるまで回す方向で考える。

正規表現に少し手を加える
文字列先頭にある「0個以上の全角スペースと、これに続く半角スペース4個セット」を検索し
これを置換する。0個以上の全角スペースとは、置換済のインデントを意味する
どのように置換するかだが、
0個以上の全角スペースはそのままで、半角スペース4個だけを全角スペース1個へ置換する
0個以上の全角スペースはそのまま残すため、
この部分を丸括弧でくくってサブマッチパターンとし、wideSpacesと名前を付ける

(?<wideSpaces>^( )*)

そして、置換後文字列にwideSpacesを利用する

最初はsplitして一行ごとに処理していたけど、せっかくだからマルチラインモードとかの
復習も兼ねて、てんこ盛りでやってみた
文字列の途中に半角スペース4個がないと仮定するならもっと簡単なのだが
そこはこだわってちゃんと作ってみた
貼ってあるコードは、もちろん作ったばかりのアプリで置換作業をしたもの。
0399おれさま ◆6CTEZS59O00a
垢版 |
2018/12/22(土) 15:28:42.73
windowsアプリの入門本使っていくつか作ってるんだけど簡単に作れるわ
今の知識だけでもいろんなもの作れそう
Javaでも外部ライブラリやら導入すればもっと簡単にできたのかもしれないけど
VisualStudioだと追加導入の手間いらずでこれだけ作れるのはすごい
今ちょうど>>119-121に相当するコードを書いていたのだけど、ずっと簡単にかける
前回閉じた場所で開く機能も試しにやってみたいがどうすっか
0400おれさま ◆6CTEZS59O00a
垢版 |
2018/12/22(土) 17:44:48.34
閉じたときの場所をlocation.logに記録して
開いた時にlocation.logから座標を読み取って再現するという
Javaでもやった例のパターンなんだけど

開いた時にロードする時、当然コンストラクタに記述するんだろと思いきや
windowsアプリだとイベントとして記述するみたいだ
これも斬新だな
0401おれさま ◆6CTEZS59O00a
垢版 |
2018/12/22(土) 17:54:18.81
private void Form1_Load(object sender, EventArgs e)
{
 string str = null;
 int x = 0;
 int y = 0;
 
 if (File.Exists(Path))
 {
  using (sr = new StreamReader(Path))
  {
   str = sr.ReadToEnd();
  }
  var rgxX = new Regex(@"(^x=)([0-9]+)", RegexOptions.Multiline);
  var strX = rgxX.Match(str).Groups[2].Value;
  var rgxY = new Regex(@"(^y=)([0-9]+)", RegexOptions.Multiline);
  var strY = rgxY.Match(str).Groups[2].Value;
  if (int.TryParse(strX, out x) && int.TryParse(strY, out y))
  {
   this.Left = x;
   this.Top = y;
  }
  else { SetCenter(); }
 }
 else { SetCenter(); }

 void SetCenter()
 {
  this.Left = (Screen.PrimaryScreen.Bounds.Width - this.Width) / 2;
  this.Top = (Screen.PrimaryScreen.Bounds.Height - this.Height) / 2;
 }
}

座標をロードするハンドラ
Pathはクラス定数としてlocation.txtが定義されてる
location.txtにはフォームを閉じる際、
x=100
y=150
のような形式で座標が登録されるようになっているので、
ロードハンドラではこれを読み込むことになる
正規表現はお気に入りのサブマッチパターンを使った
TryParseでx,y座標ともにintへの変換が成功した場合のみフォーム表示の座標として利用
失敗したときは内部メソッドのSetCenterを呼び出してモニタ中央に表示させる
0402おれさま ◆6CTEZS59O00a
垢版 |
2018/12/22(土) 18:11:47.95
フォームを開く時にモニタ中央に表示させるコードとしてこういうものがある

this.StartPosition = FormStartPosition.CenterScreen;

これを使うのであれば、コンストラクタに書く必要がある
上のロード用のイベントハンドラはどうやらフォームが表示されたあとに動いているようだ
ハンドラにStartPositionを書いてしまっても今更ということになってしまう
そのため、SetCenterメソッドでは、
すでに表示されているフォームの位置を変更するという形をとっている
0403おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 02:47:39.01
例えばカレンダーをつくるとして、日付を表示するパネルが42枚並んでるとする
このとき各日付パネルをクリックすることで何らかのアクションを起こしたい時
Form1クラスに42個のイベントハンドラを並べるのはどうなんだと思い調べてみた

https://dobon.net/vb/dotnet/control/buttonarray.html

配列を利用することになるんだけど
いくつかの方法があるようだ
0404おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 03:24:19.38
uint x;
Console.WriteLine(uint.TryParse("-10", out x));


結果はfalse
これを利用することで、モニタの表示画面からはみ出した座標が記録されていた場合
次に開く時はモニタ中央に開けるかやってみた


string str = null;
uint x = 0;
uint y = 0;

if (File.Exists(Path))
{
 using (sr = new StreamReader(Path))
 {
  str = sr.ReadToEnd();
 }
 var rgxX = new Regex(@"(^x=)([0-9]+)", RegexOptions.Multiline);
 var strX = rgxX.Match(str).Groups[2].Value;
 var rgxY = new Regex(@"(^y=)([0-9]+)", RegexOptions.Multiline);
 var strY = rgxY.Match(str).Groups[2].Value;
 if (uint.TryParse(strX, out x) && uint.TryParse(strY, out y))
 {
  this.Left = (int)x;
  this.Top = (int)y;
 }
 else { SetCenter(); }
}
else { SetCenter(); }

void SetCenter()
{
 // this.StartPosition = FormStartPosition.CenterScreen;はForm_Loadイベントハンドラでは機能しない
 this.Left = (Screen.PrimaryScreen.Bounds.Width - this.Width) / 2;
 this.Top = (Screen.PrimaryScreen.Bounds.Height - this.Height) / 2;
}


一応いけるんだけどサブモニタ上ではうまく機能しないようだ
マイナスのy座標が記録されている場合でも、そのままの座標で開いてしまう
メインモニタ上では機能するので、とりあえずいいか
0405おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 04:52:11.42
あーちょいまてよ
正規表現にマイナスが含まれてないな
この辺でおかしくなってそうだ
今いそがしいからあとから触ってみよう
0406おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 05:07:48.63
>>404の正規表現部分だけを修正
var rgxX = new Regex(@"(^x=)(-?[0-9]+)", RegexOptions.Multiline);
var strX = rgxX.Match(str).Groups[2].Value;
var rgxY = new Regex(@"(^y=)(-?[0-9]+)", RegexOptions.Multiline);
var strY = rgxY.Match(str).Groups[2].Value;


これでサブモニタでマイナス側に飛び出しても大丈夫

可能性として、下とか左に飛び出す場合もあるわけで
そういう場合には対応できていない
そう難しいわけではなさそうだけど
0408おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 09:43:36.30
>>404をさらにアプデ
private void Form1_Load(object sender, EventArgs e)
{
 string str = null;
 int x = 0;
 int y = 0;

 if (File.Exists(Path))
 {
  using (sr = new StreamReader(Path))
  {
   str = sr.ReadToEnd();
  }
  var rgxX = new Regex(@"(^x=)(-?[0-9]+)", RegexOptions.Multiline);
  var strX = rgxX.Match(str).Groups[2].Value;
  var rgxY = new Regex(@"(^y=)(-?[0-9]+)", RegexOptions.Multiline);
  var strY = rgxY.Match(str).Groups[2].Value;
  if (int.TryParse(strX, out x) && int.TryParse(strY, out y))
  {
   this.Left = x;
   this.Top = y;
  }
  else { SetCenter(); }
 }
 else { SetCenter(); }

 var scr = Screen.GetBounds(this);
 const double RemainLimit = 0.6;
 bool result = true;
 result &= (scr.X + scr.Width - this.Left > this.Width * RemainLimit);
 result &= (this.Left + this.Width - scr.X > this.Width * RemainLimit);
 result &= (scr.Y + scr.Height - this.Top > this.Height * RemainLimit);
 result &= (this.Top + this.Height - scr.Y > this.Height * RemainLimit);
 if (!result) { SetCenter(); }

 void SetCenter()
 {
  this.Left = (Screen.PrimaryScreen.Bounds.Width - this.Width) / 2;
  this.Top = (Screen.PrimaryScreen.Bounds.Height - this.Height) / 2;
 }
}
0409おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 09:45:41.05
>>408
uintは座標がマイナスの場合しか使えないロジックなのでやめやめ

こんな風にした
保存してある座標をそのまま使って一旦フォームを表示させる
もちろんlocation.txtがないとか、数値が想定通りに記録されてない場合はメインモニタ中央へ表示

その上で、フォームがモニタ画面から飛び出し「すぎてる」場合はメインモニタ中央へ移動
RemainLimit = 0.6はフォームの幅・高さの6割がモニタ画面に映っているならOK
それを下回ったらメインモニタ中央へ表示、という定数
これで上下左右・メインモニタ/サブモニタ関係なしにオールマイティにはみ出し補正可

resultのロジックだけど
result = result && (〜〜〜);
でやってたんだけど、もしかしてとおもって
result &= (〜〜〜);
にしたら行けたんでこれにした
要は if を並べて階層深くしたり、条件式が長くなるのが嫌だっただけなんだけど

これはクラスにまとめてこれから作っていくアプリにも使っていこうかなぁ〜
0410おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 09:56:37.15
フォームを一旦表示させてから問題あるなら移動させるという2段階の方法を採った理由は
一度に所定の位置へ置こうとすると、scr.X とかがうまく取得できなかったから
0411おれさま ◆6CTEZS59O00a
垢版 |
2018/12/23(日) 10:00:56.74
どうでもいいような部品なんだけど
うまくいったんで満足である

独習はまだしっかり頭にはいってないところがたくさんあるけど
辞書的に使うのにも適してる

今のGUIの入門本しばらくやってから、独習の残り1割ぐらいだけど
まだ読んでない部分読むか
復習も何度かしないといけないな
0412おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 11:13:08.50
>>403で書いた複数コントロールを束ねる処理についてなんだけど、
今やってる入門本でも紹介されていた

複数のボタンをひとつのハンドラでコントロールする方法を使う
デザイン画面で複数ボタンを選択してから
右下プロパティウィンドウ→イベントタブ→Clickの項目にハンドラ名を入力してEnter
で、Form1に選択した複数ボタンに一括対応するハンドラが自動生成

ここでひとつ問題がある
Form1のこのハンドラを見ただけでは
このハンドラがどのコントロールに対応してるかがわからない
覚えてりゃいいんだけど、またはコメント書いておけばいいとかいう話ではあるんだけど
やはりちゃんとコード上で確認できるべき

そこで、確認方法
左上ソリューションエクスプローラウィンドウ→Form1をクリックして展開
→Form1.Disigner.csをダブルクリックして開く
コード上に
「Windows フォーム デザイナーで生成されたコード」
というregionがあるので左端+をクリックして展開
この中にbutton2に対応する部分がある

//
// button2
//
this.button2.Location = new System.Drawing.Point(13, 13);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(125, 100);
this.button2.TabIndex = 0;
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.buttons_Click);//←ここ

複数ボタン対応ハンドラの名前は「buttons_Click」としたのだが、
button2.Clickにbuttons_Clickハンドラが登録されている
ここからbutton2.Clickがbuttons_Clickメソッドによりコントロールされることがわかる
同じようにbutton3, button4, button5 ・・・・といったbuttons_Clickハンドラにより
コントロールされるボタンのコードにも、buttns_Clickが登録されているのがわかる
0413おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 11:20:44.17
複数コントロールを一括してひとつのハンドラにまとめるには
対象となるコントロールをぽちぽちとctrl+左クリすることで選択していくわけだけど
こういう方法によると、対象外のオブジェクトを間違えて選択してしまうことがある

実際に自分がやった間違いとしてこれ↓

//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.button10);
this.splitContainer1.Panel2.Controls.Add(this.button7);
this.splitContainer1.Panel2.Controls.Add(this.button4);
this.splitContainer1.Panel2.Controls.Add(this.button9);
this.splitContainer1.Panel2.Controls.Add(this.button6);
this.splitContainer1.Panel2.Controls.Add(this.button3);
this.splitContainer1.Panel2.Controls.Add(this.button8);
this.splitContainer1.Panel2.Controls.Add(this.button5);
this.splitContainer1.Panel2.Controls.Add(this.button2);
this.splitContainer1.Panel2.Click += new System.EventHandler(this.buttons_Click);//←ここ
this.splitContainer1.Size = new System.Drawing.Size(412, 396);
this.splitContainer1.SplitterDistance = 54;
this.splitContainer1.TabIndex = 0;

ボタンの背景にあるパネルを間違えてクリックしてしまい
パネルがbuttons_Clickハンドラの支配下に置かれてしまっている
このままだとボタンではなく背景のパネルをクリックしただけで
buttons_Clickハンドラに記述されている処理が実行されてしまう

パネルが選択されたかどうかは、デザイン画面上は非常にわかりにくく間違いを招きやすい
選択されたオブジェクトが羅列されているウィンドウは見当たらない
注意深くやっていくしかないというところか
0415おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 11:30:14.22
ところで、>>413のようにミスしてしまった場合の対応なのだが、
実際、どのオブジェクトがどのハンドラの支配下にあるのかは>>412でわかるように
「隠された」コードを見るしかない

しかも、この部分にはこんなコメントが記述されている

/// <summary>
/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
/// コード エディターで変更しないでください。
/// </summary>

>>413の「//←ここ」の行を削除すればいいんだろうなということは
今まで貯めた知識で分かってはいるんだけど、本当にいいんだろうかと。
別の方法により、「自動的に」削除させる方法があるんだろうか

まぁよくわからないので、マイクロソフトさんに逆らって勝手にコードを削ることにする

この辺の知識なしでVisualStudioをさわる人はどう処理をしているのか
もう一度対象オブジェクトを全て削除してから自動生成し直しているのかな

なんだかんだこだわって理解しようとしてると、そのうち役に立つもんだ
0416おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 12:20:33.91
>>412のこれだけど

this.button2.Click += new System.EventHandler(this.buttons_Click);

this.button2.Click += new EventHandler(this.buttons_Click);
だとエラーがでる
コードが記述されているのはForm1のパーシャルクラスなんだけど
Form1.csにはusing System;が記述されているから省略してもいいんじゃないかと思ったのだが
パーシャルクラスであってもファイルが違うなら、冒頭にusing System;入れないと
省略できないようだ

実際にusing記述したら省略してもいけた
ここは基本的にユーザーがいじらない前提でコードが自動生成される場所なので
usingでの省略は逆に足手まといになるのかな
0417おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 12:44:16.76
イベントドリブンモデルについて再考

>>391なんだけど、こう書き直してもいい

public delegate void MyEventHandler(object sender, EventArgs e);

class Program
{
public event MyEventHandler myEvent = (sender, e) => { }; //←ここ注目

public void handler(object o, EventArgs e)
{
Console.WriteLine("handler called");
}

public static void Main(string[] args)
{
Program target = new Program();
target.myEvent += target.handler;//+= new MyEventHandler(target.handler)も可

target.myEvent(target, EventArgs.Empty);
}
}

独習567ページのコードに含まれているこれ、
public event KeyCommandEventHandler KeyCommand = v => { };
の理解のために比較対象としてあげてみた
独習の方の
v => { }
は空のメソッドを意味する。
= v => { }
により空のメソッドを初期値としてKeyCommandに代入していることになる
そもそもデリゲート型変数であるKeyCommandにはメソッドが入る
int型変数の初期値として 0 を入れることがあるように
デリゲート型変数にラムダ式を使って空メソッドを初期値として代入しているわけだ。
もちろん初期値を代入することは必須ではないので
public event KeyCommandEventHandler KeyCommand;
と書いてもエラーはでない(はずだ!)
同様に、初期値を設定しない>>391のようなコードも問題なく動く(これは確認済)

上で書きなおしたコードは
(sender, e) => { }
を初期値としてデリゲート型変数myEventに代入している
ラムダ式で表したメソッドだ
デリゲートは引数2つと戻り値voidなので、これに対応した形になっている
0418おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 12:54:49.55
>>417修正
イベントドリブンモデルにおいては、もちろん通常のデリゲートでも同じような事が
言えるのかもしれんが、
いや、もっというと初期値というもの全般について言えることなんだけど

変数に中身が入ってない状態で呼び出されてしまった場合に備えて
やはり空のメソッドでも入れておくべきだ

初期値についてはいろいろルールがあったはずだが忘れたw
調べるのが面倒なのでおいおいということにしよう
クラス変数とローカル変数でも変ってきたはず

とりあえずこれだけは確認した。下のコードはエラーがでる
初期値代入なしで、中身となるメソッドも入れずに実行した場合

public delegate void MyEventHandler(object sender, EventArgs e);

class Program
{
 public event MyEventHandler myEvent;

 public void handler(object o, EventArgs e)
 {
  Console.WriteLine("handler called");
 }

 public static void Main(string[] args)
 {
  Program target = new Program();

  target.myEvent(target, EventArgs.Empty);
 }
}
0419おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 13:08:21.72
VisualStudioでは、ボタンクリックなどで使われるデリゲート型変数の初期値は
どうなっているのか調べてみた

>>412に従って表示されたbutton2.ClickのClickにカーソルを合わせて右クリ
→定義へ移動

public event EventHandler Click;

初期値となる空メソッドは代入されていないように見える

public event EventHandler Click = (sender, e) => { };

こう書き加えてやろうと思ったがもちろん勝手には書き込めないようだ
中身となるメソッド(ハンドラ)が自動生成されて、自動で代入されていくので
初期値がないことによって生じる問題は基本的には起きないと想定した結果か
0420おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 13:12:10.10
忘れてた
>>418で、
初期値設定した上で、中身のメソッドを入れなかった場合はエラーなし
何も表示されずに終了

public delegate void MyEventHandler(object sender, EventArgs e);

class Program
{
 public event MyEventHandler myEvent = (sender, e) => { }; //初期値代入

 public void handler(object o, EventArgs e)
 {
  Console.WriteLine("handler called");
 }

 public static void Main(string[] args)
 {
  Program target = new Program();
                         //中身メソッド代入しない
  target.myEvent(target, EventArgs.Empty);
 }
}
0421おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 14:13:10.09
private void buttons_Click(object sender, EventArgs e)
{
 if (((Button)sender).Text == "あたり")
 {
  MessageBox.Show("あたり!");
 }
}

イベントハンドラの第一引数の具体的な使い方

>>395-396では第二引数 e をやったけど
今回は第一引数のsenderについて

使い方は e と同じで、object型になっているので派生クラスにキャストすることで
senderに格納されてるデータを引き出せる
派生クラスの正確な名称は
MessageBox.Show(sender.GetType().ToString());
を一旦置いてみることで取得できる
この場合
System.Windows.Forms.Button
と表示されるので「Button」が派生クラスだと分かる

Javaだとこの辺のデータも e に格納されていたと思う
>>109の e.getComponent() がそれか
0422おれさま ◆6CTEZS59O00a
垢版 |
2018/12/24(月) 14:15:36.97
派生クラスの名前は
Form1.Designer.csを見ても分かる

this.button2 = new System.Windows.Forms.Button();

ボタンには Buttonクラスのインスタンスが代入されている
0424おれさま ◆6CTEZS59O00a
垢版 |
2018/12/27(木) 15:11:07.59
フォームの大きさを変えたときにボタンとかテキストボックスが自分の思う通りに
追随してサイズを変えたり、または固定されたり・・・といったことをやってた

SplitContainer→FixedPanel, IsSplitterFixed
TableLayoutPanel

などなど・・・
なれないと思った通りにするのに時間かかる
0425おれさま ◆6CTEZS59O00a
垢版 |
2018/12/27(木) 15:52:12.98
イベントハンドラの中で、Form1の座標を取得したいとき、
イベントハンドラに渡されるsenderの実体がForm1の時は問題ない
((Form1)sender).Left
((Form1)sender).Top

senderの実体がButtonの時は同じようにやってもエラーが出る
ButtonなのにForm1型にキャストしようとするからだ
この場合はこうする
((Button)sender).FindForm().Left
((Button)sender).FindForm().Top
Buttonが位置するFormを取得するメソッドFindFormを使えばいい
0426おれさま ◆6CTEZS59O00a
垢版 |
2018/12/27(木) 15:54:53.70
自分で気に入ったアイコンをexeファイルやフォームに表示できるようになった!
0427おれさま ◆6CTEZS59O00a
垢版 |
2018/12/29(土) 10:56:50.05
TableLayoutPanel内にコントロールを並べてるのを忘れてると
これらコントロールのサイズを変更しようとしたときに動かなくて
あれれれれ
と思う事があるので注意

TableLayoutPanelで1行2列の2セルにそれぞれテキストボックスを置いていたんだけど
2つのテキストボックスの間にSplitterを挟むことでテキストボックスの幅を
ユーザーが自由に変更出来る仕組みにしようとした
上の記述はこの時遭遇したトラブル
TableLayoutPanelのセル内でもコントロール配置場所は、該当するコントロールの
Anchor,Dockプロパティによって影響を受ける

そもそもの話になるが、Splitterを使う場合はTableLayoutPanelは使わないので排除する
0428おれさま ◆6CTEZS59O00a
垢版 |
2018/12/29(土) 11:13:58.29
Splitterを使う時はこれと接するコントロールのDockプロパティの使い方に注意
>>427のように、2つのtextboxを横に2つ並べて、その間にSplitterを置く場合、

1つ目の左側に置くtextboxのDockプロパティはLeft
Splitterは自動的にLeftに設定され
2つ目の右側に置くtextboxのDockプロパティはFill ←ここ大事

右側をFillにしないと実行時にSplitterにカーソルを合わせてもカーソル表示が変らないし
幅を変えることもできなかった
0429おれさま ◆6CTEZS59O00a
垢版 |
2018/12/29(土) 16:37:34.90
入門本にgmailチェッカーが載ってたので作ってみたんだけど
テスト用にあらためてgmailアカウント新規でとろうと思ったら電話番号要求してくんのな
でもってSMSとかで確認するとか
あほらしくなって昔取得したアカウント引っ張り出してきて使うことにした
でも結局gmail側のセキュリティ機能が働いてちゃちなアプリではアクセスできないことがわかったので終了
0430おれさま ◆6CTEZS59O00a
垢版 |
2018/12/29(土) 16:55:07.37
ツイッター投稿アプリも載ってたので作ろうと思ったのだが
ツイッター側からアプリ作成に必要なAPIキーをもらうために
開発者用アカウントをつくらねばならない
これまた電話番号登録しろと出る
これもいやなのでパスでーす
0431おれさま ◆6CTEZS59O00a
垢版 |
2018/12/29(土) 17:25:48.41
>>415について
プロパティウィンドウでイベントを表示させると、
登録済のイベントがあれば右側にハンドラの名前が表示される
これを右クリ→リセットすればForm1.Designer.csからも該当コードが自動的に削除されるようだ
0432おれさま ◆6CTEZS59O00a
垢版 |
2018/12/29(土) 17:30:12.88
1.
VisualStudio自体を複数開くことができる
ソリューションはslnファイルから直接ひらくことができるが
複数のslnファイルを順々にクリックしていけばどんどん新しいVisualStudioのウィンドウが開いていく
デザイン画面で、複数の設定がめんどくさそうなコントロールを選択してctrl+c
別のVisualStudioのデザイン画面でctrl+vをすればこぴぺもできる

2.
全然別の話だが、clickイベントとmouseClickイベントの違い
mouseClickはそのまんまだけど、clickイベントは、例えば
ボタンにフォーカスがある時にキーボードでEnterを押すことでもイベント発生可能
0433おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 04:19:55.99
グラフィックについて

ざっとみたところ理解しないといけないクラスとして

1.Graphics
2.Image
3.Bitmap

入門本では説明が簡略化しすぎてるので、自分で調べないとダメだ
0434おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 07:14:59.98
グラフィック関係については一体どこから手を付ければいいのか難しいところだ
そもそも外部から持ってきた画像を表示する方法を明確にしていかないといけなさそうだ
つまりリソースの管理をVisualStudioでどうやっているのかについてだ

画像をフォームに表示する方法として、入門本で初めてやったのはこれだ

PictureBoxというコントロールをフォーム上に置く
フォーカスを当てると右上に表示される三角形から「イメージの選択」
次にローカルリソース→インポートにより外部の画像ファイルを選択して取り込むという流れになる

ここで疑問が出てくる
このインポートされた画像は一体どこに保存されているのだろうか
もちろん作成されたexeの中に入っているのは分かっているのだが
その前段階として該当するソリューションフォルダの中のどこかに
画像ファイルが取り込まれていると考えるのが妥当だろう
しかし探しても、画像ファイル自体は見つからないし、
コードをみても画像ファイルの拡張子からして見当たらない

ここでいろいろ検索してみたところ、どうやら取り込まれた画像ファイルは
拡張子「resx」の「XMLリソースファイル」とやらに格納されているようだ
実際にウィンドウ右上のソリューションエクスプローラーのForm1.csを展開するとForm1.resxがある
これをダブルクリックすると、この中に先ほどインポートした画像が入っているのを確認できる
resxには画像だけではなく、音声や文字列を格納することもできるそうだ
resxを利用しない方法もあるようだが、とりあえず利用する流れでやっていくことにしよう

インポートした画像をForm1.resxの中で選択すると、
pictureBox1.Imageという名前が付けられていることが分かる
画像ファイルとしての拡張子が消えている点に注意しなければならない
pictureBox1.Imageをコードの中から探すと、Form1.Designer.csの中に見つかる

System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(412, 450);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;

usingを使っていないと長ったらしく非常にわかりにくい
0435おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 07:25:31.53
と、ここまで書いて気づいたのだが、
入門本で初めてフォームに画像を表示した方法はこの方法ではなかったようだ
具体的にはこうやった

ソリューションエクスプローラのプロジェクト名を右クリック→プロパティ
→左側ペインからリソース選択
中央に表示される白いスペースに外部の画像ファイルをDDして放り込む
すると、>>434でもやったが、pictureBoxの右上三角マーク→イメージの選択
  (ここでローカルリソースから外部画像ファイルを選ぶのが>>434の方法だ)
→プロジェクトリソースファイルを選択することで
この中から表示する画像ファイルを選択することができる

この方法によればソリューションフォルダの中に画像ファイルがそのままの形で保存されている
プロジェクト名のフォルダの直下にResourcesフォルダが作られており、この中に保存されている

この方法によるリソースの管理は単純なので>>434の方法より理解しやすいが
せっかくなので>>434の方法についても調べてみることにする (結局分からないかもしれないが
0436おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 08:04:38.15
>>435の方法についていくつか気づいた点

ソリューションエクスプローラのプロジェクト名を右クリック→プロパティ
→左側ペインからリソース選択

ここで開いているウィンドウだが、>>435で、「白いスペース」と書いたが、実際には
デフォルトでは文字列をリソースとして格納するウィンドウが開いており、白いスペースはない
ここに画像ファイルを放り込めば自動的にイメージ対応のウィンドウに切り替わる
対応するリソースの種類に合わせて手動でウィンドウを切り替えるには、ウィンドウのすぐ上の
項目の一番左側、デフォルトだと「文字列」となっているが、右の逆三角形のマークから
イメージ、アイコン、オーディオなどの選択ができる
白いスペースが表示されるのはイメージの対応ウィンドウとなったときだ

もう一点。
>>435の方法を採った場合に、画像ファイルをpictureBoxに置きたい場合
つまり、一旦リソースとして取り込んだ画像ファイルを実際にコードの中で呼び出して使いたい場合だが
デザイン画面のpictureBoxにフォーカスしたときの右上三角マークからイメージ選択する場合は
対応コードはForm1.Designer.csに自動生成されることになる
そうではなく、自分でハンドラなどから呼び出したい場合はこうする

pictureBox1.ImageLocation = @"C:\Image\aaa.jpg";

ImageLocationプロパティに、画像ファイルをフルパスで指定すればよい
Imageプロパティを使っても指定は可能なようだ
前述のForm1.Designer.csに自動生成されるコードもImageプロパティを使用しているようだ↓

this.pictureBox1.Image = global::TestProject.Properties.Resources.aaa;
//(TestProjectはプロジェクト名)

「global::」はグローバル名前空間のエイリアス、独習393ページで一応学習済
この場合なくても動いた

上の一行をusingを使うことで

using TestProject.Properties;

this.pictureBox1.Image = Resources.aaa;

こう書いてもいけた
0437おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 09:18:22.07
>>434のコードを分析

再度書き直すと、この方法は画像ファイルをForm1.resxというXMLリソースファイルに格納し
ここから画像ファイルを呼び出してpictureBoxに表示させるというものだ

>>434の最後に貼ってあるコードは、アプリを開いた時に該当する画像が表示されるよう
Form1.Designer.csに記述されたものだ。
このコードはコンストラクタを通じてアプリ起動時に読み込まれる
このコードのうち、大事なのは↓の2行

System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));

this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));

これらをusingを使ったとして、部分的に省略すると

ComponentResourceManager resources = new ComponentResourceManager(typeof(Form1));//@
this.pictureBox1.Image = ((Image)(resources.GetObject("pictureBox1.Image")));//A

となる。
この2行は、そのままボタンクリックのハンドラに移しても機能する
(↓では変数resourcesはrsに変更)

private void button1_Click(object sender, EventArgs e)
{
 var rs = new ComponentResourceManager(typeof(Form1));//@
 this.pictureBox1.Image = ((Image)(rs.GetObject("pictureBox1.Image")));//A
}

@についてだが、わからん、なにやらよくわからん
コンストラクタの引数typeof(Form1)はForm1という型に対するTypeオブジェクトだ

「指定した ComponentResourceManager の情報に基づいて、
サテライト アセンブリでリソースを検索する Type を作成します。」
https://docs.microsoft.com/ja-jp/dotnet/api/system.componentmodel.componentresourcemanager?view=netframework-4.7.2

ということらしいんだけど、わからん
ま、とりあえずForm1.resxを探し出すためのものと理解しておこう

Aについてだが、GetObjectは例えば画像以外にも音声などもresxから取得することになるため
戻り値の型はオールマイティーなobjectとなっている
ただし、ここで取得しているのは画像なのでImage型にキャストしている
0438おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 09:28:54.37
ちょいとまとめると

外部にある画像をリソースとして使うには大きくわけて2つの方法を学んだ

@resxファイルに格納する方法>>434
AResourcesフォルダに格納する方法>>435

そして、どちらにも言える事だが、
アプリ起動時に表示させる場合はForm1.Designer.csに
そのためのコードが自動生成されていることになる
起動後にボタンをクリックするなどによって画像を表示させたいときは
ハンドラ内に自分で記述することになる
ただし、コードの内容は自動生成であろうが自分で記述したものであろうが、
基本的に差異はない
0439おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 09:41:43.25
https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%83%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E7%94%BB%E5%83%8F

●ビットマップ画像
ビットマップ画像(ビットマップがぞう、bitmap image / bitmap graphics)とは、
コンピュータグラフィックスにおける画像の表現形式で、ピクセル(画素)を用いたもの。
画像をドットマトリクス状のピクセル群として捉え、
RGB等の表色系に基づいたピクセルの色・濃度の値の配列情報として取り扱う。

●ベクタ画像
これに対し、幾何図形を作成するための情報を数値や式として表現したものをベクタ画像と呼ぶ。
0441おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 09:55:42.70
@
継承 Object→MarshalByRefObject→Image→Bitmap

A
http://koshinran.hateblo.jp/entry/2017/06/30/223423
●System.Drawing.Image
ベクタ画像、ビットマップ画像問わず、画像を扱う為のクラス。
png、jpg、gif 等、さまざまな画像形式ファイルを読み書きできる。

●System.Drawing.Bitmap
ビットマップ 画像を扱う為のクラス。
System.Windows.Forms はビットマップベースの GUI 環境なので、
System.Windows.Forms を使った GUI プログラミングでは
Bitmap クラスをよく使用する。
だが、ビットマップに対する図形の描画などは
Graphics クラスを介して行う。


わかりやすいっす
ここでGraphicsが出てくるのですね
0442おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 10:03:56.26
>>441の@から分かるようにBitmapはImageの派生クラスでビットマップ画像に特化したクラスということになる
じゃ>>437のこれ↓を

private void button1_Click(object sender, EventArgs e)
{
 var rs = new ComponentResourceManager(typeof(Form1));
 this.pictureBox1.Image = ((Image)(rs.GetObject("pictureBox1.Image")));
}

こう↓書き換えたら・・・(キャスト先の型をImageからBitmapに変更)

private void button1_Click(object sender, EventArgs e)
{
 var rs = new ComponentResourceManager(typeof(Form1));
 this.pictureBox1.Image = ((Bitmap)(rs.GetObject("pictureBox1.Image")));
}

いけた!
0443おれさま ◆6CTEZS59O00a
垢版 |
2018/12/30(日) 10:07:22.08
今気づいたんだけど、pictureBoxに画像を設定したりごちょごちょやってると
いつの間にかForm1.resxにあった画像が消えてるというかResourcesフォルダに移ってる・・・?
何らかの連動性があるようだ
この辺については後回しにしていこうとは思うが
こういう現象から導き出される答えは、できるだけResourcesの方を使った方が今のところは安全だということなのかもしれない
■ このスレッドは過去ログ倉庫に格納されています

ニューススポーツなんでも実況