System.out.println("またJavaの季節がやってきた!" + 2);
■ このスレッドは過去ログ倉庫に格納されています
去年の今頃Java学習開始するも挫折 しかし不屈の闘志をめらめらと燃やしながら そびえ立つ岩壁にいどむため、再びこの地にやってきたのだ! プログラミング歴は独学Cチョビッツ+独学VBA少々 きょうかしょ https://www.amazon.co.jp/dp/484433638X スッキリわかるJava入門 第2版 (スッキリシリーズ) 結局、スイッチON/OFFの世界をどうやってうまく利用していくかなんだろうな すごいもんだ ちなみにだけど if ((artA & r) == 0b0001) { } ○ if (artA & r == 0b0001) { } ×(エラー) なので注意 これは演算子の優先順位が == のほうが & | より高いから 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とは違うよね確か。 まぁそういうわけでシード値を次々に変えていくために カウンター変数をシード値として流用 練習コードを書くときに乱数を使うとちょっと動きのあるコードを書けるので面白い シード値はJavaでも同じかな シード値のデフォルトが違うかもしれない めんどうなんで調べないけど スッキリわかるSQL入門 第2版 ドリル222問付き! (スッキリシリーズ) 中山清喬 ぽちった 5章やってたんだけどラムダ式が結構出てくる 先に押さえておきたくて10章に一時的に出張中 この辺はJavaでは薄くしかやってないので しっかりやらないと理解できない delegateから始める VBAのちょっとしたのを組まなければならなくなってちょいと中断 さっさと終わらせたい あああああ、vbaだいぶできてきたaa もう少し! いつもやらかすのは Range(Cells(i, j), Cells(k, l)) みたいにRangeの指定をCellsを使ってやるケース このとき、 With ThisWorkbook.Worksheets("なんとか") で囲ってるなら Cellsの前にもドットが必要なんだけど、これを忘れる そしてそれに気づかない 今日もやらかしてしばし作業がとまった C# Splitクラス 区切り文字はchar型なのでシングルクオーテーションを使わないといけない string型のダブルクオーテーションを使うとエラー すぐ忘れる あと、区切り文字で new[] を使わない時は { } をつかってはダメ 正規表現 \d{2,4} ○ \d{2, 4} × なんとスペース入れるとダメ 今気づいた こういうのって実際にコードを打ち込んでみて失敗しないと気づけない あと、おれはそんな記憶力良くないんで、実際にコード打たないと覚えた気になってて 実際は覚えてないということになる めんどうだけど、とにかくできる限り全てのコードを打って試していこう テキストのコードを自分なりに少し変えて試す いや、これがまためんどくさいのだが、ためになる 命令文の中に「:」が入ってくるようなクラスを説明する時に Console.WriteLineの中に「:」を入れるのはやめて欲しいわ そうでなくてもできる限り記号を入れないで欲しい 例えば Console.WriteLine($"位置:{m.Index} 長さ:{m.Length}"); とかいうコード Console.WriteLine($"位置は{m.Index} 長さは{m.Length}"); でいいだろ このコードでは「:」は混同の原因になりにくいかもしれないけど 例えば三項演算子とか入ってきたりした場合とか ふぅ 5章の重さは半端ないわぁ 2周目なんだけどしっかりやってるとなかなか進まない 1周目で理解しそびれた部分押さえるのが精一杯 せめて9章までやらないと基本分野網羅できない感じする ここまでやると コレクション オブジェクト指向の各分野 を大体押さえることができそう 新版のスッキリSQLも届いたのでちょくちょく目を通していこうかな GUIアプリをC#でつくるための参考書も買ってあるので のぞいてみたんだけど、JavaのSwingで作るよりずいぶん簡単そうな感じがする クラス定義の後ろの方に「:」があるようなコードが書いてあったのだが これはまだやってない分野だ 自動で作られたコードを隅々まで理解できるようになりたいので 独習の方を先に進めることにする 5章2周目クリア もう一周ぐらいやらないとダメなことは分かっているが 復習はまたあとにして6章に進む Dictionary で使っている Red-Black tree だけど、なるほどなぁ これは foreach で取り出すとき、できるだけ左側の下の方から探索していくのか こういうアルゴリズムって面白いな >>358 の「:」はインターフェースの実装だったようだ この辺はJavaと記述が違うからC系から引き継いだものかな コレクションも配列も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)); >>364 は (-x) - (-y) → y - x だな すっきりとちがって独習はたまに誤解を招きそうな表現があるんで気をつけないといけない おまえらぐらいだとこの程度の説明でわかるだろ?あ? みたいなのを感じる が、おれは残念ながら分からない この説明端折りすぎてんなと思ったらコードいろいろ書いて確認してる C#ではインスタンス経由でstaticメンバにアクセスできないのか Javaだとスッキリ入門で複数の勇者インスタンスが、共有のお金にアクセスするために static int maney を定義していたが、ああいうのはだめなのか 独習278ページ 「クラスメソッドはオブジェクト経由では呼び出さない」 Mathクラスがなぜ静的クラスなのかを説明している文だけど 関連した機能を一つのクラスにまとめることでわかりやすいから、 みたいな説明がされている これって説明になってないと思う そうじゃなくて、このような数学的な処理ってのは 引数を渡して即座に処理をして結果を返せば足りるんで いちいちデータをフィールドに格納しておく必要はないから ってのが最大の理由じゃないの そもそもインスタンス化の最大の利点はインスタンスごとに 異なるフィールド値を格納しておくことができる点でしょ そこを説明してないのってちょっとあれだと思うんだけどどうなんだろうか ちがうんかね 独習287ページ 値型の値渡し 参照型の値渡し 値型の参照渡し 参照型の参照渡し 今読んでてちょい混乱したけどもうおk 「値渡しはコピー」で 「参照渡しはこれをみてね」 みたいな理解でいけた これCでもやったような記憶があるがデジャブだろうか 面倒だがひとつひとつテストコードを自分で書いて確かめてみようか 自作のJavaプログラムだけど、ちょっと前から動かなくなってた どうやらJDKのパージョンアップにともなって仮想マシンにアクセスできなくなっていた ユーザー側の問題になるんだけど、バージョンアップ程度で環境変数やらいじらせるのっていまいちだな やっぱwindowsアプリつくるならC系なのかね 素数かどうか調べるプログラムに感心した 平方根となる小数を切り捨てて整数にする この整数の値になるまで2から順に除算をして 余りが0になるものがあるか調べる ヒットする場合は素数ではない var prime = true; for (var i = 2; i <= Math.Floor(Math.Sqrt(num)); i++) { if (num % i == 0) { prime = false; break; } } 中学校の数学で必死こいてやってた作業と全く同じだ 「真ん中」まで調べる的な IEnumerable<>を戻り値として使うイテレーター構文は foreachを簡単に使えるようにするために利用される (foreachを使えるようにIEnumerableインターフェースを実装するのは大変なので) ポイントは yield return (と、yield break) 独習318ページの3.@の解答 readonlyと書いてあるけどprivateだよなこれ いちいちここに書いてないけど誤植がちらほらある 誤植だと思い違いしてるケースも考えられるので実際困る プロパティはセッターゲッターつまりアクセサーメソッドの発展系 インデクサーの説明わかりにくいなあ インスタンス名[index] でインスタンスを利用したいときに使うみたいな感じか フィールドが配列の時に使うとうまい具合に組み合わさって利用価値があるみたいな インスタンス名[ ] の形式で利用したいなら自由に使えるようなものなので 例えば[ ]の中が要素番号的なものでなくても使えると。 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」 } } で、フィールドが配列の時に、インデクサーを組み合わせて使うと 真価を発揮できると(まるで真価を発揮できてない例だが・・・・ 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」 } } this[string st] this[int index] の部分が大事で、こういう使い方をすると便利だなと思うような場面で使えば良いのかな 特にインスタンスを配列ライクに使いたい場合 インスタンスをforで回しながら何かをインスタンス内のどこかに代入していきたいとか 忙しくなってきて時間裂けなくなってきたけど 少しずつでもいいんでやっていこうと思う マッマに新しいPC買ってもらっただで 今までは簡単なアプリをGooglePlayにリリースしてきたけど、ようやく本格的なアプリが作れそうや あとは今運営してる比較サイトもAjaxで非同期にデータベースとアクセスできるようにしたい Googleが提供してるFireBase使えば、サーバーサイドの開発する必要すらないみたいやな 便利な時代になったで ぐぐるさんは優秀なapi無料で公開してくれてるからありがたいんだけど セキュリティ固めてる環境からアクセスするようコードに仕込んでると そのうち担当者から怒られそうなのがネック ふぅ 8章まで終わった 覚えてるのかと言われたらスッカスカだが一応理解はした スッカスカで先に進むと理解できなくなりそうだが ここは敢えて進むのだ >>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) こんな風に ちょいGUIに寄り道する 入門本買ってあるので簡単なものを作れるようにしていく Javaの時と同じ流れでやっていく slnファイルをクリックするとそのソリューションがVisual Studioで立ち上がる ふむふむ 違う本読むとまたそれはそれで勉強になるわぁ Visual Studioの使い方適当にやってたけどいろいろと説明してくれててありがたい オブジェクト指向がどういう流れで生まれてきたのかとか、 この辺は著者によっていろんな説明してくるけど、この本の説明は頭にすっと入る データベースの誕生に関連させてオブジェクト指向の誕生を説くあたり + 別のプログラムを組む時に、他のプログラムから一部借用してきたりとか、そういう再利用のしやすさ ふーむ これはVBEのフォーム組むのとすごーく似てるね VBAのプロパティってC#のプロパティと同じものなのか オブジェクト指向のインスタンスやプロパティ、メソッドをコードからじゃなくて VisualStudioのGUIを使って説明するとか斬新だわ あと、デザイン画面でぽんぽんとコントロールを貼り付けていくと 勝手にコードが背後で生成されていくわけなんだけど このコードも理解したいな JavaでSwingで試してた時は全部自分で書いてたわけで C#では相当楽できるんだが、仕組みは分かっておきたい パーシャルクラスとかさっき勉強したばかりのを使ってて復習にもよさそう Program.csがMainメソッドを持つ主か ここからスレッドを走らせ 編集対象となっているForm1.csのForm1クラスのインスタンス生成 Form1クラスのコンストラクタがInitializeComponentメソッドを呼ぶ これはデザイン用に用意されているForm1.Designer.csにあるメソッドで ちょうど、Swingでコンストラクタの最初の方に書いていたようなコントロールの配置とかが書いてある 各コントロールの実際の動きはForm1にメソッドとして記述していくわけか Javaでのイベント系の処理とどの程度類似してるか そっくりというわけではなさそうだ この辺を理解するには独習の最後の最後を読んだほうが良さそうだ いろいろ調べてみたんだけど、マルチキャストデリゲートなのかな それだけでは説明できない要素が加わっているようなので、これを理解するには 独習の最後、ほんとに最後なんだよなこれ、ここを読むほうがよさそう で、明日読もう 今日は終わり 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はまだよく分からない 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 で理解出来そうだ なんとなくだけど、分かった気がする ハンドラ、つまり、実際に実行されるメソッドなんだけど、これに情報を渡したい時がある このとき、場合によってどういう情報を渡したいのかは様々なので、 自分でクラスを作ってそこに情報を記録してわたせということか。 その際、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#でやろうとしても、ちょっと勝手が違う 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 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 という情報を引き出せたことになる 一応満足した ((MouseEventArgs)e).X ((MouseEventArgs)e).Y 相対座標もこれで取得できる ラベルの左上が原点かな?たぶん C#はこの辺の理解全くなしでGUIアプリを組めるという点では楽だな その反面理解なしに進んでしまうから、そのうち壁にぶつかりそうだけど これまでコンソールアプリだとVisualStudioの画面に、 windowsアプリだとMessageBox.Show()でメッセージボックスに 文字情報を出力してきたけど これからはフォーム上に作ったテキストボックスに出力する方がよさそうだ こぴぺもできるしね ここにコード貼るときにタブというかスペースを加工しないと うまくインデントを表現できなかったので、正規表現使えるエディタで置換してた ただ、ちょっと使いづらい そこで、この加工をする専用のwindowsアプリを自分で作ってみようかなとか思ってる 簡単そうだし役に立ちそう でけた〜 初のC#アプリ やっぱりC#は簡単に作れるなぁ 正規表現でちょっと迷ったところがあったけど サブマッチパターンに名前を付けて処理することで解決した 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個がないと仮定するならもっと簡単なのだが そこはこだわってちゃんと作ってみた 貼ってあるコードは、もちろん作ったばかりのアプリで置換作業をしたもの。 windowsアプリの入門本使っていくつか作ってるんだけど簡単に作れるわ 今の知識だけでもいろんなもの作れそう Javaでも外部ライブラリやら導入すればもっと簡単にできたのかもしれないけど VisualStudioだと追加導入の手間いらずでこれだけ作れるのはすごい 今ちょうど>>119-121 に相当するコードを書いていたのだけど、ずっと簡単にかける 前回閉じた場所で開く機能も試しにやってみたいがどうすっか 閉じたときの場所をlocation.logに記録して 開いた時にlocation.logから座標を読み取って再現するという Javaでもやった例のパターンなんだけど 開いた時にロードする時、当然コンストラクタに記述するんだろと思いきや windowsアプリだとイベントとして記述するみたいだ これも斬新だな 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を呼び出してモニタ中央に表示させる フォームを開く時にモニタ中央に表示させるコードとしてこういうものがある this.StartPosition = FormStartPosition.CenterScreen; これを使うのであれば、コンストラクタに書く必要がある 上のロード用のイベントハンドラはどうやらフォームが表示されたあとに動いているようだ ハンドラにStartPositionを書いてしまっても今更ということになってしまう そのため、SetCenterメソッドでは、 すでに表示されているフォームの位置を変更するという形をとっている 例えばカレンダーをつくるとして、日付を表示するパネルが42枚並んでるとする このとき各日付パネルをクリックすることで何らかのアクションを起こしたい時 Form1クラスに42個のイベントハンドラを並べるのはどうなんだと思い調べてみた https://dobon.net/vb/dotnet/control/buttonarray.html 配列を利用することになるんだけど いくつかの方法があるようだ 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座標が記録されている場合でも、そのままの座標で開いてしまう メインモニタ上では機能するので、とりあえずいいか あーちょいまてよ 正規表現にマイナスが含まれてないな この辺でおかしくなってそうだ 今いそがしいからあとから触ってみよう >>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; これでサブモニタでマイナス側に飛び出しても大丈夫 可能性として、下とか左に飛び出す場合もあるわけで そういう場合には対応できていない そう難しいわけではなさそうだけど >>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; } } >>408 uintは座標がマイナスの場合しか使えないロジックなのでやめやめ こんな風にした 保存してある座標をそのまま使って一旦フォームを表示させる もちろんlocation.txtがないとか、数値が想定通りに記録されてない場合はメインモニタ中央へ表示 その上で、フォームがモニタ画面から飛び出し「すぎてる」場合はメインモニタ中央へ移動 RemainLimit = 0.6はフォームの幅・高さの6割がモニタ画面に映っているならOK それを下回ったらメインモニタ中央へ表示、という定数 これで上下左右・メインモニタ/サブモニタ関係なしにオールマイティにはみ出し補正可 resultのロジックだけど result = result && (〜〜〜); でやってたんだけど、もしかしてとおもって result &= (〜〜〜); にしたら行けたんでこれにした 要は if を並べて階層深くしたり、条件式が長くなるのが嫌だっただけなんだけど これはクラスにまとめてこれから作っていくアプリにも使っていこうかなぁ〜 フォームを一旦表示させてから問題あるなら移動させるという2段階の方法を採った理由は 一度に所定の位置へ置こうとすると、scr.X とかがうまく取得できなかったから どうでもいいような部品なんだけど うまくいったんで満足である 独習はまだしっかり頭にはいってないところがたくさんあるけど 辞書的に使うのにも適してる 今のGUIの入門本しばらくやってから、独習の残り1割ぐらいだけど まだ読んでない部分読むか 復習も何度かしないといけないな >>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が登録されているのがわかる 複数コントロールを一括してひとつのハンドラにまとめるには 対象となるコントロールをぽちぽちと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ハンドラに記述されている処理が実行されてしまう パネルが選択されたかどうかは、デザイン画面上は非常にわかりにくく間違いを招きやすい 選択されたオブジェクトが羅列されているウィンドウは見当たらない 注意深くやっていくしかないというところか ところで、>>413 のようにミスしてしまった場合の対応なのだが、 実際、どのオブジェクトがどのハンドラの支配下にあるのかは>>412 でわかるように 「隠された」コードを見るしかない しかも、この部分にはこんなコメントが記述されている /// <summary> /// デザイナー サポートに必要なメソッドです。このメソッドの内容を /// コード エディターで変更しないでください。 /// </summary> >>413 の「//←ここ」の行を削除すればいいんだろうなということは 今まで貯めた知識で分かってはいるんだけど、本当にいいんだろうかと。 別の方法により、「自動的に」削除させる方法があるんだろうか まぁよくわからないので、マイクロソフトさんに逆らって勝手にコードを削ることにする この辺の知識なしでVisualStudioをさわる人はどう処理をしているのか もう一度対象オブジェクトを全て削除してから自動生成し直しているのかな なんだかんだこだわって理解しようとしてると、そのうち役に立つもんだ >>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での省略は逆に足手まといになるのかな イベントドリブンモデルについて再考 >>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なので、これに対応した形になっている >>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); } } VisualStudioでは、ボタンクリックなどで使われるデリゲート型変数の初期値は どうなっているのか調べてみた >>412 に従って表示されたbutton2.ClickのClickにカーソルを合わせて右クリ →定義へ移動 public event EventHandler Click; 初期値となる空メソッドは代入されていないように見える public event EventHandler Click = (sender, e) => { }; こう書き加えてやろうと思ったがもちろん勝手には書き込めないようだ 中身となるメソッド(ハンドラ)が自動生成されて、自動で代入されていくので 初期値がないことによって生じる問題は基本的には起きないと想定した結果か 忘れてた >>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); } } 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() がそれか 派生クラスの名前は Form1.Designer.csを見ても分かる this.button2 = new System.Windows.Forms.Button(); ボタンには Buttonクラスのインスタンスが代入されている フォームの大きさを変えたときにボタンとかテキストボックスが自分の思う通りに 追随してサイズを変えたり、または固定されたり・・・といったことをやってた SplitContainer→FixedPanel, IsSplitterFixed TableLayoutPanel などなど・・・ なれないと思った通りにするのに時間かかる イベントハンドラの中で、Form1の座標を取得したいとき、 イベントハンドラに渡されるsenderの実体がForm1の時は問題ない ((Form1)sender).Left ((Form1)sender).Top senderの実体がButtonの時は同じようにやってもエラーが出る ButtonなのにForm1型にキャストしようとするからだ この場合はこうする ((Button)sender).FindForm().Left ((Button)sender).FindForm().Top Buttonが位置するFormを取得するメソッドFindFormを使えばいい 自分で気に入ったアイコンをexeファイルやフォームに表示できるようになった! TableLayoutPanel内にコントロールを並べてるのを忘れてると これらコントロールのサイズを変更しようとしたときに動かなくて あれれれれ と思う事があるので注意 TableLayoutPanelで1行2列の2セルにそれぞれテキストボックスを置いていたんだけど 2つのテキストボックスの間にSplitterを挟むことでテキストボックスの幅を ユーザーが自由に変更出来る仕組みにしようとした 上の記述はこの時遭遇したトラブル TableLayoutPanelのセル内でもコントロール配置場所は、該当するコントロールの Anchor,Dockプロパティによって影響を受ける そもそもの話になるが、Splitterを使う場合はTableLayoutPanelは使わないので排除する Splitterを使う時はこれと接するコントロールのDockプロパティの使い方に注意 >>427 のように、2つのtextboxを横に2つ並べて、その間にSplitterを置く場合、 1つ目の左側に置くtextboxのDockプロパティはLeft Splitterは自動的にLeftに設定され 2つ目の右側に置くtextboxのDockプロパティはFill ←ここ大事 右側をFillにしないと実行時にSplitterにカーソルを合わせてもカーソル表示が変らないし 幅を変えることもできなかった 入門本にgmailチェッカーが載ってたので作ってみたんだけど テスト用にあらためてgmailアカウント新規でとろうと思ったら電話番号要求してくんのな でもってSMSとかで確認するとか あほらしくなって昔取得したアカウント引っ張り出してきて使うことにした でも結局gmail側のセキュリティ機能が働いてちゃちなアプリではアクセスできないことがわかったので終了 ツイッター投稿アプリも載ってたので作ろうと思ったのだが ツイッター側からアプリ作成に必要なAPIキーをもらうために 開発者用アカウントをつくらねばならない これまた電話番号登録しろと出る これもいやなのでパスでーす >>415 について プロパティウィンドウでイベントを表示させると、 登録済のイベントがあれば右側にハンドラの名前が表示される これを右クリ→リセットすればForm1.Designer.csからも該当コードが自動的に削除されるようだ 1. VisualStudio自体を複数開くことができる ソリューションはslnファイルから直接ひらくことができるが 複数のslnファイルを順々にクリックしていけばどんどん新しいVisualStudioのウィンドウが開いていく デザイン画面で、複数の設定がめんどくさそうなコントロールを選択してctrl+c 別のVisualStudioのデザイン画面でctrl+vをすればこぴぺもできる 2. 全然別の話だが、clickイベントとmouseClickイベントの違い mouseClickはそのまんまだけど、clickイベントは、例えば ボタンにフォーカスがある時にキーボードでEnterを押すことでもイベント発生可能 グラフィックについて ざっとみたところ理解しないといけないクラスとして 1.Graphics 2.Image 3.Bitmap 入門本では説明が簡略化しすぎてるので、自分で調べないとダメだ グラフィック関係については一体どこから手を付ければいいのか難しいところだ そもそも外部から持ってきた画像を表示する方法を明確にしていかないといけなさそうだ つまりリソースの管理を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を使っていないと長ったらしく非常にわかりにくい と、ここまで書いて気づいたのだが、 入門本で初めてフォームに画像を表示した方法はこの方法ではなかったようだ 具体的にはこうやった ソリューションエクスプローラのプロジェクト名を右クリック→プロパティ →左側ペインからリソース選択 中央に表示される白いスペースに外部の画像ファイルをDDして放り込む すると、>>434 でもやったが、pictureBoxの右上三角マーク→イメージの選択 (ここでローカルリソースから外部画像ファイルを選ぶのが>>434 の方法だ) →プロジェクトリソースファイルを選択することで この中から表示する画像ファイルを選択することができる この方法によればソリューションフォルダの中に画像ファイルがそのままの形で保存されている プロジェクト名のフォルダの直下にResourcesフォルダが作られており、この中に保存されている この方法によるリソースの管理は単純なので>>434 の方法より理解しやすいが せっかくなので>>434 の方法についても調べてみることにする (結局分からないかもしれないが >>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; こう書いてもいけた >>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型にキャストしている ちょいとまとめると 外部にある画像をリソースとして使うには大きくわけて2つの方法を学んだ @resxファイルに格納する方法>>434 AResourcesフォルダに格納する方法>>435 そして、どちらにも言える事だが、 アプリ起動時に表示させる場合はForm1.Designer.csに そのためのコードが自動生成されていることになる 起動後にボタンをクリックするなどによって画像を表示させたいときは ハンドラ内に自分で記述することになる ただし、コードの内容は自動生成であろうが自分で記述したものであろうが、 基本的に差異はない 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等の表色系に基づいたピクセルの色・濃度の値の配列情報として取り扱う。 ●ベクタ画像 これに対し、幾何図形を作成するための情報を数値や式として表現したものをベクタ画像と呼ぶ。 @ 継承 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が出てくるのですね >>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"))); } いけた! 今気づいたんだけど、pictureBoxに画像を設定したりごちょごちょやってると いつの間にかForm1.resxにあった画像が消えてるというかResourcesフォルダに移ってる・・・? 何らかの連動性があるようだ この辺については後回しにしていこうとは思うが こういう現象から導き出される答えは、できるだけResourcesの方を使った方が今のところは安全だということなのかもしれない すでにある画像を読み込んだり、キャンバスを用意したりするのがImageやBitmapクラスで 四角や円や線などを書き込む筆のようなクラスがGraphicsクラスかな https://so-zou.jp/software/tech/programming/c-sharp/graphics/ Graphicsオブジェクトの取得 3通りの方法が紹介されているが入門本では3つ目の方法を使っている ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる