System.out.println("またJavaの季節がやってきた!" + 2);
■ このスレッドは過去ログ倉庫に格納されています
去年の今頃Java学習開始するも挫折 しかし不屈の闘志をめらめらと燃やしながら そびえ立つ岩壁にいどむため、再びこの地にやってきたのだ! プログラミング歴は独学Cチョビッツ+独学VBA少々 きょうかしょ https://www.amazon.co.jp/dp/484433638X スッキリわかるJava入門 第2版 (スッキリシリーズ) Swingをいれてみた JavaFXはいろいろエラー吐いてうまく行かないというか原因がよくわからんから SwingをGUIの部品として採用 Swingのいいテキストあったら買いたかったけど古いのしかないからネットで知識漁ることにした 最初はシンプルな作りで十分だし https://www.javadrive.jp/tutorial/ ここみながらぼちぼちやっていく windowsbuilderとかscenebuilderとか使ってウィンドウ作って行くとダメだな あれは理解出来てる人が使うものだ いやっほおおおおおおお週末だぜいぃ! JavaJavaすっかね ごく基本的な構造そなえたウィンドウを形成するコードは暗記することにする 何度も繰り返し書くのである ActionListener関係はちょっと複雑であり しかも重要性高いので慎重にいくのであります 原理をちゃんと理解するのである ActionListenerと書くと高確率でスペルミスをする eがなかったり 多重継承がここででてくるんだよな いろいろ基本の復習勉強できていいかもしれない ちなみに継承なのか承継なのかいつも迷う 承継は小計みたいだからだめ!と覚えよう extends JFrame implements ActionListener !!!! GUIの基本であるこの辺でみられる技は見事だな extendしたJFrameのメソッドをコンストラクタで使うあたりとか プロの技って感じです こういう風に使うんだなぁと public void actionPerformed(ActionEvent e) { System.out.println("腹減ったしメシくうか"); } GUI分野の部品はこれで大体完成 次は定期処理の部品を学んでいく予定 ざっとみたところ学習する内容は TimerTask Timer ScheduleExecutorService あと、前から気づいていたんだけど、クラスを今までに学んだことのない方法で使ってるのをみかける どうやらこれを無名クラスとか匿名クラスとか呼ぶようだ わかりにくいから普通の使い方に書き換えて今まで使ってたんだけど 頻繁にでくてくるのでちゃんと頭に入れた方がよさそうな気もする 定時処理難しいな windowsのタスクスケジューラに任せることにしよう とするとGUI使わないほうがよさそうだな まぁ今の段階ではそれでいいか GUIアプリで 開始ボタンを押すことで毎日定時に処理するようにする 停止ボタンを押すことで定時処理を停止させる をやろうとしたんだけど、いろいろとまだ知識足りない threadとかの知識も必要なんだけど実践編でもあまり書いてなさそう thread interrupt とか使うといけそうなんだけど、いろいろと問題も起きそうで それを回避するための仕組みがイマイチ難しい おれの作った最初のソフトウェアでけたああああ ショボイけど グローバルIPアドレスを記録していくプログラム 実行すると、実行ファイルと同じフォルダにテキストファイルを作成し グローバルIPアドレスを日時とセットでかき込む (ついでにプライベートIPアドレスもセットでかき込む) 実行するたびに同じファイルに追記していく 年ごとにファイルを新しく作っていく タイマーは難しかったんでwindowsのタスクスケジューラで毎日定時に実行することにした おれの環境は時々IPアドレスが変わるんで いつ変ったのか知りたくて自動で記録していくフリーソフトないかなと探してたんだけど よさそうなのがなかった 単純な動きなので自分で作れたらなぁと思ってた 問題はタスクスケジューラが正常に動いているかだ 壊れちゃってたのが治ってなければ意味なし どうやらタスクスケジューラでjar実行ファイルを起動するときは javaw -jar C:\〜パス〜\test.jar みたいにしないといけないみたいだ exe化してもいいんだけどどうしようかな うーむ 不思議なことにexe化してもしなくてもタスクスケジューラから起動すると挙動がおかしい 一瞬コマンドプロンプトが表示されて、 System.out.prinlnで指定した文字列が見えるからプログラムの一部は動いている感じはする でもテキストファイルを作ってくれない ためしにバッチファイルをかましてみようと思い作成、 ひとまず手動でバッチファイルを起動してみたらバッチファイルが消滅 おいおいアバストさん・・・・ もしやおれのプログラムもまさかこいつが・・・ と思ったがどうやら違う アバストを停止させてもテキストファイルを作ってくれない バッチファイル噛ませばいけるならそれでいいか 1個しょぼいの作ったらPythonに目移りしてきた どどどどどどどどどどどしようかすら GUIを作りたいんだよな そうするとWPFとかいうのがヒットする C#なのか そうなのかそうなのか どどどどどどどどどどどどどどどしようかすら てかもう1個Javaでしょぼいのつくろうかな 今欲しいプログラム思いついた 時計作った USA東部時間をサマータイム込みで知りたいこと多いから常時表示させるやつ いろいろと問題にぶち当たったけど、一応役に立つものができあがったんでOK あと、アマゾンでプログラミング関連の本注文しまくってしまった C# python javascript 一応しばらくはJava中心だけど気が向いたらほかのもやろう すっきりの実践編を読み終えたいな 入門編も完全に自分のものにしたとも言えないし HTML・CSS・Javascript関連の初心者本に浮気してる HTMLはずいぶん昔に多少勉強したことあるんだけど、 当時はいかに見せるかに力点がおかれてたと思う 今は最初から入力欄やボタンやらを紹介するのな 利用してもらうってのが先にある ずいぶん変ったもんだ 作った時計プログラムのタイトル消して ウィンドウごとDDして移動させたり、右クリックメニュー付けて終了できるようにしたりしてるんだけど なんだかググって適当にコピペしてるだけでなんとなくできてしまうのはいいんだろうか・・・ イマイチ理解できてない部分もあるんで後々ちゃんとやっていこうと思ってはいるんだけど 大体欲しかった機能付けられた 前回閉じた場所で開く機能をつけたらほぼ完成だな 機能追加のために足りない知識を補う目的で部分的に実践編読んでるんだけど やっぱネットと違って説明がしっかりしてていいわぁ ちゃんと読む価値あるなといまさらながら思った 最低限実践編までは読まないと、無駄に時間食う 前回閉じた場所で開く機能も付けた iniファイルを作って座標を保存しておくタイプにしたんだけど ファイルが消えちゃったとか中身がおかしくなっちゃったときとか いろんなトラブルに対処できるようにするとなかなか難しい ある程度対処できたけど、まだ完全じゃない ファイルのclose()は必ずfinallyで記述するのです と思ってたけどエレガントな記述方法があると次のページに! 単純にテキスト流して読んで問題といて頭に入っていくかというとそうでもない そこで、 簡単な機能ではあるけど、自分が必要だと思うコードがふんだんに含まれる プログラムを用意してこれを何度も書いて覚えることにする 学習の骨格がないと肉付けする過程でぐらぐらゆれちゃってなかなか覚えられないんで 骨格部分をちょっと頑張って頭にいれよう ウィンドウ操作とかいろいろできるようになってきた おもろいなぁ APIレファランスだっけ、だんだん読めるようになってきた もう一度すっきり入門編の後半読み直したいな あの辺大事だわ ヤフーの天気予報を表示するようなwindowsアプリってどういう風にサーバから情報を得てるんだろうと思ったんだけど、 ヤフーがそのためのAPIを提供してるんだな おそらくアプリ作った人が自分が運用してるサーバで情報取得する 配布した個別のアプリはそのひとのサーバに接続して情報取得する こんな感じなのかな ヤフーに直接接続するとなるとアプリケーションIDとやらが必要となるそうなので現実的ではないんで、こういう感じで間接的に情報取得してそうだ もし自分だけで利用するアプリつくるなら、ID登録後に直接ヤフーから情報取得すればよさそう 天気予報を常時表示してくれるソフトは昔から使っているんだけど そのソフトの情報取得先のヤフーが提供するデータに明日の天気がないらしい そのため明日の天気が表示されない そこで、明日の天気だけを表示するちっこいソフトをつくろうかと思う APIを使うとたぶん同じことになるんでHTMLから適当に抽出してやろうと計画してる しかしだ、頻繁にHTMLを変えられてしまうとなかなか難しいかもしれない http と https ではHTMLの取得方法を変えないといけないのか 文字化けするから文字コードがらみでいろいろ調べてたんだが違っていた URLクラスではなく URLConnectionクラスを使ったらHTML取得までうまくいった いや、ちがうな・・・ URLクラスでいける この辺はいつか解決する課題として残そう char型使って読み込んでいく最も入門的なコードだと、どこかで文字がおかしくなる StringBuilderが原因かと思ったがそうでもなさそうだ ふぅ・・・ひとつひとつ壁があるわい お天気マークのgifをそのままフレームに表示させようと思ったがなぜかできない ローカルにある画像ファイルならいける いろいろ調べたらようやくわかった URLクラスのインスタンス使わないとだめなようだ つまり ImageIcon ii = new ImageIcon("./img/aa.jpg") はおkだけど ImageIcon ii = new ImageIcon("http://www.eee.jp/ee/aa.jpg" ;); はダメ ローカルにない画像使いたい時は、一旦 URL url = new URL("http://www.eee.jp/ee/aa.jpg" ;); として ImageIcon ii = new ImageIcon(url); とするのが正解 おれさま!がんばってるな!見ているからこれからも頑張って https://dotup.org/uploda/dotup.org1654406.jpg まだ途中だけど、こんな感じでいく アイコンはヤフー天気からそのまま借用 データは全部普通にヤフー天気開いた時に取得するHTMLから 必要な部分切り出して利用した ヤフーがURLやらHTMLの中身を変えちゃうと表示できなくなる でも自分で作って自分でしか利用しないからこれで十分だ あと付け足さないといけない機能は 数時間おきにデータとりに行く機能と右クリメニューから閉じる機能 あと、前回閉じた場所で開く機能 どの機能もいままで作った2つのプログラムから借用できるので大した事はない 機能完備して完成 なんだけど、さっきググってたら面白そうなの見つけた おれのお天気表示プログラムはヤフー天気のHTMLを取得して特定ルールのもとで splitを使って分割、配列に格納してる この特定ルールなんだけど、できたらタグを目印にぶつぶつと小間切れにしていく方向でやりたかった しかしだ、正規表現<.*>を使って表現したタグでsplitすると たとえば、このHTML <div>ちんちん</div> <p>まんまん</p> を配列に格納すると 要素番号0 ちんちん</div><p>まんまん 要素番号1 (なし) となってしまう 本来は 要素番号0 ちんちん 要素番号1 まんまん とならなければならない どうやら * は「よくばり」らしくて、途中で > が表われてももっと後ろに > があれば まだまだいけるだろーとどんどん先へ進んで行ってしまうようだ それが分かったあと、まぁ正確にタグで区切る必要も無いだろうと考えて < 記号でsplitしてたんだけど・・・・・ <.*?> という書き方があるそうだ これでやると 要素番号0 ちんちん 要素番号1 まんまん が実現できるそうだ この ? 記号は普通の ? 記号(直前パターンの0回か1回の繰り返し)ではなく * の「よくばり」を消し去る効果をもつらしい つまり、タグの中を * が進んで行く途中で、 > が現れた瞬間にそれ以上進むのを諦めてくれるそうだ これを「最短一致」という デフォルトは「最長一致」なのだが、最長もこれはこれで使えそうだ 最短一致は正確には→の方向に進んでいく場合の最短一致で 逆方向には働かないので注意 >>52 を修正 要素番号0 ちんちん</div><p>まんまん 要素番号1 (なし) ↑間違い 正確には↓ 要素番号0 div>ちんちん</div> (改行記号が入る) <p>まんまん</div 要素番号1 (なし) せっかくだからこれで書き直してみようかとおもおとる おれが今使わせてもらってる誰かが作ったお天気表示ソフトなんだけど iniファイルをみたら、おれが利用してるヤフー天気のHTMLと同じURLが書いてあった とすると、このソフトはおれと同じようにHTMLを加工して作っているのでは・・・ もしそうならヤフーがHTMLを改変し、おれのお天気表示ソフトが正確に表示されなくなったタイミングで このソフトも同じ症状を見せるんではないかと思う もちろんHTMLの分析の仕方いかんで、そうとも言い切れないだろうけど、観察してみる価値ありだ ちなみにだけど、 <.*?> でタグを表現する方法は不完全らしい しかし、その不完全さを理解するにはもうちとHTMLやらweb系の知識がいるようなので後回しにしていこう >>54 を修正 要素番号0 div>ちんちん</div> (改行記号が入る) <p>まんまん</p 要素番号1 (なし) そういや気温表示がなかった これ付けておきたいな 特にこれからの季節寒いんで 複数ラベルについてforやら使ってまとめてコード書こうとしたら大変な目にあった ラベル名の一部に数字使ってこれを変数に置換えてforで回す方法はないかと模索したができないようだ つまり for (int i = 0; i < 5; i++) { label_i.setText("おほほ"); } みたいのはだめ 配列使う方法で代用できそうなので試してみたが、ここでまた問題勃発 JLabel[] lbl = new JLabel[5]; for (JLabel bb : lbl) { bb.setText("むほほ"); } これでだめときた あの有名な ぬるぽ が出てしまう ぐぐりまくってようやくわかったのが このコードではJLabelのインスタンス化が済んでいないということ。 配列の作り方とインスタンス化が結構似てるんで両方が組み合わさると混同してしまうのがポイント 正解は JLabel[] lbl = new JLabel[5]; //←ここでは配列変数と配列の実体が作られただけ for (JLabel bb : lbl) { bb = new JLabel(); //←JLabelのインスタンス化のためこの1行が必要! bb.setText("むほほ"); } さらにforの中でswitchを使ったのだが 案の定break;を忘れて、忘れたことに気づかずに試行錯誤1時間ですわ main factory already defined exewrapを使って作ったexe実行時にこのエラーが出るのは 実行可能jarファイルをエクスポートするときライブラリー処理を 上から2番目の選択肢にするから。 一番下を選択すること 隣のサブフォルダにコピーするとかなんたらこうたらのを選択 カレンダーをデスクトップに表示してるんだけど こいつ、祝日を判定できない 次はカレンダーづくりか・・・? 祝日のAPIも誰かが作ってくれているようだ http://s-proj.com/utils/holiday.html 便利だの〜 祝日自体そう多いわけでもないから 内閣府が出してる振替休日込み祝日等のcsvをそのまま使うっていう手もあるな ん〜 そういえば定期的な実行にthreadとsleep使ってたんだけど これはあまり良くないとかいうのを読んだ もう少し基礎力アップさせてから次のソフトに挑んだ方が良いのかもしれない 今のままでもいろいろ作れることは分かったけど、もう少し基礎知識の幅の広さが欲しい Swingを使ったWindowsアプリを作っていると 継承の知識をちゃんと生かしていかないと理解できなくなる 右クリックメニューの項目を作るためのメソッドがあるんだけど、 これにActionListenerクラス型変数「のようなもの」を引き渡さないといけなかったりする 「ようなもの」というのは、そもそもActionListenerはインターフェースでインスタンス化できない 今の知識ではこれをなんと呼ぶのかよく分からない ここで、引き渡す際の実引数にthisを使うとなぜかうまくいく 適当にやったらうまくいったのだが、自分でやっていて頭が混乱してしまう 落ち着いて考えてみたら理解できた つまり、まず、 クラスの宣言でこうやってる public class Main extends JFrame implements ActionListener そしてmainメソッドで Main mm = new Main(); のようにインスタンスを生成している ここでthisとは何を指すのかと言えば Main型変数mmということになる このmm、実はActionListener型変数(のようなもの)でもある なぜかというとMainクラスはActionListenerを実装しているからだ だからthisでうまくいくのだ・・・・(と今のところ思っておこう インターフェースはインスタンス化できないだけで インターフェースの変数は作れるということかな ActionListener al みたいのはそういうもんか あと、 インターフェースのインスタンス化に絡んで分からなくなるのが匿名クラス JButton btn = new JButton(); btn.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { } } ); みたいなやつ これもActionListenerをnewしてるからおかしいじゃん!って思うんだけど ぐぐってみたら、これは、みためはインターフェースActionListenerをnewしてるようで 実はActionListenerを継承した匿名クラスをnewしてるんだそうだ すっきり入門を読んでいる段階では、 オブジェクト指向というものはわかりやすくメンテしやすいコードを書くための技法であって 一歩先へ進みたいなら理解しておいたほうがいいよって程度に思えたんだけど 実際windowsアプリ作り始めると、基本的なコードを理解するのに必須な知識だと分かる 理解できてないと話にならないというレベル まぁまだ理解仕切れてないし忘れちゃってる部分もあるんで読みなおそっと MainクラスにActionListenerを実装させない方法だと、 btn.addActionListener(new al()); として、これとは別に実際の処理を任せるクラスをつくる public class al implements ActionListener { public void actionPerformed(ActionEvent e) { } } こういうのがどちらかというと基本のコードだから >>65 の匿名クラスのnewというのは、ここでいう al みたいのをnewしてるってことか jarのままだとタスクマネージャやらにファイル名が表示されないから 基本的にはexewrapを使ってexe化している しかし何度もコマンドプロンプト開いてうだうだ繰り返しやってると煩わしいので D&Dして処理するできるようバッチファイルを作った @echo off if %~x1 == .jar ( exewrap -g %1 ) else ( echo .jarではありません。 ) pause 久々にバッチファイルについてぐぐってみたんだけど 意外といろいろ出来ちゃうんだということを思い出した パネルの上にもう一枚枠線だけで中身は透明のパネルをかぶせることで すこしだけおしゃれにしてみた この2枚重ねのパネル、簡単だと思ったのだが以外とつまずきが多かった JPanel pnl_1 = new JPanel(); Jpanel pnl_2 = new JPanel();//こいつを透明化して枠線だけ設定することにする pnl2.setOpaque(false);//透明化 Container contentPane = getContentPane(); contentPane.add(pnl_1); contentPane.add(pnl_2); でいけるだろ〜と思ったら大間違いだった こんだけやったら思い通りになった↓もしかしたら不必要なものもあるのかもしれないが ・pnl_2はcontentPaneにaddするのではなく、pnl_1にaddする pnl_1.add(pnl_2); ・pnl_1はsetSize()でフレームと同じ大きさにサイズ設定 pnl_1.setSize(100, 100); ・pnl_2はsetBounds()で位置サイズ固定。 ぴったりpnl_1にかぶせるのであれば pnl_2.setBounds(0, 0, 100, 100); たぶんLayoutにも関連してくるんだと思う 今のところだけど、 contentPaneは setLayout(new BorderLayout()); pnl_1は pnl_1.setLayout(null); としてある フォントの種類っていろいろあるけど今までほとんど気にしたことなかった デフォルトで表示される日本語フォントがあまりに変なのでメイリオっていうのに変更した すっきり入門読み直してるんだけど windowsアプリ作ってる時になんどかstatic関連のエラーが出た なんとなく適当にやったら切り抜けられたんだけど ちゃんと頭に入れないといけない いつも忘れるのは 「staticメソッドからはstaticではないメンバを呼び出せない」 ということ。 何度かこれでつまずいたんだけど、そのうちの一つがthread関連の処理をしたとき threadはまだちゃんと理解できてなくて、それが原因というのもある threadを使うだけの簡単なプログラムをつくれと言われたら簡単なんだけど 自分がそれまで書いたコードを前提にして、そこにthreadを組み込もうとするといろいろ制約が出てきて難しくなっていくのだ そもそもスレッドは鬼門なのだ すっきりでも実践編の最後に触れているだけで 入門編しか読んでないおれが立ち入ってはいけない領域だったのだ しかしスレッドを利用しないとなるとさらに難しいコードを書かなければならなさそうだったので あえて踏み込まざるを得なかった まず第一の制約がこれだった メインに使うクラスをMainとした場合、このMainクラスはこう宣言されている public class Main extends JFrame 普通スレッドを使う時は extends Thread を使うのだが しかしextendsによる多重継承はゆるされないため、Runnableを使う事になる public class Main extends JFrame implements Runnable と宣言することになる と書いたのだが、実は ごく基本的なコードを書くのであればRunnableはメインのクラスに実装するものではない それはあとになって分かったことなのだが、基本レベルではこう書く もちろんSwingを使ってwindowsアプリをつくる前提で。 public class Main extends JFrame { public static void main(String[] args) { Main mm = new Main(); Aa aa = new Aa(); Thread thrd = new Thread(aa); thrd.start(); } } public class Aa implements Runnable { public void run() { System.out.println("この辺に処理内容を書く"); } } つまり、Mainとは別に処理系のクラスを作って、これにRunnableを実装するのだ そしてmainスレッドでThreadクラスのインスタンスを生成するときに 処理系クラスのインスタンス変数を引数として渡すことになる しかし、おれが何もわからないまま参考にしたコードではメインのクラスはこう宣言されていたのだ 先ほど書いたものをもう一度書くが、これだ public class Main extends JFrame implements Runnable つまり、本来メインのクラスとは別にRunnableをimplementsするクラスをつくるはずが そのクラスをメインのクラスに吸収するような形で合体させてしまっているのだ その結果、メインのクラスにRunnableをimplementsさせてしまっているわけだ これはextends JFrameと同じ構造だ これも基本レベルではメインのクラスとは別のクラスを作ってextends JFrameとすべきところを メインのクラスに合体させてしまった結果なのだ MainクラスがAaクラスを吸収合体した結果上のコードはこう変ることになる public class Main extends JFrame implements Runnable { public static void main(String[] args) { Main mm = new Main();//この一行にAa aa = new Aa();も一緒に入っていることになる Thread thrd = new Thread(mm);//mmにはaaも一緒に入っていることになる thrd.start(); } public void run() { System.out.println("この辺に処理内容を書く"); } } で、結局なんの話だったかというと そう、staticの話なのだ static などどこにも出てきてないぢゃないか! その通り、これから出てくるのだ 時計やら定時処理系をthreadを使って書くと sleepメソッドを使う事になる もちろんrunメソッドの中に書いていくことになる public class Main extends JFrame implements Runnable { public static void main(String[] args) { Main mm = new Main();//この一行にAa aa = new Aa();も一緒に入っていることになる Thread thrd = new Thread(mm);//mmにはaaも一緒に入っていることになる thrd.start(); } public void run() { try { thrd.sleep(1000); //ここ!注目 } catch(InterruptedException e) { e.printStackTrace(); } } } が、これはエラーが出てしまうのだ thrd が犯人なのだ なぜならthrdはmainメソッド内で宣言されている変数であるため runメソッドではスコープの外に置かれている そのため利用できないのだ! そこで、しゃーないので、こう書く public class Main extends JFrame implements Runnable { Thread thrd = new Thread(mm);//←クラスブロックに移動! public static void main(String[] args) { Main mm = new Main();//この一行にAa aa = new Aa();も一緒に入っていることになる thrd.start(); } public void run() { try { thrd.sleep(1000); //←thrdがスコープ内に入る! } catch(InterruptedException e) { e.printStackTrace(); } } } しかしだ!これでもエラーが出てしまい頭を抱えてしまうだ 犯人は mm である Threadインスタンス宣言Thread thrd = new Thread(mm);が クラスブロックに移動してしまったため、引数として渡しているmmが スコープから外れてしまい、ここからではみえなくなってしまったのだ そこでmmを定義する一行もクラスブロックに持ってくることにする public class Main extends JFrame implements Runnable { Main mm = new Main();//←クラスブロックに移動! Thread thrd = new Thread(mm);//←mmがスコープ内に入る! public static void main(String[] args) { thrd.start(); } public void run() { try { thrd.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); } } } しかしだ〜、まだこれでもエラーが出てしまう ようやくここで、static の話になるのだ 最後の犯人は、またもや thrd である mainメソッド内の thrd.start(); である >>72 「staticメソッドからはstaticではないメンバを呼び出せない」 mainメソッドはstaticメソッドである にも関わらず、staticではない thrd を thrd.start(); で呼び出しているのだ この問題を解決するには Thread thrd = new Thread(mm); を static Thread thrd = new Thread(mm); とするだけではダメだ 今度はstaticな「メソッド」ではないものの、static から 非static を呼ぶという同じ現象が static Thread thrd = new Thread(mm); の中で起きてしまっている staticなthrdを定義するのに非staticなmmを呼んで引数にしてしまっているのだ そこでmmを定義する一行にもstaticを付けることにする public class Main extends JFrame implements Runnable { static Main mm = new Main();//←static static Thread thrd = new Thread(mm);//←static public static void main(String[] args) { thrd.start(); } public void run() { try { thrd.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); } } } これでようやく解決したのだ、ちゃんちゃん! こやって書いているとあやふやだったところが見えてくる 実際のコードはずっと長く複雑なので、焦点を絞って小さく書き直すとなかなかいい 解決策はいろいろあるんだろうが、今の知識の範囲内で理解のできる解決策を見つけられるといいのではないかと思っている 間違えて理解しているところはあるだろうが こうやって書いて残しておけば、そのうち気づくときもくるだろう staticがつくと、インスタンスが全く生成されてないのにアクセスできることになる そのためインスタンス生成されて始めて使えるようなメンバを呼び出すことはできないし 許してはだめなのだ だからエラーがでるのだ! ボタン押すと・・・・系 最も基礎レベルのコードがこれ public class Main extends JFrame { Main() { setSize(200, 200); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel pnl = new JPanel(); JButton btn = new JButton("押して・・・・"); pnl.add(btn); Container contentPane = getContentPane(); contentPane.add(pnl, BorderLayout.CNETER); MyListener ml = new MyListener();//@ btn.addActionListener(ml);//A } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } class MyListener implements ActionListener {//B public void actionPerformed(ActionEvent e) { System.out.println("あ〜ん"); } } おれのイメージだと Aを媒介にして @のbtnさんがBの処理系全体を背負ってるような感じ まずこういう骨格を作る class MyListener implements ActionListener {//B public void actionPerformed(ActionEvent e) { System.out.println("あ〜ん"); } } __r'⌒'⌒'⌒ヽ,,_ (,三∧_∧::: 4三) ~(´∀` )爻丗 ~ MyListener ml = new MyListener();//@ とll lと),幵+! (( ◯,,_ , ソ,王ノ btn.addActionListener(ml);//A し" モナーがbtnでリュックが処理系MyListener全体 リュックの肩紐がインスタンス生成の式 みたいな・・・ ボタンを押すと・・・ モナーbtnがぴょんと飛ぶ ↓ するとモナーの足元で震動ActionEventのインスタンスeが自動生成されて、 ↓ 震動 e は肩紐を介してリュックに伝わる ↓ そしてリュックの中で震動 e を actionPerformedメソッドがキャッチして 処理が始まるみたいな・・・・ これが基礎の基礎のイメージ ここがちゃんとできてないとすらすら書けない https://www.javadrive.jp/tutorial/event/index1.html イベント処理の流れを間単に確認しておきます。 まずボタンやテキストなどのコンポーネントが何のイベントを受け取るのかを指定します。 これは例えばボタンについて考えてみると、ボタンが押されたとか、ボタンの上でマウスが 動いたなどの様々なイベントが絶えず発生していますが、必要の無いイベントについては 処理する必要が無いため、自分で処理したいイベントだけ受け取るようにするためです。 ↑ おれのSwingの教科書的サイト ボタン押すと、ボタンからActionEentのインスタンス e が自動生成されるイメージ・・・・ >>82-85 が一番の基礎で・・・ 次がこんなの 少し変るだけ 肩紐の@がAに吸収された感じ public class Main extends JFrame { Main() { setSize(200, 200); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel pnl = new JPanel(); JButton btn = new JButton("押して・・・・"); pnl.add(btn); Container contentPane = getContentPane(); contentPane.add(pnl, BorderLayout.CNETER); btn.addActionListener(new MyListener());//A } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } class MyListener implements ActionListener {//B public void actionPerformed(ActionEvent e) { System.out.println("あ〜ん"); } } >>86 とはちょっと別系統の発展系で、 BをMainクラスに合体させる形も考えられる public class Main extends JFrame implements ActionListener { //BがMainに合体! Main() { setSize(200, 200); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel pnl = new JPanel(); JButton btn = new JButton("押して・・・・"); pnl.add(btn); Container contentPane = getContentPane(); contentPane.add(pnl, BorderLayout.CNETER); btn.addActionListener(this);//Aモナーbtn } public static void main(String[] args) { Main ma = new Main();//@肩紐生成はここにふくまれることになる ma.setVisible(true); } public void actionPerformed(ActionEvent e) { System.out.println("あ〜ん"); } } 今は覚えちゃったから迷わないけど ここはよく迷った btn.addActionListener(this);//Aモナーbtn ここのthis このコードの体系なら btn.addActionListener(ma); でもいいんじゃないかとか btn.addActionListener(new Main()); とか?どうや!とかやったけどダメだった thisにしたらうまくいったんで、そのまま思考停止してthisのままきたわけだ ところでこのthisとは ●「自分自身のクラスのインスタンス」 そして、Main()、つまり、コンストラクタとは ●「インスタンスが生まれた直後に自動実行されるプログラム」 である。 基礎の基礎である>>82 を思い出すと、thisの位置にくるのは本来は ActionListenerを実装したクラスのインスタンス変数 ml である >>87 ではこのクラスはMainに合体しているため、ml生成の式は Main ma = new Main(); に含まれていることになる そしてこの式が生成されるちょうどその時に、コンストラクタMain()が呼び出されることになるのだ いわば、maを作る時にその材料づくりとしてコンストラクタMain()の内容が処理されることになる btn.addActionListener(ma); とすると、maをつくる材料にmaが含まれるというおかしなことになってしまうが これは問題ない。問題なのはその書き方である maの作成途中でmaを引き渡そうとしても、まだmaはできあがってないので引き渡せないのである そこでthisという特殊な書き方をするのだ (とおれは考えているのだ そもそもthisというのはそーゆーときに使うのだ! (とおれはかんがえている わかったか! btn.addActionListener(new Main()); はもう少しわかりやすい問題が起こる 今つくろうとしているインスタンスを引き渡したいのに、new Main()としてしまうと 別のインスタンスをあらためて作って引き渡すということになる。これはダメだ。 ちなみに、この「別のインスタンス」だが、生成するときにコンストラクタMain()を呼び出してしまう するとまた異なるインスタンスをMainクラスから生成しようとする。そしてこのインスタンスはまた・・・・以下同様 このさまは実際にコードを実行してみるとコンソールでみられる ちなみにおれはSwing Javaと格闘してるのだが 最近よくきいている音楽はSwing Jazz だから何?????とか言わないで >>88 > btn.addActionListener(ma); とすると、maをつくる材料にmaが含まれるというおかしなことになってしまうが > これは問題ない。問題なのはその書き方である > maの作成途中でmaを引き渡そうとしても、まだmaはできあがってないので引き渡せないのである > そこでthisという特殊な書き方をするのだ (とおれは考えているのだ > そもそもthisというのはそーゆーときに使うのだ! (とおれはかんがえている > わかったか!。 を修正 btn.addActionListener(ma); とすると、maをつくる材料にmaが含まれるというおかしなことになってしまうが これは問題ない。問題なのはその書き方である thisというのはそもそもまだインスタンス化がされる前にコードに書かれるものである 基礎レベルのクラスの使い方を思い出してみるとわかるのだが 本来はMainクラスとは別のクラスファイルに書かれたクラス、 例えばHeroクラスの中でthisは使われる そしていつかHeroクラスがインスタンス化されたときに、インスタンスが自らを利用するためにthisとして控えているのだ thisというものはそういうものなのだ! 何が大事なのかというと、もう一度繰り返すが、thisを書いた時点では普通インスタンスは生成されていないのだ よってインスタンス変数名など分かるはずがないのである >>87 のコードはその辺が非常に特殊であって、クラスの中で自らのインスタンスを生成しちゃってたりする だからわかりにくい 本来はMain ma = new Main();みたいのは別のクラスに書かれるようなものなのだ それに備えてMain側では将来作られるであろう自らのクラスのインスタンスを表す名称として thisを使うわけだ 確かにbtn.addActionListener(ma);とするのは理屈としては間違えていないのだが 本来の使われ方からするとおかしいのでじゃばがくるくるぱ〜になってしまうのである あーそういえば思い出した この前こういうの書いてみたんだ >>87 に少し付け足し public class Main extends JFrame implements ActionListener { Main() { setSize(200, 200); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel pnl = new JPanel(); JButton btn = new JButton("押して・・・・"); pnl.add(btn); Container contentPane = getContentPane(); contentPane.add(pnl, BorderLayout.CNETER); btn.addActionListener(this); } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); Main ma2 = new Main();//←ここ ma2.setVisible(true);//←ここ } public void actionPerformed(ActionEvent e) { System.out.println("あ〜ん"); } } このときにさっきの話でthisの代りにmaを使ってしまうとma2には対応できなくなってしまうんだ だからやっぱりthisでないとダメなのだ! ちなみにこのコードだとウィンドウが2枚開くことになって面白い そういうプログラム作る時に使えそうだ そして最後に、 >>86 を発展させたのが下のコード @だけではなくBまでもAに合体してしまう public class Main extends JFrame { Main() { setSize(200, 200); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel pnl = new JPanel(); JButton btn = new JButton("押して・・・・"); pnl.add(btn); Container contentPane = getContentPane(); contentPane.add(pnl, BorderLayout.CNETER); //@+A+B btn.addActionListener( new ActionListener() { public void actionPerformed(ActionEvnet e) { System.out.println("あ〜ん"); } } ); } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } //@+A+B btn.addActionListener( new ActionListener() { public void actionPerformed(ActionEvnet e) { System.out.println("あ〜ん"); } } ); この部分はモナーbtnがリュックを背負ってる部分がセットで表現されている 発展形態とはいえ、もっともわかりやすい しかし、ここで、あれ?っと疑問が出てくる @、A、Bが結合しているあたりのコードがおかしいのではないか 本来こう書かなければいけないのではないか? //@+A+B btn.addActionListener( new MyListener() implements ActionListener { //←このへん public void actionPerformed(ActionEvnet e) { System.out.println("あ〜ん"); } } ); ActionListenerのインスタンスではなくActionListenerを実装したクラスのインスタンスを 生成しなければならないのだから。 しかし、このように書くとエラーが生じる 👀 Rock54: Caution(BBR-MD5:1341adc37120578f18dba9451e6c8c3b) この辺を理解するにはある原則的なルールを覚える必要が出てくる このようなbtnにクラスから全部背負わせてしまうようなコードには名称がついている 正確には、背負われているクラスの名称なのだが、「匿名クラス」とか「無名クラス」と呼ばれる 匿名クラスには大事なルールがある。 それは、 「new クラスA(インターフェースA)」 とした場合 クラスAをnewすることにはならないのだ(インターフェースはそもそもnew出来ないのが基本) そうではなく、 ●「クラスAまたはインターフェースAを継承または実装した」クラス をnewすることになるのだ なぜだか理由はよく分からないが >>93 の下の方のコードにエラーが出てしまうように、implementsを記述できないからなのだろうか なにはともあれ、このルールを前提に考えれば btn.addActionListener( new ActionListener() { の2行目は、「インターフェースActionListenerを実装したクラスをnewする」、という意味になる つまり最も基礎的なコードである>>82 の@new MyListenerと全く同じことを意味するのだ 参考までにいえば、 もしスーパークラス(ここでいうならActionListener)の中で private修飾子のついたフィールドが宣言されていると、 newしたあとのブロック内ではこのフィールドにアクセスできないことになってしまうのだ ちゃんと書こう クラスAAでaというフィールドがこう宣言されていたとする private int a; このとき匿名クラスを利用し、こう書いたとする new AA() { public void bb() { a = 10; } } これはエラーが生じてしまう なぜならnewしたのはAAのように見えて実はAAを継承した別の(名無しの)クラスだからだ 名無しの別のクラスからはAA内に宣言されたprivate変数にアクセスすることは許されないのだ まぁだからこそ「匿名」クラスという名前がついている new AA が クラスAAをnewするというのであれば AAって名前あるじゃん・・・となる しかし new AA が クラスAAを継承した名無しクラス または インターフェースAAを実装した名無しクラス をnewするという意味だとしたら まさに匿名っすよね! さて、今日からは フレーム上で右クリックメニューを表示させ、 「閉じる」の項目を選択・クリックしてプログラムを終了させる処理 について再考する この処理はすでに作ったソフトで利用してはいるが 理解を深めるために他の処理とは独立した形でとりだして分析すべきだと思っている 先を急いだため、コピペでしのいだ部分もあり、 部分的には理解できていない可能性があるのだ ところで、なぜ右クリからの終了処理が必要になったのかというと windowsアプリは通常タイトルが表示される枠部分がある そしてこのタイトルの右の端には最小化・最大化・閉じるボタンがあるのだ 閉じるボタンがあればわざわざ右クリから閉じる機能を作る必要もない しかし、小さなウィンドウのプログラムを作るときは、このタイトルバーが邪魔になってしまう 右端の3つのボタンはウィンドウをより小さくする時に障害となってしまうのだ おれが作ったものはこういうもの https://dotup.org/uploda/dotup.org1659204.jpg 昭和チックな絵柄でデザインセンスが皆無なのが分かるだろうか いやそういう話ではなく、ウィンドウを小さくするためにタイトルバーを取り外してしまったわけだ すると、 setDefaultCloseOperation(true); が機能しなくなってしまうのだ それどころか、ウィンドウの位置を動かすことすら出来なくなってしまう つまり、タイトルバーを消してしまった代償として、以下の2つの機能を実装する必要があるのだ 1.閉じる機能を右クリメニューに加える 2.ウィンドウをD&Dにより動かせるようにする 今回は1.について分析をしていこうとおもうとる 分析大体終了 右クリして閉じる機能は大きく2つに分けて考えるといい イベント処理が2つあるのでこの2つを分けて考えるのだ イベント処理というのはつまり >>82-85 と同じ モナーが肩紐を肩にかけてリュックを背負ってるイメージ これが2段構えになっている モナーが背負ったリュックの上に別のモナーが別のリュックを背負ってる感じ 一つ目の処理は 右クリックをして何かが起きるまで 二つ目の処理は 項目がポップアップし、「閉じる」を選択することでフレームが閉じるまで >>83 だけどちょい間違えてるな Aを媒介にして @のbtnさんがBの処理系全体を背負ってるような感じ ↓ @を媒介にして AのbtnさんがBの処理系全体を背負ってるような感じ 最も基礎的なコードを書こうとして逆に迷う これまでdispose()をプログラム終了のために使ってきたが、Mainとは別のクラスから使おうとするとなかなかうまくいかない System.exit(0); を使う事で問題を回避できたのだが、原因はなんだったのかなといろいろ考えてる このサイトでの記載がキーになるのではないかと思っている http://www2n.biglobe.ne.jp/ ~fify/shiroutoshikou/java/api/java/awt/Frame.htm 終了処理にはSystem.exit()ではなくdispose()を使っています。 System.exit()はJava仮想マシンの終了を意味しますが、 dispose()はメソッド呼び出し元のウィンドウおよび、 そこから呼び出されているすべてのコンポーネントを解放し、 メモリ資源をOSへと返却します。ここで行いたいのは Java仮想マシンの終了ではなくFrameを閉じることなので、 dispose()を使うのが作法的にも正解です。 クラスの内部でさらにクラスを定義していることに注意してください。 ここで、先ほどのクラスWinLのようにメソッドwindowClosing()を オーバーライドしたクラスを用意してフレームを表示するクラスから呼び出そうとしても、 コンパイルエラーとなります。なぜなら、メソッドdispose()は 抽象クラスWindowAdapterおよびその親クラスには実装されていないからです。 メソッドdispose()が実装されているのは、Frameの親クラスであるjava.awt.Windowとなります。 やはりよくわからない が、まぁいいだろう 今回焦点を当てたいのは終了処理ではないのだ さて、気を取り直して、 右クリから終了するコードを書く これがおれ史上もっとも基本的なコードとして頭にたたき込んでおくものとする public class Main extends JFrame { static JPopupMenu pm = new JPopupMenu();//C Main() { setSize(100, 100); setLocationRelativeTo(null); MyMsListener ml = new MyMsListener();//A addMouseListener(ml); //@ MyAcListener al = new MyAcListener(); //G JMenuItem mi = new JMenuItem("閉じる");//E mi.addActionListener(al); //F pm.add(mi); //D } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } class MyMsListener implements MouseListener { //B public void mouseClicked(MouseEvent e) { if(SwingUtilities.isRightMouseButton(e)) { Main.pm.show(e.getComponent(), e.getX(), e.getY()); } } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } class MyAcListener implements ActionListener { //H public void actionPerformed(ActionEvent e) { System.exit(0); } } いや、タブを全角スペースに直すの忘れてたんで再度こぴぺ 右クリから終了するコードを書く これがおれ史上もっとも基本的なコードとして頭にたたき込んでおくものとする public class Main extends JFrame { static JPopupMenu pm = new JPopupMenu();//C Main() { setSize(100, 100); setLocationRelativeTo(null); MyMsListener ml = new MyMsListener();//A addMouseListener(ml); //@ MyAcListener al = new MyAcListener(); //G JMenuItem mi = new JMenuItem("閉じる");//E mi.addActionListener(al); //F pm.add(mi); //D } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } class MyMsListener implements MouseListener { //B public void mouseClicked(MouseEvent e) { if(SwingUtilities.isRightMouseButton(e)) { Main.pm.show(e.getComponent(), e.getX(), e.getY()); } } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } class MyAcListener implements ActionListener { //H public void actionPerformed(ActionEvent e) { System.exit(0); } } >>106 おれの感覚では T @〜Bが右クリから何かを起こすまでの処理 U C〜Hが右クリメニューがポップアップしてから実際のプログラム終了までの処理 というように2つの段階があると捉えている ● Tは @(JFrame).addMouseListenerのモナーが A肩紐ml宣言を通じて BリュックであるMouseListenerを実装した実際の処理を背負っている イメージで捉える フレーム全体にわたってマウスの動きを感知する機能が加えられる フレーム上でマウスがクリックされると、その震動 e が肩紐Aをつうじて リュックにつたわりBの実際の処理へとつながる このとき e がマウスのどの種類のクリックだったのかを分析して if 文により、それぞれの処理を個別に指定できる ここでは e が右クリにより生じたとするなら、pmを特定位置でshowしろと指示する ● Uは CDEpmが何なのを説明し、miまでつながる道筋を示す Fmi.addActionListenerのモナーが G肩紐al宣言を通じて HリュックであるActionListenerを実装した実際の処理を背負っている イメージで捉える CDEは一応Uに含まれるようなイメージで捉える Tでの実際の処理としてpmがshowするのだが pmを宣言するのがC、pmとはJPopupMenu つまり右クリしたときにぽよんとあらわれる「あれ」の本体とイメージする 「あれ」(JPopupMenu)は当初は姿形がなく、 ここに項目JMenuItemが加えられることで目視できるようになる JMenuItemは今回のプログラムでは1個だけで、「閉じる」 の項目を示すために使う 「他地域の天気」などの別の項目を加えたいのであれば複数のJMenuItemを宣言し これを、目では見えないがぽよんの本体であるpm(JPopupMenu)にaddすることになる mi(JMenuItem)は宣言時に表示文字列をコンストラクタに渡すことになる そしてこのmiがTのモナーが背負うリュックのさらに上に立つモナーとなるのだ このmiは>>82-85 のbtnと全く同じ位置づけと考えればよい Fmi.addActionListener(al);というモナーが G肩紐al宣言を通じて Hリュックである実際の処理を背負う構図だ 「閉じる」の項目をクリックしたとたんに震動 e がFモナーの足元で生じ これがGを通してHに伝わり、最終的に e を受けとったactionPerformedメソッドが System.exit(0)を実行し、プログラムが終了するのだ このコードの形式を前提とするなら 右クリメニューを増やすごとに D〜Hを変数名等を変えて書き足すことになる しかし、これでは面倒ではないか?コードが読みにくくなるのではないか? という批判に応えるため、クラスを活用したコードを書くのが一般的のようだ ただし、それはもう少し後に回すことにして >>106 を匿名クラスを使って書き直したものを貼ることにする イベント系の処理は基本的には匿名クラスを使って書くようにしていこうと思っている public class Main extends JFrame { JPopupMenu pm = new JPopupMenu(); //C Main() { setSize(100, 100); setLocationRelativeTo(null); addMouseListener( //@ new MouseListener() { //A+B public void mouseClicked(MouseEvent e) { if(SwingUtilities.isRightMouseButton(e)) { pm.show(e.getComponent(), e.getX(), e.getY()); } } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } ); JMenuItem mi = new JMenuItem("閉じる"); //E mi.addActionListener( //F new ActionListener() { //G+H public void actionPerformed(ActionEvent e) { System.exit(0); } } ); pm.add(mi); //D } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } >>107 修正 BリュックであるMouseListenerを実装した実際の処理を背負っている ↓ BリュックであるMouseListenerを実装したクラスMyMsListenerが実際の処理を背負っている HリュックであるActionListenerを実装した実際の処理を背負っている ↓ HリュックであるActionListenerを実装したクラスMyAcListenerが実際の処理を背負っている さて、先ほど書いた 「クラスを活用したコード」 とは、匿名クラスのことではない 自作のクラスを作成し、自作クラスのインスタンスを複数生成することで 複数の右クリメニューを作って行くという方法である このタイプの書き方をすることで、右クリメニューの項目が 各インスタンスのnewごとに羅列されるため、見た目わかりやすい しかし、おれみたいなレベルのプログラマーにとっては匿名クラスで書いた>>109 を前提に 右クリメニューを増やしたほうがわかりやすかったりもする メモリの使い方なんやらでやはり自作クラスを使うべきなんだろうが。 匿名クラスでメニューを増やすなら D〜Eのブロックをメニューごとに増やすことになる もちろん変数名などは変えていかねばならぬ 例えばこんな感じだ 最終的な処理がより複雑になりコードが長くなった場合 わかりにくいコードになってしまう点は否定できないのだが public class Main extends JFrame { JPopupMenu pm = new JPopupMenu(); //C Main() { setSize(100, 100); setLocationRelativeTo(null); addMouseListener( //@ new MouseListener() { //A+B public void mouseClicked(MouseEvent e) { if(SwingUtilities.isRightMouseButton(e)) { pm.show(e.getComponent(), e.getX(), e.getY()); } } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } ); JMenuItem mi = new JMenuItem("閉じる"); //E mi.addActionListener( //F new ActionListener() { //G+H public void actionPerformed(ActionEvent e) { System.exit(0); }}); pm.add(mi); //D JMenuItem mi2 = new JMenuItem("サイズを大きくする"); //E mi2.addActionListener( //F new ActionListener() { //G+H public void actionPerformed(ActionEvent e) { setSize(300, 300); }}); pm.add(mi2); //D } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } ちなみに、「サイズを戻す」 というメニューを追加すると 5チャンで書込みがロックされてしまうため項目は2つに留めておいた 繰り返し似た文を書くと駄目なようだ ロックされた場合は https://agree.5ch.net/mango/ この板で試行錯誤を繰り返しながら原因把握ができる コードは繰り返しの文が多くなるので引っかかりやすいかもしれない Javaでつくったwindowアプリの右クリメニューがひどいデザインなのは仕方ないのか? Swingだとこうなってしまうのか、、、、? 右クリから閉じる機能の説明はまだ終わってないのだが >>100 に書いた 「ウィンドウをD&Dで動かす機能」 について先回りしてざっとみている 自分が書いたコードは試行錯誤しながらコピペしまくったせいか 不必要な部分がいくつも見つかった D&D移動機能については別の機能との関連もあって、頭の中でまったく整理できていない とくに注目しなければならない「別の機能」とは、 前回閉じた位置で開く機能である この機能は大まかに説明すれば ウィンドウを閉じるときにiniファイルに現在座標を記録し 次に開くときにiniファイルから座標を読み込んで、同じ位置に開くというものだ と、書いたのだが正確にいうとiniファイルに書き込むタイミングはウィンドウを閉じる時ではない プログラムは予期せぬトラブルによって終了してしまうおそれがある そこで、ウィンドウ位置が動いた場合、そのたびにiniファイルに場所を記録するのだ こうすることでトラブル対策になる そのためD&D機能との関連が大事になるのだ ちゃんとまとめれば、そう難しいものではないと思うのであせらずやっていこう すべての機能が整理できたあと、もう一度最初から全部書き直すといいのだが その気があればやることにしよう >>108 >>111 の修正 「クラスを活用したコード」 は間違いだった 実際に書いてみたところ、クラスではなく、「メソッドを活用したコード」だった 右クリメニューの項目を増やすごとに 文字列とActionListenerのインスタンスをメソッドに引数として渡す 実際に書いていくとこういうものになる >>109 をさらに発展させたといえるのだろうか public class Main extends JFrame { JPopupMenu pm = new JPopupMenu(); //C Main() { setSize(100, 100); setLocationRelativeTo(null); addMouseListener( //@ new MouseListener() { //A+B public void mouseClicked(MouseEvent e) { if(SwingUtilities.isRightMouseButton(e)) { pm.show(e.getComponent(), e.getX(), e.getY()); } } public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } ); addMi("閉じる", new ActionListener() {//G+H public void actionPerformed(ActionEvent e) { System.exit(0); }}); addMi("サイズを大きくする", new ActionListener() {//G+H public void actionPerformed(ActionEvent e) { setSize(300, 300); }}); } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } public void addMi(String name, ActionListener al) { JMenuItem mi = new JMenuItem(name);//E mi.addActionListener(al);//F pm.add(mi);//D } } >>117 は、@〜Cまではこれまでと同じなのだが、それ以降のD〜Hが違う まだ目に見えないJPopupMenuに各項目を加え実際の処理につなげていく部分なのだが そのうち、GActionListener実装クラスのnewとH実際の処理部分だけを項目ごとに書き、 言い換えると、G肩紐とHリュック部分だけを項目ごとに書き、 その他の部分は共通部分としてメソッドにまとめることになる こうすることで>>112 のように項目を増やすごとに変数をあらたに作っていく必要がなくなる 正直言ってこうすることでどれだけのメリットがあるのかは、今のところよく分からない 右クリメニュー機能をつくるために検索した結果、 お手本としたのがこの手のタイプのコードだった これを理解することを目標に書いてきたので、とりあえず目的達成ということでいいだろう これから先、右クリメニューのコードを書くときは これをベースに書いていけるといいなと 次に行こう ウィンドウのD&D移動である これまで書いてきた処理のほとんどはイベント系の処理だ D&D移動もイベント系の処理の一つである パターンがつかめてくると、理解するまでのスピードが速くなってくる D&D移動の処理も3つのイベントに区分できる T マウスを押す U そのままマウスを動かすことでウィンドウがうごく V マウスを放す それぞれの処理を引き受けるインターフェースは T MouseListener U MouseMotionListener V MouseListener ということになる TとUは同じMouseListenerを使うため、コードはまとめることができるだろう ウィンドウD&D移動 public class Main extends JFrame { static Point pt; Main() { setSize(100, 100); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addMouseListener( new MouseListener() { public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {//@ pt = e.getPoint(); } public void mouseReleased(MouseEvent e) {//B pt = null; } public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } ); addMouseMotionListener( new MouseMotionListener() { public void mouseDragged(MouseEvent e) {//A Point currentPt = e.getLocationOnScreen(); setLocation(currentPt.x - pt.x, currentPt.y - pt.y);// } public void mouseMoved(MouseEvent e) {} } ); } public static void main(String[] args) { Main ma = new Main(); ma.setVisible(true); } } 一気に匿名クラスを使った最終版を書いたわけだが 基本的にはこれまでとパターンは同じだ 細かい処理が違ってくるだけだ まずここで使っているPointというクラスが大事だ 簡単にいえばデスクトップ上の(x, y)座標を格納してくれるインスタンスを生成できるクラスなのだ 正確にいうと、デスクトップ上の(x, y)座標は絶対座標というが、 Pointのインスタンスは相対座標も格納できる 今回使われる相対座標は、マウスをウィンドウ内でクリックしたとき、マウスの座標を ウィンドウの左上端から測った相対座標である Pointインスタンスに格納された座標をStringで表示するには Point pt = new Point(); pt = e.getPoint(); を前提とするなら System.out.prinln(pt.x); System.out.println(pt.y); System.out.println(pt); のどれでもOKだ。一番下のものはtoStringの機能が自動で使われており便利だ 相対座標を取得するメソッドはgetPoint() 絶対座標を取得するメソッドはgetLocationOnScreen() どちらもActionEvent e つまり「震動」の発生地点の座標を測ることになるので e.getPoint() e.getLocationOnScreen のように e を基準としてコードを書くことになる T〜Vの処理を細かく見ていく T→@ マウスを押すことでウィンドウ左上端から測ったマウスの相対位置をptに格納 相対座標はAで使うためにここで取得している U→A ドラッグするごとに変化するマウスの位置をcurrentPtに格納していくと同時に currentPtに応じてウィンドウの位置を設定していく setLocationにはウィンドウの左上端となる座標を渡さないといけないので currentPtから相対座標分だけずらした座標を計算してわたすことになる マウスの座標をそのまま渡してはいけない点に注意しなければならない V→B ptにnullを入れる ちなみにB処理だが、pt = null; をコメント行にしても正常に動いた pt = null:が必須なのかはよくわからない 少なくとも、ptを他の処理に使い回したい場合にはこうして置いた方がよいのかなと思った yahooから明日のお天気を取得するソフトがらみで おさらい分析しなければならない最後の部品に取りかかろう 「前回閉じた場所に開き直す」 機能 テキストファイルに座標を書き込む・読み込む ウィンドウ位置が変ったときにiniファイルに座標をかき込むなど まだ苦手としている処理が含まれている そのまえに座標の取得について e からx座標、y座標を取り出す方法なのだが さきほど使ったのは一旦Pointインスタンスに格納する方法 相対座標に絞って説明するが Point pt = e.getPoint(): int x = pt.x; int y = pt.y; Pointインスタンスを使わないでも e から直接x座標、y座標を取り出すことは可能だ int x = e.getX(); int y = e.getY(); これは「右クリから閉じる機能」>>117 で使ったものだ 2つの方法を混同して使わないようにしなければならない ところで、この方法どちらもだが、相対座標を取り出すのに使われるのだが 何を原点(0, 0)とするのかを明確にする必要がある これについては 「発生元のコンポーネントを基準とする、イベントの相対 x、y 座標値」 と考える ここでいう発生元とは、e がどこから発生したのか、である btn.addActionListener ならbtnということになるのだろう btnの左上端を基準に測ってくれるのだろうか(未確認) this.addMouseListener this.addMouseMotionListener ならthisということになる このthisだが、>>120 では使ってはいないものの コンストラクタの中にあるaddMouseListenerやaddMouseMotionListener の前にthisをつけるのが本来の書き方じゃないかと思っている 実際、エラーはでない thisは「自分自身のクラスのインスタンス」を意味するため、ここでは ma がそれにあたる MainがJFrameを継承しているから、maはJFrameのインスタンスでもある つまり this.addMouseListenerとした場合の e の発生元はthis=ma=JFrame=フレームそのものと考えられる こうすることで この場合の e.getX()は フレーム(ウィンドウ)の左上端を原点とした場合のマウス位置の相対座標をかえすことになる ついでなのだが、右クリ閉じる機能>>117 の pm.show(e.getComponent(), e.getX(), e.getY()); showメソッドは、JPopupMenuを表示するためのメソッドである 「イベントを発生させたComponentオブジェクト」内の (x, y)座標で指定された位置にJPopupMenuを表示する (x, y)はレファランスで読む限り相対座標でなければならないようだ e.getComponent() は「イベントを発生させたComponentオブジェクト」を取得 e.getX() は「イベントを発生させたComponentオブジェクト」内での相対座標xを取得 e.getY() は「イベントを発生させたComponentオブジェクト」内での相対座標yを取得 少し脱線するのだが getComponent()について疑問が残った ActionEvnetのインスタンスである e についてのメソッドだろうと思って ActionEventを調べてみたところこのようなメソッドはなかった どうやら、ComponentEventという別のクラスのメソッドであるようだ ComponentEventはActionEventによって継承なり実装されてるのかとおもいきや、そうでもない なぜ e.getComponent() という書き方ができるのか、今の知識では理解できない これは後回しにしておこう いずれ理解できるのかもしれない >>124 はちょっと勘違いしてた >>117 の pm.show(e.getComponent(), e.getX(), e.getY()); で使っている e はActionEventではなくてMouseEventだった MouseEventをAPI referenceでみてみると java.awt.event クラスMouseEvent java.lang.Object java.util.EventObject java.awt.AWTEvent java.awt.event.ComponentEvent ←ここ java.awt.event.InputEvent java.awt.event.MouseEvent ←ここ となっており、MouseEventの親のそのまた親にComponentEventがある つまり、この繋がりがあるからMouseEventのインスタンス e はComponentEventで 定義されている getComponent()メソッドを利用できるというわけだ 実際にreferenceにもこう書いてある クラス java.awt.event.ComponentEventから継承されるメソッド getComponent な〜んだな〜んだ そう難しい話ではなかった またまたついでだが >>117 の自作メソッドを使ったパターンについて自分なりのとらえ方というか考え方を書く 自作メソッドの部分 public void addMi(String name, ActionListener al) { JMenuItem mi = new JMenuItem(name);//E mi.addActionListener(al);//F pm.add(mi);//D } モナーがリュックを背負っている形をつくり さらにそのモナー全体がJPopupMenuに加わるという メインの処理は、ここだけで終わっていると考える そのうえで、addMiを呼び出すこの部分↓はどう捉えるのかというと addMi("閉じる", new ActionListener() {//G+H public void actionPerformed(ActionEvent e) { System.exit(0); }}); メインの処理の中で、ある変数を利用することで詳細を省いた部分がある そこを埋めるため、あとからジグソーパズルのピースをはめ込むような処理を担っているとする 欠けていたピースは2つあり、 一つは 本来JMenuItemインスタンス生成時にコンストラクタに 渡すはずの項目名称をnameという変数をつかって空欄状態にしてあった部分 もう一つは 本来addActionListenerの引数として実際の処理を含めた形で匿名クラスのインスタンスを 渡すはずが al という変数を使って空欄状態にしてあった部分 この2カ所に実際のピースをはめたのがaddMiの呼び出し部分と捉えることにする 基礎レベルのコードからいくつかの高度化を経てたどり着いた雛形となるコードは そらで書けるようになんどか繰り返して書くことにする ただし、インターフェース実装によりオーバーライドが必要なメソッド群については eclipseのTODOに頼ることにする import文も同様にeclipseに頼ることにする それ以外は何も見ずに書けるようにする Swingは今後どう扱われているかはわからないものの、 今となっては時代遅れな代物に成りはてている Java自体もそうなりつつあるのかもしれない しかし、今後どのような言語を学んでいくとしても Javaに代表されるような主要言語の体系は引き継がれていくと予想される JavaのSwingを使った時はこういう風に書いたなという明確なイメージが 頭にあるのとないのとでは全く違ってくるのではないか そこでいくつかの基本パターンについてはしっかりと暗記してしまおうと思っている >>122 にとりかかっているんだけど今知ったことがある https://www.sejuku.net/blog/20794 プログラミング言語のなかでもC++などは、拡張子を「.ini」とした設定ファイルを 読み書きする関数が用意され、それを利用しています。 Javaの場合は、拡張子が「.properties」のプロパティファイルに定数などの 規定値や、ファイルのパスなどをまとめて記載し、読み書きするのが一般的です。 な、なんだって〜 iniファイルってC系の設定ファイルだったのか Javaではpropertiesを使うとは! もしかして〜と思って実践編をぺらぺらめくってみたら10章に書いてあった あれかね、やっぱりこの一冊ちゃんと読んでから分析したほうがいいかな properties便利だわぁ iniよりずっと難易度下がった 前閉じた場所で開くコードは長くなるんで、今のところはここには書かない プログラムを大きく分けるとこうなる T プロパティファイルを読みにいってウィンドウを開く部分 U ウィンドウが動くたびに変数に数値を格納して閉じるときにプロパティファイルに記録する部分 Tについてプロパティファイルを読むためにクラスを自作して 座標と幅・高さに関するフィールドを置く このクラスはmainメソッドはなく、フィールドに値を突っ込むためのコンストラクタだけ。 Uでプロパティファイルに記録する部分は、Mainクラス内にメソッドを設ける 読み込む時だけクラスをつくって書き込む時はメソッドにしたのは何となく書きやすかったと理由にすぎない もう一つだけ暗記のベースにするためのコード作っておくか HTMLを取得してタグで分割して配列に格納する これだけやったらテキストに戻ろう ウェブスクレイピング(英: Web scraping)とは、 ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと。 ウェブ・クローラーあるいはウェブ・スパイダーとも呼ばれる。 ひょんなことからWSH windows shell hostのVBScriptをちょっとだけやってみた HTML取得したりもできるのかな?と思って調べてみたら HTMLを専門に扱う目的でプロパティやメソッドが用意されている これはもしやJavaでもあるのではないかと思って調べてみたら、やっぱりあった Java ウェブスクレイピング でぐぐるといろいろ出てくる 「HTMLパース」 HTMLパースとは、HTML文法規則にのっとった文字列を、その文法に基づいて字句解析し、 意味や構造を解釈することをいい、HTMLパースを行うプログラムのことをHTMLパーサといいます パースはparse、構文解析 parseIntのparseか JavaのHTML paserとしては 「Jsoup」 (じぇぃすーぷ) がいまのところ有力だそうで。 導入方法がいままでみたことがない方法だ 外部ライブラリというのかな https://qiita.com/Terry3/items/0c1829130111967773bf eclipseへの導入はここがわかりやすいか? あとでやってみようか >>133 は違うな これはScalaとかKotlinという別の言語でJsoupを利用しているようだ Java以外からも利用できるライブラリなんだな FileOutputStream ファイルに書く FileInputStream ファイルを読む 逆にしてしまいがち スッキリ実践編260ページ FileReaderやFileWriterで、コンストラクタの引数に文字コードを指定することができると 読み取れるような文章があるんだけど、これできないよね https://uxmilk.jp/47743 FileWriter クラスは文字コードを指定することができないので、 文字コードを指定するときは、 OutputStreamWriter と FileOutputStream を使用します。 OutputStreamWriter のオブジェクトを生成するときに、第2引数に文字コードを指定します。 File f = new File("sample.txt"); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(f), "UTF-8"); BufferedWriter bw = new BufferedWriter(osw); bw.write("1行目"); bw.newLine(); bw.close(); こういうのを使えば簡単に人が集まるんでしょうね じゃなくて こういうのを使えばプロパティファイルの日本語文字化けの問題にも対処できるんかなとか思ったりしたんだけど File f = new File("save.properties"); if (f.exists) {} みたいな感じでFileクラス使ってきたけど Path と Files を使っていくことにした Path p = Paths.get("save.properties"); if (Files.exists(p)) {} ポイント: ・Pathはインターフェースなのでインスタンスをnewできない その代りにPaths.get()を使う事でPathインスタンスを取得する ・Filesはインスタンスを生成しないでクラスを直接使ってメソッドにアクセスする ぶっちゃけFileを使った方がわかりやすいんだが public static final String st = "あああ"; 定数であることはfinal修飾子だけで表現できますが、 static修飾子を付けるのがお作法です。static修飾子を付与することで、 インスタンス生成のたびに同じ値をインスタンスにコピーするのを防ぐことができます。 インスタンス生成のたびに同じ値をインスタンスにコピーするのを防ぐことができる インスタンス生成のたびに同じ値をインスタンスにコピーするのを防ぐことができる これ大事 パブリックスタティックファイナルストリング!すたっ!ああああああああぁぁぁぁぁっぁ!!!! (変身 プロパティファイルの読み書きに関してはみんないろいろ工夫してるんだな いろんなコードみてきたんだけど、おれの用途だと 技が高度すぎてちょっとここまでしないでもいいかなと思えるものが多い 部分的に参考にしたらよさそうなのはあった 読み込みのクラス作って コンストラクタでPropertiesをnewしてloadするところまでやる このクラス内でゲッターみたいなメソッドを作って引数にキー名を指定して 戻り値で値を返すみたいな。 書込みについてはまだ調べてないが 書込みのクラス作ってから コンストラクタでPropertiesをnewしておいて セッターみたいなメソッド作って、引数にキー名と値を指定とかかな 値に関しては最終的にはStringにしないといけないんだけど 当初はintだったりStringだったりするわけだから 型によって複数のメソッド作ったりするんかな https://nompor.com/2017/11/26/post-1430/ 2018/08/03・・・PropertiesにはReaderやWriterを引数にすることもできます。こちらを利用して文字コードを指定すれば、日本語の表示も可能です。 どこかに同じようなことが書いてあったけど ちょっとやってみよう じゃなぜみんなFileReaderやFileWriterを使うんだろうかと思うと やはりデメリットがあるんだろうな >>141 いやいや、書込みをこの方法で作っちゃうと インスタンス生成したのはいいがメソッドを使わなければcloseされないという問題が起きるぢゃんか メソッド単位でFileWriterのnewとclose処理すれば良いんだけど newというものはそこそこ重い処理だなんてことをどこかで見て以来 こういう連続した処理でそのたびにnewするのはだめなのかなとか思っちゃう どうなのかね と、ここまで考えて気づいたのは、closeしないまま終わるのは 書込みだけじゃなくて読み込みもだ 参考にしたコードをもう一度見直してみたんだけど なんと、このコードはFileWriterとかFileReader使ってない 結局closeの問題を避けるためにこういう方法があるのかな ん〜やっぱりわかんないや お手本のコードもう一度見直したらthrows IOExceptionしてる 読み込みや書込みのクラス内で例外処理も完結してくれないといやだいやだ お天気表示ソフトが3時間おきに天気取得にでかけるんだけど これを、何時に起動したとしても、1回目の取得のあとは 0:05 3:05 6:05 みたいに3の倍数の時刻の5分後にとりにいくようにコードを書き直そう CalendarのgetInstanceメソッドは、Calendarオブジェクトを返しますが、 このカレンダ・フィールドは現在の日付と時間に初期化されています。 Calendar rightNow = Calendar.getInstance(); 現在日時の取得するのにDateクラスのインスタンス生成に頼る必要はない 時刻の引き算は一度Dateをlongに変換する Date d = new Date(); long l = d.getTime(); で変換終わり getTime()は CalendarからDateへの変換でも使うし Dateからlongへの変換でも使うので混同しないように! ちなみに CalendarインスタンスのgetTime()、setTime()はともにDateがらみだが get()、set()はCalendar内部のフィールドがらみメソッド threadについて MainクラスはRunnableを実装している Threadインスタンスとしてthrdを宣言して mainメソッドで thrd.start(); public void run() {} の中で thrd.sleep(1000); とするとエラーなしで実行はできるものの注意マークがついていて気になっていた 要はstaticの問題 API referenceをみてみると static void sleep(long millis) システム・タイマーとスケジューラが正確であることを前提として、 現在実行中のスレッドを、指定されたミリ秒数の間、スリープ(一時的に実行を停止)させます。 となっていてsleep()メソッドはstaticがついている しかし、staticの基本として、 static宣言されているフィールドやメソッドには インスタンス変数名で呼び出しても→thrd.sleep(); クラス名で呼び出しても→Thread.sleep(); どちらでもOKなはず (スッキリ入門367,368ページ) なぜクラス名が推奨されるのかはよく分からないが すくなくともクラス名を使うと注意マークが消えることはわかった おまけだが static関連で制限される事項として staticがついているメソッド内でフィールドやメソッドを使う時は そのフィールドやメソッドはstaticでなければならない つまり>>150 の例で言えば、sleep()にstaticがついているから sleep()の中でフィールドやメソッドを使う時は・・・・ ということになる が、sleep()はおれが作ったものじゃないから制限されるといわれても困るわけで 今回の問題とは無関係 おれのプログラムだとメインのクラスが public class Main extends JFrame implements Runnable {} と宣言されていて、MainにRunnableを実装している なので、Mainクラスのなかにpublic void run()をオーバーロードする目的で設置することになる もし1つではなく2つスレッドを作りたい時は MainにRunnableを実装するのではなく スレッド用に2つ新しいクラスを作って、これらがRunnableを実装する(またはThreadを継承) それぞれのクラスの中にpublic void run()をおいて処理内容を書いていくとわかりやすいかな 今どきjavaでGUIって笑 そもそもWindowsアプリなら.NET使えよ ちなみに俺はプログラミング始めて1年ほどだが、PythonのBeautifulSoupでスクレイピングした株価データをMongoDBに永続化し、javaのspringbootで指定された統計データを公開するWEBアプリをVPS上で運用してるから、そこら辺の質問あったらアドバイスしてやるよ ちなphp(&laravel)とjavascriptも基本的なことならわかるから質問あったらどーぞ >>152 ってどういうこと? MainクラスがJFrameを継承してRunnableを実装するなんてあり得ない 設計がおかしすぎる 何を作りたいのか知らんがMVCのよくある設計パターンで、ControllerクラスにRunnableを実装したロジック(model)のインスタンスと、JFrameを継承したインスタンスを生成して、JTextfieldなりにsetすればいいんじゃないのか? それとsleepがstatic云々言ってるが引数がプリミティブ型なんだから、何の関係もない ちゃんとリファレンス読んだ? まぁまぁ落ち着いて。 基礎的な動きを確認しながらプログラミング練習してる段階なんでね これはこうしなければならないみたいなものより これはこうしても動くし、こうやっても動くみたいな知識が面白いんだよ javaでGUIってwなんていうけど メーヴェを作って空を飛ぼうとしてるひとに向かって 空飛ぶならヘリコプターかセスナ使えよ!って言ってるのと同じだよ ゴールに到達するまでの時間を競うつもりもないし。 プログラミングを仕事にしたらそういう世界になっていくんだろうけど それってつまんないだろうなと思うんだ せっかく面白い道具があるのに使い方を縛られるなんてね >>156 どういうレベルから助言をくれてるのかわからないからどう答えるべきなのか迷うんだけど まず問題なく動いているということが大事で 今作ったものを土台にいろいろ考えていけるといいなと思ってるよ https://www.javadrive.jp/tutorial/jframe/index5.html extends JFrame にかんしてはこれ >ただし、上記のようにした場合、mainメソッドが含まれるSampleクラスは >単にmainメソッドが存在するだけのクラスとなってしまいます。その為、 >通常はmainメソッドが含まれるクラスそのものをJFrameクラスの >サブクラスにする方法が取られます。 このサイトではクラス名はSampleだけど、おれのだとMainのままになってるだけ。 おれはね、これ読んだ瞬間に面白いなぁって思ったんだけど。 自分とこのクラスにextendsして自分とこのmainメソッドで自分のインスタンス生成するとかさ Swingではこれ普通なの?面白いじゃん じゃ俺もこれ使おうと思ったんだけどね。 基礎レベルのおれには継承やら実装やらの感覚掴むのに悪くないなって思ってる ちなみにイベント系のインターフェースも全部Mainに実装させたらMainの行があほみたいに長くなったね 今は匿名クラス使ってるけどね Runnableも同じようなもんだよ で、あとsleepか そもそも起きた問題と何をしたら解決したのかがちゃんとそっちに伝わってるかわからないし 何を問題と捉えて助言をくれているのかもわからないからちょっと難しいよ もし助言くれるなら、なぜthrd.sleep()だと注意マークがでてThread.sleep()だと出ないのかに 焦点を絞ったもので。引数がどうのこうのの話はそもそもそこが問題の原因ではないだろうと 目星を付けて適当に書いただけで。 問題にしているのはsleepの引数ではなくて、 sleepメソッドがインスタンスから呼び出される場合と クラスから呼び出される場合の違いなんだ だれかに何かを伝えるためにここに書いているというよりも 自分が見直した時に参考になる程度にしか書いてないから いろいろ誤解を与えてるようですまんね このときはこういう風に考えてたけど、間違ってたなとか、 逆に大事な事忘れてたなとか、あとで見たら面白そうじゃん >>153 ( ^ー゚)b ツールチップで次回取得予定の時刻表示させようとしたけど 右クリメニューとかち合うみたいなんでやめやめ 右クリメニューに表示させるかな いずれにしてもRun()メソッドがらみなんでちょいめんどくさそう こんなことやる前に、これまでまとめ上げた内容でもう一度作り直してスッキリさせたほうがいいかもしれん 右クリメニュー関連のコードが迷走してるし あとあれだなぁ ScheduledExecutorServiceを習得したいね めんどくさそうだったから、一番簡単な処理方法に逃げてきたんで お天気取得ソフトのエラーがたまに起きるので修正 0時回って5分後に取得しようとすると明日の日付がhtml上にまだ表示されてないようだ このへん適当にコード書いたんで 日付がないときの分岐処理がなかった String.containsみたいな処理書くときは忘れないようにしないとな 分岐させないと常にエラーがでるようなものだとすぐに気づくんだけど たまにしかエラーがでないものだと忘れ去ってしまう 表示されたエラーの内容は半分忘れてしまったんだけど Stringの配列要素番号として -1 が返されてた 明日の日付が見当たらないと -1 を返してくるようだ いやいや違う >>160 修正 containsは分岐処理でかくものだ エラーの原因はindexOf()で起きてる indexOfに渡す引数が見当たらない時にエラーだ ウィンドウのD&D移動で、 MouseListenerの public void mousePressed(MouseEvent e)での処理なんだけど いつも間違えるのは、コンポーネントの中での相対座標を取得するコード JFrameを継承するクラス内だからComponentのメソッドで「も」ある getX()やgetY()を前置きなしにそのまま使えるんだけど ComponentのメソッドとしてのgetX()、getY()は相対座標取得のメソッドではない getX() コンポーネントの原点の現在のx座標を返します。 なんとなく掴みづらい表現なのだがコンポーネントの左上端の絶対座標を意味してる(と思う) x = getX(); はダメ。ウィンドウ左上端の絶対座標をとってきてしまう x = e.getX(); が正解。eを生んだコンポーネントであるJFrameの左上端を原点としたマウスプレス点の座標を取得できる >>120 では、この辺の処理は pt = e.getPoint(); をつかっており、x と y をばらばらに取得していない ばらばらに取得するならここで書いたように e.getX()、 e.getY() を使うことになる package privateのクラスをよく使うんだけど スッキリ入門のどこに書いてあったか探し出せなかったんだけど やっとみつかったわ カプセル化のところだ タイトルなしのウィンドウを作り D&D移動・右クリから閉じる・前回開いた場所で開き直す こんだけはそらで書けるようにした いろんな要素が含まれてるから基本覚えるには役に立つ 特にイベント処理は ActionListener MouseListener MouseMotionListener WindowListener ComponentListener が含まれていて練習としては悪くない Propertyファイルの取り扱いも基礎レベルでしかないけど しっかり覚えたんで今後に使えそう またテキストに戻るか Main.class----------------- public static void Main class Aaa class Bbb --------------------------- これはOK Xxx.class------------------- class Aaa class Bbb ---------------------------- これもOK クラスはpublicとpackage privateしかない デフォルトはpackage private >>166 修正 public static void Main ↓ public class Main iPhoneアプリ作っても実機にいれようとすると年間1万ぐらい払わないといけないと聞いて 作るならandroidアプリだなと思っていたんだけど よくよく調べてみるとすでに数年前から自分のiPhoneに入れるだけなら無料でいけるようだ いずれにしてももう少し先の話だ 2. プログラミング言語 アプリを開発する上で最も重要なプログラミング言語。 Androidアプリで主に利用されるのはJavaとC++ですが、 2017年にはオフィシャル言語としてKotlinも追加されました。 iOSアプリは主にobjective-Cが使われますが、 より多くの人がiOSアプリを作れるようにと2014年にSwiftが オフィシャル言語に追加されています。 いいでしょ Xamarin(「ザマリン」と読みます)は、C#を用いてiOSとAndroidのアプリケーションを 開発するためのライブラリおよび開発環境です。 XamarinはMicrosoftよりVisual Studioの一部として提供されています ●iOSアプリ プログラミング言語 Objective-C Swift 開発環境 Xcode 開発に使用するOS Mac ●Androidアプリ プログラミング言語 Java 開発環境 Android Studio Eclipse 開発に使用するOS Windows Mac ↓ Xamarin プログラミング言語 C# 開発環境 Visual Studio(Windows)もしくは Xamarin Studio(Mac) 開発に使用するOS Windows Mac Windows上では、Visual Studioという非常に優れた開発環境を 利用してiOS/Androidアプリを開発することができます (注: 詳しくは後述しますがiOSアプリをビルドするには別途Macが必要になります)。 って結局Macいるってことかいな さすがに無理ですわ abstractクラスを継承したときに、 abstractなメソッドをオーバーライドして確定することを 「実装する」と表現する これが「実装」という言葉の基本 インターフェースを実装するというのは インターフェースに含まれるabstractなメソッドをオーバーライドして確定するからこそ こういう表現が使われる eclipseでかき込んだメソッドやクラスにカーソルを合わせてから F3を押すとそのメソッドやクラスの宣言が表示される 中身をみられる F4を押すと階層構造をみることができる むむむ・・・クラウド上でiOSアプリをビルドする・・・だと・・? https://www.macincloud.com/ でもどうやら有料@$22.5/月だそうで http://www.nuits.jp/entry/2016/04/02/124859 ちなみにMacBook買うと大体10まんえんぐらい ん〜やっぱないわ さすがにMac囲い込みすぎだろ iOSは駆逐されて欲しいわ オラクルの決定以後、Java周りはざわざわしてて おれもこの先どうするか考えつつ勉強してる とりあえず実践編読み終わってからちゃんと決めようとは思ってるが できたら実践編の次にある2冊を読みたい Javaそのものの勉強に限らず、サーバやらデータベースやら、 この辺の一般的な知識を頭に入れるいい機会なんじゃないかと思う 他の言語に行くのはいいんだけど、また一からやったら深い所に行くまでにまた時間かかってしまう 言語の勉強だけにいつまでも時間費やせないんで、選択に迷うところだ すでにJavaScript、C#、pythonの入門本は買ってあるんで ちょいちょい浮気しながら様子を見ていこうと思ってる >>173 追加 Shift+F2でeclipse内でAPIドキュメントを表示することができる ZonedDateTimeは実践編で紹介されていたのか この辺の新しい日付の処理方法は便利だな newできないものが多いから注意か 既に作ったプログラムで DateとThreadを使っているものがあるんだけど 正しく動作しないことがあると書いてある ふむむ ArrayList 面白いな ラッパークラスがここに結びついてくるのか eclipseでimport文いれるのがめんどくさくなってきた マウスをクラス名に合わせてポップアップから選択してたんだけど もっと簡単な方法があるはずだと思ってしらべてみた まず、* を使って省略して一気にimportすることにした ウィンドウ→設定→Java→コードスタイル→インポートの編成 .*に必要なインポート数 これが99になってたので1にする インポートの追加([Ctrl] + [Shift] + [M]) 1個ずつimport インポートの編成([Ctrl] + [Shift] + [O]) 一気に全部import これでずっと楽になるはず 実装されていないメソッドの追加 のショートカット alt + shift + s + v 空白を示す正規表現に \s というものがある これをこうやって使ってみるとエラーがでる boolean b = "abc def".contains("\s"); これだとエラーがでない boolean b = "abc def".contains("\\s"); ここに理由が書いてあった https://teratail.com/questions/31841 が、\n だと \\n にしないでも動く 理由の解明は後回しにすることにする とりあえず正規表現で \\ としないと駄目なことがあるということで。 典型的な本読んだだけで理解したつもりになってるタイプだな 入門編読み終わったんならオブジェクト指向で簡単なアプリで作ったら? DBの代わりにファイルに読み書きするToDoリストやクリックすると月が替わるGUIカレンダーとか 本当に理解してるならこのくらい簡単に作れるはず それもできないのに正規表現やThreat知っても成長しないぞ インプットとアウトプットは両方大事だね これはどんな勉強にも言える 入門編読んでから 4つ作って常時起動してるPCでずっと動かしてる もちろん入門テキストの知識だけでは作れないものなので いろんなサイト巡って知識かき集めて作ってある 今やってるというか、つい最近までやっていた作業は 最後に作ったプログラムから自分が気に入った機能を実現するコードを抜き出して 雑だったものをもう少ししっかりしたものに組み直す こんな風にしてお手本コードとしていくつか作っておく そして、こいつらを何も見ずにざっと書けるようにする 書くたびに所々アレンジを加えていろいろ試して見る ということをやってた 一つが大体300行程度のコードか これは結構楽しい ベースとなるコードは毎日同じなんだけど、理解が深まって悪くない 正規表現はずっと昔からいろんな所で使ってきたんだけど もちろんプログラミング始める前の話ではある。 覚えようと思ってはいたんだけど、使う機会が年に数回であとはコピペでいけちゃって なんとなくうやむやにしてて、しっかり頭に入れてなかった なんというか、正規表現には思い入れがあって、是非自分のものにしたいなぁと。 ちょいちょい毎日のアレンジに組み込んで使っているのだ 数日前からはテキストを読み進めている アウトプットは楽しいけど、インプットも進めないと知識の幅が広がらない スカスカな知識でもいいから、こういう事ができるんだということをなんとなく覚えていると アウトプットとしてソフトを作っているときに選択肢が広がる 具体的にどんなアプリ作ったんだ? もしかして>>160 みたいなの? ちなみにカレンダーはそのうち作ろうと思っている 上のほうですでに書いたんだけど、今デスクトップ上で表示してるカレンダーが 日本の祝日や振替休日を正確に示していないので、代用品が欲しい。 その辺から拾ってこれば早いんだけどそれじゃなんだし。 ところで、プログラムを作ってて思うのは、自作のクラスの インスタンスを何個も作って活用するという場面はなかなか出くわさないということ。 いや、正確にいうと、そういう場面に無理やり持っていくこともできるんだけど、 無理してる感がすごくて、不自然すぎる 毎日アレンジ練習でプロパティファイルReaderクラスを作って遊んでたりする カプセル化を施すためにフィールドをprivateにしてsetter、getterを作って setterにはフィルターかけたりなんかするわけだけど、今までつくったような小規模ソフトだと ここまでやっても、おいおい無理スンナよ・・・という天の声が聞こえてくる 多様性の練習でabstractクラスやinterfaceをいくつも作るのは面白い 最後にforでまわして結果がでるとすっきりする が、練習でしかない その点、カレンダーは日付クラスを作ると大量にインスタンス生成できたりなんかして面白そうだ 月クラスや年クラスなんかも組み込んじゃって多重構造にしちゃったりとかいろいろ想像してる 祝日やらの情報は内閣府のcsvを自動で取り込んで組み込んでもいい おそらく今の知識で足りるだろう じゃ、なんで作ってないのかというと、実践編の知識を組み込みたいと思ったからだ 組み込んだほうがよりコード的に面白そうなのがつくれるのであれば、だけど。 今日はコレクションの章を読んだんだけど、この辺も使えそうなら使ってみるつもりだ 日付という集合はキッチリカッチリ仕様が固まっているものなので、 曖昧さが残るデータを取り扱うのに便利そうなコレクションの知識は使えないかもしれないが。 もう一点カレンダーを作るのを遅らせている理由 今の知識だとThreadクラスに定期実行の役割を担わせていくしかない でもThreadクラスはいろいろと問題があるようだ 既にPCで動かしている4つのソフトはどれもThreadクラスを使っていて これ以上そういうソフトを増やすことでPCを不安定リスクに晒したくないというのがある。 これについては問題があって、ざっと見る限り実践編では解決する手段が書かれていない ネットを漁るか別のテキストに手を伸ばすか、という話になる コピペして流用するのは簡単だ でも使うならコピペではなく、ちゃんと理解した上で使いたい 代用となるクラスについては上の方でも何度か書いているが イマイチ自分の理解が浅い部分がある この辺の理解が深まった頃にカレンダーを作るかもしれない そう急ぐものではない 俺も入門書読んでた頃、カレンダーアプリ作ったことある 俺はMVCモデルで、viewはSwingで年月変更するボタンと7×6個のJTextFieldを用意して、そこにmodelとなる二次元配列で作った日付をcontrollerではめ込んでいくって設計にした でも、日付の始まりは月によって違うし祝日は年によって日付が変わるからそこら辺の調整が結構悩んだな 頭で理解するのと、実際にオリジナルのアプリを作るのでは全然違うことを知った いきなりThreat使ったアプリなんて作れるわけないんだから、まずは簡単な設計でオブジェクト指向に則ったちゃんと機能するアプリを作ってはどうよ? 兄さん、それThreatじゃなくてThreadっすよ 何度も間違えてるところからして使ったことないんだろうけど・・・・ おれの作ったアプリは全てThreadクラス利用した定期実行プログラム 兄さん・・・・ おれVBAやってたんだけど やり始めて数ヶ月後にカレンダーをクラスモジュールとform使って作った クリックすれば月がどんどん変っていくやつ 日付をクリックすることでその日付が起点となってエクセルの表に入っていく おれにとってカレンダーを作る事自体はそう難しくないんだよ VBAみたいなオブジェクト指向でない言語でクラスモジュール使って書く方がよっぽど難しいんだ・・・ てかね、そんな競争みたいのどうでもいいんだ なんで言語やってると後ろから蹴り飛ばしながらお前のあれが悪いこれが悪いの 言う人多いんだろうか 楽しんでやろうよ?ね? 予測変換使ってたから間違い気づかんかったw VBAってExcelのマクロを組んだってことでしょ? そうじゃなくて一からアプリを作ったことあるのかってこと 雑学で本読んでるだけならどうでもいいけど、本気でプログラミングを学びたいなら方向が間違ってるってアドバイスしてるだけ ArrayListのインスタンスが変更されると発生する例外 ConcurrentModificationException いろいろと書いてみるとたまに出る iteratorを使って回してると出た iterator宣言文をちょい上の方に書いてしまうと出るようだ whileの直前にしたら出ない どうやらArrayListにaddする前にiteratorをArrayListを対象に宣言してしまうとでるみたいだ addし終わってからwhileで回す直前にいれるようにしよう iterate v 〜を反復する 〜を繰り返して言う 実践編はなかなか重いな 重要なコードはそらで書けるようにしていこう 曖昧なままだと先に進んだところでつまずく とかいいつつ、どれがほんまもんに大事なコードなのかは先に進まないと分からないのだが 一応ArrayListとHashMapの操作法は基本的な部分は頭にいれた ジェネリスクについてより深くやっていくようなのでちょうどよかった public static final String LS = System.lineSeparator(); 改行 定数 今度からこれを使う事にする 旧版 public static final String LS = System.getProperty("line.separator"); 継承関係 B a t t l e C r e a t u r e ↑ ↑ Character Monster ↑ ↑ ↑ Hero Wizard Slime 多様性の話 List<Character> alChar = new ArrayList<Character>(); Character c0 = new Hero("勇者あ"); Character c1 = new Hero("勇者い"); Character c2 = new Hero("勇者う"); Character c3 = new Hero("勇者え"); Character c4 = new Hero("勇者お"); Character c5 = new Wizard("魔法使いa"); Character c6 = new Wizard("魔法使いb"); Character c7 = new Wizard("魔法使いc"); alChar.add(c0); alChar.add(c1); alChar.add(c2); alChar.add(c3); alChar.add(c4); alChar.add(c5); alChar.add(c6); alChar.add(c7); List<Monster> alMons = new ArrayList<Monster>(); Monster m0 = new Slime('A'); Monster m1 = new Slime('B'); Monster m2 = new Slime('C'); alMons.add(m0); alMons.add(m1); alMons.add(m2); List<BattleCreature> alBC = new ArrayList<BattleCreature>(); alBC.add(c0); alBC.add(c1); alBC.add(c2); alBC.add(c3); alBC.add(c4); alBC.add(c5); alBC.add(c6); alBC.add(c7); alBC.add(m0); alBC.add(m1); alBC.add(m2); for (BattleCreature bc : alBC) { System.out.println(bc.getClass()); } こうやってクラス名を取得したときにBattleCreatureではなく 中身のHero、Wizard、Slimeを表示出来ないかと思って試して見たんだけど成功 for (BattleCreature bc : alBC) { System.out.println(bc.getClass().isInstance(c0); } とすることでBattleCreatureの中身がCharacterかどうかをbooleanで戻す事ができる c0としてあるが、これはCharacter変数であればなんでもいい 要は、Character変数に代入できるかどうかを判定してくれてる と思ったが違うわ c0の中身がHeroだから Heroかどうかしか判定してくれてないな ん〜失敗 どちらか全滅までの自動バトルプログラム完成 魔法使いカンの攻撃! スライムAに14のダメージを与えた!(186) スライムCの攻撃! 魔法使いトンは53のダメージをうけた!(0) 魔法使いトンは死んでしまった! 勇者ぽんの攻撃! スライムBに0のダメージを与えた!(200) スライムCの攻撃! 勇者ぽんは64のダメージをうけた!(36) 魔法使いコンの攻撃! スライムBに42のダメージを与えた!(158) 魔法使いカンの攻撃! スライムBに16のダメージを与えた!(142) スライムCの攻撃! 魔法使いカンは127のダメージをうけた!(0) 魔法使いカンは死んでしまった! 勇者ぽんの攻撃! スライムBに140のダメージを与えた!(2) 魔法使いコンの攻撃! スライムBに22のダメージを与えた!(0) スライムBを倒した! スライムAの攻撃! 魔法使いコンは52のダメージをうけた!(0) 魔法使いコンは死んでしまった! スライムCの攻撃! 勇者ぽんは21のダメージをうけた!(15) 勇者ぽんは逃げ出した! 勇者ぽんたちは、ぜんめつしてしまった! 多様性とArrayListの復習になった! おれさまはレベルがあがった! 逃げ出したのに全滅してしまった、はダメか ここは要修正だな WHSをずっとやってた 簡単なコードおぼえた フォルダ作ったりファイルコピーしたり。 Javaと比べると簡単 今日は復習だけ WSHのコード2つ 実践編のコード3つ これだけ 実践編のジェネリクスと列挙型の練習問題、金庫にアイテム出し入れするやつ 最初見たとき一体これはなにやってんだと思ったけど、 いろいろやってたら理解できた ・自作のジェネリクス付きのクラスを使う事でいろんな型のインスタンスをを金庫に入れることができるようにする ・次に、金庫を守るためにカギとなる仕組みを作る ここで列挙型を利用する 久しぶりのswitchがでてきて復習になった switch (keytype) { case LOCK : break; case FINGER : break; } 2つを分離して考えないといけない 昨日少しだけラムダ式だっけか 読んだけど、また明日にしよう 実践編は各章の練習問題を解けるようにすることを目標とする 解けるというか、覚えて利用出来るようにしておく これだけだと、テキストに書いてあることの一部しかカバーできない でも、実践編では、最低限の重要な知識を抑えることに焦点を絞ることにする toStringのオーバーライドとかクソつまらなさそうなのは切って捨てたいけどどうすっか この辺は自分で使うイメージが全くわかない コレクションのところで自然順序とかなんとかでこの辺のオーバーライドがされてないと ダメだと説教されたんで、大事なんだろうけど とにかく最後までなんとか読み切る Javaでは型安全、型安全で列挙型やらやってるんだけど WSHは変数宣言いらないわ全部Variantだわで適当もいいところだ 楽だけど 復習復習復習 Calendar c = Calendar.getInstance(); c.set(Calendar.DAY_OF_MONTH, get(Calendar.DAY_OF_MONTH) + 100); のように書くと、c の日付は +100 される これと比較したいのはLocalDateTimeクラスを使ったパターン↓ LocalDateTime ldt = LocalDateTime.now(); ldt.plusDays(100); これだと ldt の日付は +100 されない plusDays()をCalendarクラスのset()と同じような感覚で書くと間違える plusDays()は戻り値がLocalDateTimeオブジェクト→オブジェクト変数に格納必要 set()は戻り値がvoid→変数への格納不要 正解は、2行目を ldt = ldt.plusDays(100); とすることで100日加算されたオブジェクトに置換える必要がある 同じような間違いとして SimpleDateFormat sdf = new SimpleDateFormat("西暦yyyy年MM月dd日"); System.out.println(sdf.format(c.set(Calendar.DAY_OF_MONTH, get(Calendar.DAY_OF_MONTH) + 100).getTime())); とするとエラー 原因は set() の戻り値をCalendarオブジェクトと勘違いしている点 もしそうであれば c.set().getTime() によってDateオブジェクトを取得できる しかし c.set() はvoidである よって、これにgetTime()をつなげることはそもそもできない もう何度もやってるからわかってるわいと思ってアレンジして書くといろいろと問題が起きる 細かい部分が分かってないことがアレンジによって露呈する そういえばすっきり入門の最初の方でこういうのを書いていた String s = new java.util.Scanner(System.in).nextLine(); 理屈はいいから覚えろみたいなことが書いてあったんだけど 覚え直した方が逆に楽になりそうだ Scanner sc = new Scanner(); String s = sc.nextLine(); 単純にScannerクラスのインスタンス生成して nextLine()を呼び出しているだけ importは別途必要だ ディープクローンが難しかった テキストと同じ形式なら理解できたんだけど 少し違った形にすると突然難しくなる ディープクローンの必要性がある変数がprivateで さらに、コンストラクタの引数になっているような場合 やっと練習用雛形作れたから何度も書いて理解していこうと思う equalsやhashCodeその他のオーバーライドも組み込んだから この辺の復習として使う 結局この辺はコレクション関連分野でもあるんで コレクションの復習にもなる >>183 について \n \s この2つはそもそも種類が違う \n は改行で、\s は空白だから違うのは当たり前とかそういう意味じゃない 属しているグループが全然違う \n は \t \r などと同じ「エスケープシーケンス」 \s は \w \d などと同じ「あらかじめ定義されている文字クラス」 \n " " の中にそのまま書いただけで \n という文字そのものではなく、 「改行」として認識される \s " " の中に書いたときに 「 \s という文字列として認識」 された場合に 初めて特殊な意味、ここでは「空白」として認識される もう少し詳しく書く "\s" と書いてしまうと、\ を特殊な記号として認識してしまう そのため、これはエスケープシーケンスの一種だな、と誤解してしまう しかしエスケープシーケンスには \s は存在しないため、エラーとなる 「 \s という文字列として認識」 させるには \ がもつ特殊な機能を消し去って \ そのままの文字列として認識させる必要がある そこで、\ の前にもう一つエスケープのための \ をつける こうすることで、 「 \s という文字列として認識」 してもらえる つまり、あらかじめ定義された文字列を matches などで使う時は、総じて \\s \\d \\w のような書き方をしなければならないということになる >>216 修正 つまり、あらかじめ定義された文字列を matches などで使う時は、 ↓ つまり、あらかじめ定義された文字クラスを matches などで使う時は、 >>183 の中に書いてあるURL ここで質問している人は、おれと同じように、 \n のようなエスケープシーケンスと混同したのだと思う 回答にはエスケープシーケンスとの違いが説明しているものがない 質問した本人は分かったつもりでいるみたいだけど、 問題は解決できてないんじゃないかと思う スッキリ実践編にもその辺を書いてくれるとよかったな ここで疑問がもう一つ生まれる \s が 「 \s という文字列として認識」 されたときに初めて 「空白」 と捉えてもらえる それならば、 \s という文字列とマッチするかどうかを調べたいときはどうすんぢゃい と。 String s1 = "\\s"; System.out.println(s1); if (s1.matches("\\s")) { System.out.println("s1 ok"); } これではokはでない s1 は \s と認識されているが matches("\\s") の \\s は 「空白」 として認識されてしまうためマッチしない \s と書くとエラーでるし。 今後の課題として残しておこう >>219 String s1 = "\\s"; System.out.println(s1); if (s1.equals("\\s")) { System.out.println("s1 ok"); } これで一応おk 要は s1 で \s と認識できたわけだから 同じようなレベルで認識してもらえるようなメソッドを使えばよいだけ そもそもmatchesでは不可能なのかもしれない containsでもいけた C#関連(本買っただけで何もやってないが) ビルドの中にコンパイルがある。 コンパイル: コンピュータが実行するのに適した形式に変えて、実行可能なファイルに変換する。 ビルド: コンパイル+使っているライブラリに関連づける(リンク) https://qiita.com/rico/items/9ab8aa110e757a13ef37 Visual Studio が無い Windows 環境で c# コードをコンパイルする https://qiita.com/asterisk9101/items/4f0e8da6d1e2e9df8e14 スクリプト 簡易的なプログラムのこと。スクリプトを記述するための言語をスクリプト言語といい 、機械語への翻訳を必要とせずに実行できる。スクリプト言語は、 アプリケーション開発用の本格的なプログラミング言語に比べ、 用途を限定することで、覚えやすいように簡単な構造になっている。 代表的なスクリプト言語としては、JavaScript、PHP、Perlなどがあり、 特定のアプリケーションの動作の記述、マクロやバッチファイルの作成、 CGIなどの簡単なプログラムに用いられる。 https://kotobank.jp/word/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88-4871 最近使ってるVBSもスクリプト言語 × A.instanceof(B) ○ A instanceof B instanceofは演算子 演算子の種類としては関係演算子または比較演算子と呼ばれるもので == < > <= <= != などと同じ種類 メソッドだと勘違いしがちなので注意だ https://www.javadrive.jp/start/ope/index11.html public class Book { public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (!(o instanceof this)) return false;//←ここダメ } } A instanceof B は 「参照型変数a が bクラス/インターフェース/配列のインスタンスかどうか」 を調べるものなので Bにインスタンスを持ってきてはダメ Bに来るのはこの場合だとクラス名のBook if (!(o instanceof Book)) return false; が正解 >>219 正規表現で\sという文字列を表すにはエスケープして\\sとなる だがこれをそのまま引数に渡すとJVMが最初の\を文字エスケープと認識して\sという文字列に変換し、結果的に正規表現の空白文字にマッチするか検証することになる \\sという文字列を正規表現として渡すには文字エスケープが2つ付けて、\\\\sとする必要がある >>227 なるほどねぇ 言われてみればそうだな String s = "\\s"; System.out.println(s); if (s.matches("\\\\s")) { System.out.println("ok"); } ちなみにだけど、>>227 の前半部分の説明を \n についてすると? ラムダ式とかの6章クリア 練習問題とstream()の基本的な使い方ぐらいだけど、まぁいいか ぐぐるとラムダ式使ってるコードってたまに出てくるから 参考にしたいときに使える知識かなとは思う ProcessBuilder pb = new ProcessBuilder( "c:\\windows\\system32\\notepad.exe", "calcreport.txt"); ProcessBuilder pb = new ProcessBuilder("java", clazz.getName() ); こいつら、上が第7章198ページ、下が同じく第7章217ページ練習問題の答 上が本文内で出てきたときは、まぁこんな感じで外部のexe起動できるんだな ああそうですか、で終わった 練習問題で下のが出てきて???????????????ですわ 一応練習問題はできるようにするという目標を立てているので、しゃーないから調べてみた 意外と簡単だった つまりだ、 ●CMDでなんかプログラムを起動するときに >xxx yy zz みたいに打ちこんでEnterパーン!てやるとする ちなみにxxxはexeだったりいろいろ ●これをJavaから同じように起動したいと思うなら ProcessBuilder pb = new ProcessBuilder("xxx", "yy", "zz"); pb.start(); 具体的に書くと ●CMD >notepad /W test.txt ●Java ProcessBuilder pb = new ProcessBuilder("notepad", "/W", "test.txt"); pb.start(); CMDでnotepadのかわりにnotepad.exeとしてもいいのだが これはJavaのほうでも同じで "notepad" のかわりに "notepad.exe" としてもよい ちなみにメモ帳はパスが通ってるからCMDにおけるカレントフォルダがどこであっても notepad.exeへの完全なパスなしで起動できる ProcessBuilderの第一引数においても同様に絶対パスを書く必要はない とにかくCMDでどう書くのかを参考にして書けばいいだけ よって上に書いた1個目のProcessBuilderの宣言で ProcessBuilder pb = new ProcessBuilder("notepad.exe", "calcreport.txt"); と書いてもいける ただし、違いが一つある CMDだとcalcreport.txtがカレントフォルダになければ新しく作りますか? とのウィンドウがでる Javaではcalcreport.txtが存在しないとエラーが生じる 2つ目の ProcessBuilder pb = new ProcessBuilder("java", clazz.getName() ); も同様 CMDでFQCNを使ってclassファイルを実行する場合に >java jp.co.aaa.Calc としてEnterパーン!とするなら Javaでは ProcessBuilder pb = new ProcessBuilder("java", "jp.co.aaa.Calc"); pb.start(); と書く 第二引数が clazz.getName() となっているのはFQCNを取得するためだ 👀 Rock54: Caution(BBR-MD5:1341adc37120578f18dba9451e6c8c3b) >>230 の2つ目を考えるにあたって注意しなければならないこと あくまでも ProcessBuilder は「外部」プログラムの実行に使われる よって、 Javaのクラスファイルを実行するといっても、 外部に存在しているコンパイル済のクラスファイルの実行に使うであって 今現在組んでいるソースコードに存在する他のクラスを指定してもダメ コードが正常に動くか実験したい時に勘違いしないようにする Eclipseで楽してたらコマンドラインから実行する方法忘れてしまった 例: Main.class ----------------------- package aaa; public class Main { public static void main(String[] args) { System.out.println("test"); } } ----------------------- (パスを通さないことを前提に説明・カレントフォルダ名はtestとする) これをコマンドラインから起動するときは フォルダtestの中にフォルダaaaを作る その中にMain.classを入れておく propertiesファイルとか使うなら フォルダtestに入れておく CMDでフォルダtestに移ってから >java aaa.Main で起動 eclipseのワークスペースからクラスファイルを拾ってくる時は binフォルダの中をみればいい ただ、この中にMain.classとは異なる見慣れないものが入ってたりする Main$1.class Main$2.class Main$3.class eclipseがバックアップ用に用意したものかと思ってフォルダaaaにコピペしなかったらエラー 表示をみるとどうやらこいつらも必要なようだ この3つもaaaに放り込んだらうまく起動した ProcessBuilderのテストはまた今度にしよう ここつまんねぇなぁ 覚えても意味なさそうだぁ とか思っててもいざ練習問題ちゃんと出来るようにしようとすると 派生的にいろんな所の復習することになる この 「いろんな所」 が結構大事な分野だったりするんで 結局がんばってやったほうがいいんだろうな よし、ProcessBuilderによるclassファイル実行でけた eclipseの今扱っているプロジェクトのプロジェクトフォルダの直下に フォルダaaaをおいてこの中にMain.classを入れる ProcessBuilder pb = new ProcessBuilder("java", "aaa.Main"); pb.start(); で起動確認済 >>235 の状況下で Class<?> c = Class.forName("aaa.Main"); System.out.println(c.getName()); はできなかった ProcessBuilderではいけるのになぜだ もしかしてと思いながらbinフォルダの中にaaaフォルダをぶちこんだら行けてしまった 手法がどうであれ、ClassクラスもProcessBuilderと同様に外部のクラスファイルに アクセスできるようだ eclipseでコマンドライン引数を渡して実行する方法 実行の構成→「引数」タブ→プログラムの引数 ここにコマンドライン引数を並べればいいだけ >>236 はちと違う感じがする クラスファイルへのアクセスってのは内部も外部もないのでは。 この辺は学習が進めばハッキリしてくるだろう 7章の練習問題は解答が間違えてるようだ https://teratail.com/questions/153338 問題の指示によると、 文字列配列を引数とするmainメソッドの存在を確認しなければならない 存在する場合のみ、第二引数による条件分岐に入る にもかかわらず、 @条件分岐に入ってから存在確認処理をしているのが第二引数が I のケース Aそもそも存在確認を行ってさえいないのが第二引数が E のケース @の存在確認とは、 getMethod()によって 文字列配列が引数であるmainメソッドを指定している この条件に当てはまるメソッドがない場合に例外が投げられるようになってる (throws Exception) 例外はメソッドを呼び出したmainメソッドで処理される という部分を指している >>239 の間違いを正したコードを書いてた これでいいだろと思って実行してみるんだけど ProcessBuilder による起動がうまくいかない 起動するクラスのmainメソッドには System.out.println("eating memory......."); と書いてあるのだが、これが表示されない ProcessBuilderによるクラス実行は実験済で間違いないはずなのだが いろいろやっても上コメントが表示されない まさかな、と思ってこれを実行するクラスのmainメソッドに追加 JFrame jf = new JFrame(); jf.setSize(100, 100); jf.setVisible(true); そしたらなんとフレームが出現するじゃないか ProcessBuilderによる実行は、「外部プログラム」の実行なので、printlnがあっても 内部的な処理結果を表示するコンソール画面には出ないということか ちなみに実行するクラスファイルはbinフォルダに置いたままではだめ プロジェクトのフォルダ直下に置く ProcessBuilderによる実行は、やはり「外部のプログラム」を動かすものなので eclipse上、カレントフォルダはプロジェクトのフォルダ直下(この辺は不確実) いやはや やたら時間を食う章だ 今日はこの辺で終わり ちなみにリフレクションによる実行では ちゃんとコンソールにprintlnの内容が表示される これが External Launch と Internal Launch の違いってことかな >>238 の続きなんだけど、リフレクションによる実行は「内部」だね >>236 で、binフォルダにaaaをぶち込むと実行できたのは まさにbinフォルダが内部的なものだからだ 普通にクラスのソースコードを書いて実行するとbinフォルダにクラスファイルが生成される つまり、binフォルダにクラスファイルを置くということは、 ソースコードに書いたのと結果的に同じ 外部のクラスファイルを持ってきたという考えはしない方がいい >>239 の問題をクリア @で使っている例外を利用してmainメソッドの存在確認をする方法は 秀逸だと思うので、これはちゃんと利用する ただし、 launchInternalメソッドの中に書くのではなく mainメソッドに書く --------------------------------------------- try { m = c.getDeclaredMethod("main", String[].class); } catch (NoSuchMethodException e) { System.out.println("指定されたメソッドが存在しません。"); System.exit(1); } ----------------------------------------------- m は static なクラス変数として宣言したMethodクラスのインスタンス変数 クラス変数としたのは launchInternalメソッドにおいて invoke するのに流用するため あと、launchExternal メソッドで起動した場合に起動確認のためJFrameを表示させたい そこでMemoryEaterクラスの main メソッドの中にJFrame表示のコードを入れた さらにフレームタイトルに launchInternal、 launchExternal どちらから起動されたか わかるように I か E の文字をいれることにする そのため、これらのメソッドを起動する際に、I か E の引数を渡すことにする 内部起動か外部起動かによって引数の渡し方が違ってくるところがポイント ------------------------------------------------------------- public static void launchExternal(Class<?> clazz) throws Exception { ProcessBuilder pb = new ProcessBuilder("java", clazz.getName(), "E"); Process proc = pb.start(); proc.waitFor(); } public static void launchInternal(Class<?> clazz) throws Exception { String[] args = {"I"}; m.invoke(null, (Object)args); } -------------------------------------------------------------- この問題は例外処理の復習になる ●例外インスタンスを自分で投げるケース throw new IllegalArgumentException("起動方法の指定が不正です"); IllegalArgumentExceptionはメソッドの引数が不正 ●例外を伝播させる public static void launchExternal(Class<?> c) throws Exception { } throws と複数になってるところがポイント ●例外処理中の e.getMessage() とは これは e.printStackTrace() を使った場合に表示されるメッセージが冗長なため、 これらのメッセージのうち一部分だけを表示させたいときに使うようだ 具体的には、今取り組んでるコードにおいて、実行対象となるクラスにmainメソッドがない場合 もし e.printStackTrace() なら ----------------------------- java.lang.NoSuchMethodException: MemoryEater.main([Ljava.lang.String;) at java.lang.Class.getMethod(Class.java:1786) at Main.main(Main.java:19) ------------------------------ もし System.out.println(e.getMessage()); なら ------------------------------ MemoryEater.main([Ljava.lang.String;) ------------------------------ 調べた結果このようになったのだが、疑問に感じたのは実践編7章解答で catchの中にこのような記述がある System.out.println(e.getMessage()); e.printStackTrace(); 包含関係にあるこの2つを並べることに何の意味があるのか分からない 今のところは自分が調べた結果を信じることにしておこう e.getMessage()はエラーメッセージを簡潔に書きたいときに使うもの、とする あとこれ Method m = clazz.getMethod("main", String[].class); getMethodメソッドの第二引数 String[].class この class は何なんだ! 調べまくって何となく分かったんだけど、要はこの class は実践編209ページの Class インスタンスの基本的な取得方法の一つ Class<?> cinfo = クラス名.class の class と同じものだということ。 String[].class は文字列型配列に関するClassクラスのインスタンスである リフレクションと呼ばれる分野について学習してるわけなんだけど 特徴的なのはあるクラスを対象とするとき、 そのクラスを対象とするClass クラスのインスタンスを生成する点 この先はざっくりとした説明になる。 場合によるのだろうが、この分野において、 メソッドに渡す引数の(クラス)型を指定するときも 同様の配慮をしなければならないようだ つまり、メソッドの仮引数が int i となっていたら、実引数は int.class のように表現する場合があるということ getMethod のレファランスを見てみると public Method getMethod(String name, Class<?>... parameterTypes) Class<?> はまさにClassクラスのインスタンスをここにもってこいという事 clazz の宣言文を補足する 例えばこんな風になる Class<?> clazz = MemoryEater.class; Method m = clazz.getMethod("main", String[].class); これは、下のように書いてもよいということになる Class<?> clazz = MemoryEater.class; Class<?> stClazz = String[].class; Method m = clazz.getMethod("main", stClazz); 分析の対象となるクラス(MemoryEater)もClassクラスのインスタンスを生成し 分析の対象となるクラスで使われる引数のクラス型(String[])についても Classクラスのインスタンスを生成して使いなさい!ということらしい クラス名.class クラスリテラルとかなんとか タイプリテラルとか リテラル記法とか なにやらかなり特殊な書き方のようだ 今日はこれで終わり 自作Classに含まれるメソッドリスト main wait wait wait equals toString hashCode getClass notify notifyAll これまで間違えてコードを書いてたみたいで main以外表示されてなかったんだけど、さっき間違いに気づいて修正 こんなにでてきた Objectクラスから引き継いだものも表示されるのな 複数のwaitはオーバーロードか コマンドライン引数によって受けとったclassファイルを ProcessBuilderによって起動するテストをeclipse上でやろうとすると失敗することが多い というかclassファイルのソースコードを修正しては起動するみたいなことをしていると起動しなくなったりする eclipse上ではなくてちゃんとコマンドラインから起動すれば正常に動くので eclipseの問題なのか まぁこれ以上ここに時間を費やすのもどうかと思うから追究するのはやめるか 今日はずっと前にやってたところの復習してた せっかく覚えたのに忘れるのもったいないからたまにやらないとね 9章269ページあたりを読んでるんだけど System.out.println() とは結局何なのだろうかと。 System はクラス名で out はそのフィールドで、型は PrintStream つまり System クラスでは PrintStream out; みたいな宣言があるわけだ (実際には public final static PrintStream out = null;) んで、PrintStream クラスのメソッドの一つに println() がある out はクラス型をフィールドに用いたもの すっきり入門340ページの Hero クラスのフィールドとして宣言されている Sword sword; と同じようなものか 341ページの下に hsword.name というのがあるが、もし Sword クラスの name フィールドが private で getter が置かれているとしたら @ h.sword.getName() となっていたはず これと A System.out.println() は結構似てると考えていいのか 違いは、@では Hero クラスの中で宣言されている sword は static ではないため アクセスするには Hero クラスのインスタンス h を生成したが Aでは、System クラスの中で宣言されている out が static 宣言されているため インスタンス生成が不要だった点 こういった構造を、フェイクを使いながら書くと、こんな感じになるのか これでいいのかな 警告はでてるけど実行可 public class Main { public static void main(String[] args) { Systemm.outt.printlnn("aaa"); } } class Systemm { static PrintStreamm outt; } class PrintStreamm { public static void printlnn(String st) { System.out.println(st); } } >>253 の PrintStreamm#Printlnn から static を抜いたら警告が消えた 理由はあとで考えることにする public class Main { public static void main(String[] args) { Systemm.outt.printlnn("aaa"); } } class Systemm { public static PrintStreamm outt; } class PrintStreamm { public void printlnn(String st) { System.out.println(st); } } 例えばこのスレを 「2ch.txt」 に全コピペして保存 (例外は投げるとする) FileReader fr = new FileReader("2ch.txt"); BufferedReader br = new BufferedReader(fr); String line = br.readLine(); while (line != null) { System.out.println(line); br.readLine(); } これだと文字化けしてしまう そこで文字コードを指定したい 実践編260ページの記述によると、 FileReaderのコンストラクタで文字コード指定ができるかのように思われるが 実際はできない。いや出来るのかもしれないが調べた限りでは分からなかった ぞ 文字コードの指定には FileInputStream InputStreamReader を使う (この辺はHTML取得の時に使ったコードに似てる URL、InputStream、InputStreamReader を使った) FileInputStream fis = new FileInputStream("2ch.txt"); InputStreamReader isr = new InputStreamReader(fis, "SJIS"); BufferedReader br = new BufferedReader(isr); String line = br.readLine(); while (line != null) { System.out.println(line); br.readLine(); } これで文字化け回避できた SJIS はググってでてきたものを適当にいれたらいけたってだけ TeraPad というテキストエディタを昔から使っているのだが、 下の方に文字コードが表示される 試しにこのスレやgoogleの検索結果のページやらをコピペしてみたり パソコン内にあるいろんなファイルをTeraPadで開いてみたりしたが 全て SJIS と表示されていた というか SJIS と指定して開いているからそう表示されるのかもしれないが 少なくとも、TeraPad でみたときに文字化けしていない状態で、SJIS と表示されているなら SJIS がこの場合の正しい文字コードなんだなと ちなみにeclipse上で、デフォルト文字コードを取得するこれ System.out.println(System.getProperty("file.encoding")); を確認してみると UTF-8 と表示される この違いが文字化けの原因だ この辺はstream関連のクラスがたくさん出てきて何がなんだか分からなくなる 整理する -------------------------------基本用語 ●文字ストリーム系 Writer、Reader がクラス名に入る ●バイトストリーム系 OutputStream、InputStream がクラス名に入る -------------------------------- ・基本用語の頭に File がつくと ストリームの終端がファイルであるクラスになる ・基本用語の頭に Buffered がつくと バッファリングされた出力または入力ストリームをつくるクラスになる ・特殊なものとしてバイトストリームと文字ストリームの橋渡しをするクラス OutputStreamWriter : 文字をバイトにエンコード InputStreamReader : バイトを文字にエンコード どちらも指定された文字セットを用いて変換することになるが 指定がなければシステムのデフォルトの文字セットを用いることになる この文字セット指定がまさしく >>255 でやった "SJIS" である ここでは文字セットとは文字コードと同義か >>255 を再考 FileInputStream fis = new FileInputStream("2ch.txt");//@ InputStreamReader isr = new InputStreamReader(fis, "SJIS");//A BufferedReader br = new BufferedReader(isr);//B String line = br.readLine(); while (line != null) { System.out.println(line); br.readLine(); } >>257 の「基本用語」に注目しながら分析 @一旦バイトストリームによってファイルを読み込んでいく (バイトだからInputStream) A吸い上げたバイトを文字にエンコードするが、その際文字セットを SJIS に指定 (橋渡し役) B変換された文字をバッファリングする (文字だからReader) InputStreamReaderのせいで頭が混乱してた 常に文字セットを指定してれば橋渡し変換役だってことが理解できてたんだけど 文字セット指定がないデフォルトでこれまで使ってたんで 役割が頭ん中で明確になってなかった public class Main { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; BufferedOutputStream bos = null; GZIPOutputStream gos = null; try { fis = new FileInputStream("test.txt"); fos = new FileOutputStream("test.txt.gz"); bos = new BufferedOutputStream(fos); gos = new GZIPOutputStream(bos); int i = fis.read(); while (i != -1) { gos.write(i); i = fis.read(); } } catch(IOException e) { e.printStackTrace(); } finally { try { if (fis != null) fis.close(); if (gos != null) gos.close(); } catch(IOException e) { } } } } 実践編9章の練習問題 コマンドライン引数はテストが面倒なので内部指定した test.txt を読み込んで、同じ内容を test.txt.gz にかき込むんだけど、 書込みの際のフィルタリングとして バッファリング+圧縮 が指示されている 文字ストリームは一切使わず バイトストリームのみで処理するため Reader、Writer がついたクラスは出てきていないのがポイント FileOutputStream ↓ BufferedOutputStream ↓ GZIPOutputStream の順でフィルタにかけてるんだけど FileOutputStream ↓ GZIPOutputStream ↓ BufferedOutputStream でやったらどうなるかテストしてみた 作成されるgzファイルが壊れてた GZIPOutputStream が最後じゃないとだめみたいだ >>260 修正 gos.flush(); を忘れてた while ブロックの直後に挿入するとする ふらぁぁぁぁぁぁぁっしゅ! >>261 逆でもいけるやろ どっちもOutputStreamのサブクラスなんやから gzip形式で圧縮してるんだから直で開いても見えへんで 解凍するかGZIPInputStream使わんと public class Main { public static void main(String[] args) { try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt")); BufferedOutputStream gos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test.txt.gz")));) { int i; while ((i = fis.read()) != -1) { gos.write(i); } } catch (IOException e) { e.printStackTrace(); } try (BufferedReader gis = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream("test.txt.gz"))));) { String str; while ((str = gis.readLine()) != null) { System.out.print(str); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } >>263 ほんとだ たぶんコードをどこかで間違えてたな しかしわかりにくいので勝手に改変 GZIP→Buffer (test_gos-bos.txt.gz) Buffer→GZIP (test_bos-gos.txt.gz) フィルタ順を変えた2つ圧縮ファイルが作られるがどちらも正常 public class Main { public static void main(String[] args) { try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt")); BufferedOutputStream bos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test_gos-bos.txt.gz")));) { int i; while ((i = fis.read()) != -1) { bos.write(i); } } catch (IOException e) { e.printStackTrace(); } try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt")); GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream("test_bos-gos.txt.gz")));) { int i; while ((i = fis.read()) != -1) { gos.write(i); } } catch (IOException e) { e.printStackTrace(); } } } 自分のコードでも成功 public class Main { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; BufferedOutputStream bos = null; GZIPOutputStream gos = null; //bos→gosの順 try { fis = new FileInputStream("test.txt"); fos = new FileOutputStream("test_bos-gos.txt.gz"); bos = new BufferedOutputStream(fos); gos = new GZIPOutputStream(bos); int i = fis.read(); while (i != -1) { gos.write(i); i = fis.read(); } } catch(IOException e) { e.printStackTrace(); } finally { try { if (fis != null) fis.close(); if (gos != null) gos.close(); } catch(IOException e) {} } //gos→bosの順でもOK try { fis = new FileInputStream("test.txt"); fos = new FileOutputStream("test_gos-bos.txt.gz"); gos = new GZIPOutputStream(fos); bos = new BufferedOutputStream(gos); int i = fis.read(); while (i != -1) { bos.write(i); i = fis.read(); } } catch(IOException e) { e.printStackTrace(); } finally { try { if (fis != null) fis.close(); if (bos != null) bos.close(); } catch(IOException e) {} } } } fos = new FileOutputStream("test_bos-gos.txt.gz"); を fos = new FileOutputStream("test.txt_bos-gos.gz"); と指定すると 中身のファイルが、拡張子なしの test.txt_bos-gos になるという事に気づいた こういう仕様なのか ちなみに作成された圧縮ファイルが正常化どうかのチェックは WinRARを使って適当にやってる そして flush() がまた抜けているという件 ふらぁぁぁぁっぁぁぁぁぁっしゅ!!! finally使わないでいい書き方だけど try () のカッコの中に複数文書いてもいいんだな おれはこういう風に書きたい public class Main { public static void main(String[] args) { try ( BufferedInputStream fis = new BufferedInputStream(new FileInputStream("test.txt")); BufferedOutputStream bos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test_gos-bos.txt.gz"))); ) { int i; while ((i = fis.read()) != -1) { bos.write(i); } } catch (IOException e) { e.printStackTrace(); } } } 12章のデータベースアクセスを読んでいるのだけど 実践編の次の位置にあるテキストとして スッキリわかるSQL入門がある これはJavaのテキストかと思っていたのだが そういうわけではなさそうだ 「スッキリわかるサーブレット&JSP入門」 はJavaのテキスト この2冊に踏み込むべきか、迷うところだ ん〜いろいろぐぐってみたがSQL入門は買っておいたほうがよさそうだな どうせだからサーブレットの方も買うか? それはともあれ、データベースは実践編12章で触ることになるため DBMSの導入が必要となる ここでは実践編が勧める HS Database を導入することにする インストールまでは簡単だ 適当にぐぐれば出てくる 次に・・ 実践編335ページ >以後、この章のプログラムの実行時には、このJARファイルにクラスパス >(eclipseの場合はビルドパス)を通して実行する必要があります。 eclipseを使っているのでビルドパスとやらを通さなければならない 調べた結果 ビルドパスはプロジェクトごとに通していくことになる ここでいうJARファイルとは、バージョンごとにファイル名は違うだろうが おそらくH2 Databaseをインストールしたフォルダにあるこれ H2\bin\h2-1.4.197.jar であろうと推測できる このjarファイルを外部のライブラリとして追加していくことを意味するのだろう まずプロジェクトのプロパティーを開く 方法はいろいろあるが、パスを通したいプロジェクトをパッケージエクスプローラで選択した状態で プロジェクト→プロパティー 次に →「ライブラリー」タブ→外部JARの追加 ここで上記のjarファイルを選択する こうすることで、パッケージエクスプローラ上で、当該プロジェクトを開いた場合に 「参照ライブラリー」 が追加されており、この中に h2-1.4.197.jar が配置されることになる 不正確なら以後修正していく public class Main { public static void main(String[] args) { try { Class.forName("org.h2.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Connection con = null; try { con = DriverManager.getConnection("jdbc:h2:G:\\DB\\H2_Database\\test01"); } catch(SQLException e) { e.printStackTrace(); } finally { if (con != null) { try { con.close(); } catch(SQLException e) { e.printStackTrace(); } } } } } ファイルが作成されたので、これでとりあえずいいのか Class.forName("org.h2.Driver"); の org.h2 については、パッケージエクスプローラから h2-1.4.197.jar を開くと 直下に同じ名前のパッケージがあるので、これだろう ん〜ん〜 実践編361ページのコード これおかしくないか? いろいろとまだ知識が固まってないので自信あるわけではないが con.close(); の位置 finally ブロックに書かれているのは、どんなときでも必ず実行されなければならないから。 (もちろん if 文で示す通り null の時は除くけど) しかしだ、この finally ブロックが置かれている位置、catch ブロックの「中」だぞ? ということは例外が catch されなければ実行されないんじゃないのか? おかしいのであれば誰かネット上で指摘してるはずだと思って ぐぐってみたけどヒットしない おれがおかしいのですか〜 public class Main { public static void main(String[] args) { //finallyが※の内側のケース try { Class.forName("org.h2.Driver"); } catch (ClassNotFoundException e) {//※ System.out.println("@"); try { Class.forName("org.h2.Driver"); } catch(ClassNotFoundException ee) { System.out.println("A"); } finally { System.out.println("finally内側"); } } //finallyが※の外側のケース try { Class.forName("org.h2.Driver"); } catch (ClassNotFoundException e) {//※ System.out.println("A"); try { Class.forName("org.h2.Driver"); } catch(ClassNotFoundException ee) { System.out.println("B"); } } finally { System.out.println("finally外側"); } } } 結果は 「finally外側」 「finally内側」 が表示されるのは、一つ目の※で存在しないクラスを指定した時 この時例外をキャッチして catch ブロックに入る そこで初めて finally は実行される ん〜おかしいよね? いや、話はもう少し複雑なのか? con が catch 文の中でも使われているから内側、外側両方で finally がいるということか? つまり上の例で言えば public class Main { public static void main(String[] args) { try { Class.forName("org.h2.Driver"); } catch (ClassNotFoundException e) {//※ System.out.println("@"); try { Class.forName("org.h2.Driver"); } catch(ClassNotFoundException ee) { System.out.println("A"); } finally { System.out.println("finally内側"); } } finally { System.out.println("finally外側"); } } } いやいや、やっぱり違う 内側で使った con は結局、外側の finally で close されるからいいんだ やっぱ内側の finally は必要ないはずだ にも関わらず実践編361ページでは内側のみに finally があるのでおかしいなぁ というのが疑問点 ま、とりあえず12章まで読むだけ読んだ ちょい飛ばしたから、今週は先へは進まずに復習のみでもおkか とか言いながら、斜め読みしながら先へ進むおれ 「リファクタリング」 これな 以前VBAの10,000行ぐらいのプログラム書いたんだけど おれが組んだもので一番でかいやつ 今も他人によって使われてて、自分でいうのもなんだけど役に立っている しかし中のコードはひどいもので その原因の一つは、VBAを一から勉強しながら書いていたから、 勉強初期の頃のコードと、それなりに理解できてきた頃のコードが絡まり合って、それはもう。 もう一つは、計画性がなく気ままに機能を追加してきた結果、ネストの階層がとんでもなく深い 滅多に表層にでないバグを潰したりして、最終的に完成するまでに2年はかかっている たぶんもう一度組み直せばすっきりとして実行速度もあがると思うのだが あの苦労をもう一度・・・と思うと。 コードをいじらないでも設定を柔軟に変えられるよう、 各種設定値をワークシート上に記述できるようになってはいるのだが 実は全て正常に動くかは全部チェックしてない この辺も組み直す過程でチェックできるだろう 今はおれが触れる場所にいるのでなんとかなるのだが いずれ離れる予定なので、それまでにはなんとかしないといけないのだが。 めんどい 初心者あるあるやね ワイも昔は一つのクラスの中にズラーっと書いて保守性も拡張性も考えとらんかった といってもプログラミング始めてまだ半年の素人やけども 最近は機能別にクラス分けするようにしとるけど、今度はどう設計するか考えんといかんからこれはこれで大変 >>272 finallyでcloseするとネストが深くなって可読性が落ちるし、し忘れることもあるからauto_closeにしたほうがええで try { } catch() { } finally { if () { try { } catch() { } } } これはもうルーチンワークだわ closeまで書いてから対象となるインスタンス生成してるぐらいだ try(){} をベースにしようか迷ったけど めんどくさい方を先に覚えて間違えずに書けるようにしたほうがいい 簡略化が導入されるまでみんな書いてたものだしね スッキリわかるSQL入門 第2版 ドリル222問付き! (スッキリシリーズ)2018/11/30 中山清喬、 飯田理恵子 新しい版がでるそうなのであと3週間ほど待つ事にしよう 実践編どくはああああああああああああああああ 寄り道したくなってきたぞ 「独学プログラマー」 という本をテキストとして使う IDLEというPython付属のIDEをテキストでは使っているのだが PyCharmで普通にpyファイルを新規作成してコード書いて実行した場合と微妙に違うようだ もしかしてーと思いつつ、左下のほうの「Pythonコンソール」とやらのタブを押してみたら それっぽいのが出てきたので、コードを打ち込んでみたら正解だ IDLEをここで使えるようだ なかなか便利である ちなみにプロジェクトの削除はPyCharm上でやるのではなく 作成されているプロジェクトフォルダをエクスプローラ上から削除してから PyCharmを再起動すれば消えている print(3 ** 300) 136891479058588375991326027382088315966463695625337436471480190078368997177499076593800206155688941388250484440597994042813512732765695774566001 プロセスは終了コード 0 で完了しました おお・・・・ こういうでかい数字はjavaだと扱ったことないからわからんのだけど 難しいんではないのか すごいとおもたぞ この対話シェルとやらは、簡単なチェックのために使うのはよさそうだが いろいろと学習上誤解を招きそうな機能だな 多言語やってきたおれは、2と打ち込んで実行すると2が表示されることに違和感を感じることができるが 全くの初心者はそれが当たり前だと思っちゃうよな いや、ある意味学習が捗る部分もあるのだけれども 論理演算子はVBAと同じか and or not if 文は条件はカッコなしで文末にコロン : ヘッダーとスイート 対話シェルじゃなくてpyの方に書いていくことにしているのだが def ppp(a, b): return a + b print(ppp(2, 5)) こういうの書くと関数のあとは2行は空けろとか言ってくる Pythonは空行とかタブとか五月蠅いのな うわ、行空けすぎるとおこられるw あと、関数に渡す引数のデフォルト値設定で def ppp(n = 1): ってやったらスペースいれるなって怒られる def ppp(n=1) にしろだと なるほどねー 1/3ぐらい読んでみたけど、 Pythonはわかりやすい、悪く言えばいい加減な感じ 今日は終わり! 今日はhtmlの基礎 テキストは 「これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん」 ここに書いてあるHTMLやらCSSの簡単なコードをとりあえず ぱぱぱぱぱぱっと書けるようにしていく やったことないわけではないんだけど、 JavaScriptやその先のJavaにつなげるために もう少し記憶を堅いものにしておく ふぁ〜い HTMLもCSSも、「覚える」ってことをしたことがなかったので新鮮 ぴっちぴちです 今日は用事あるのでここまで >>290 pythonはインデントでスコープを決めるからね でも文中の空白は問題なかったはずやが 個人的にpythonはあんま好きやないな 科学技術計算や深層学習の分野では強いけどアプリ作るとなるとピンとこん ワイはjavaでデータベース使ってウェブサイト制作なんかは一通りできるようになったっから、Androidアプリ作るためKotlin勉強しとる でもワイのノーパソでAndroidStadioのエミュレータ動かすと重すぎて作業できん 新しいPC欲しいで マルチモニタのデスクトップでシコシコ書いてるわ ブラウザでググりながらが基本なんで ノーパンは厳しいな モニタもっとでかいのに取り替えようかとも思ってるぐらいだ web系のプログラミング始めると レンタル鯖とか興味湧いてくる 無料もあるけど@500円/月でよさそうなの借りられるし HTML・CSSのテキスト テキスト通りの流れでVSCodeにカキカキ しっかり覚えたわけじゃないけど、難易度は低いので 大体なにができるのかざっくり理解出来ていれば あとはググったりして再現できそう 正直いうとこれつまんねぇのな HTML/CSSの部分は一通り流したので JavaScriptの部分をこれまた流し読みをしてみた Javaで基本やってると大した事ないのな 匿名クラスのような使い方も出てきてるし JFrameでやってたEvent処理の知識が生きそう JavaScriptは一時期Javaと近い所にいたようで、似た部分が多くて勉強しやすそうだ Javaの将来性があれなんで、C#の本も買ってある どちらかに限定しないで両方やればいいじゃんってゆる〜く考えてる C#はwidowsアプリに強そうなんで、軽く何か作れるレベルまでやってみたい んでJavaと比べてみたい C#はVSCodeでも開発できるんだけど この際Visula Studio 2017 Communityを入れる事にしよう オプションでインスコできるものがいくつかあるんだけど 全部チェック付けたら20GB越えるみたいだ SSDの容量食いそうだけどまぁいいか 「独習C#新版」 ちょいと読んでるんだけど Javaとやたら似てるな namespaceというのは初めてだけど packageみたいなもんかこれ ●Java System.out.println("hello," + name); ●C# Console.WriteLine("hello, {0}", name); プレースホルダー使うところがC系っぽい感じする Cでもそんなことやってたような(忘れたけど でもJavaでも位置揃えのために実践編でやったな オブジェクト指向を勉強するのにJavaは適当で 特にスッキリシリーズは初学者にぴったりと聞いたんで使ってたんだけど その通りだな このC#のテキストは初学者にとっては厳しいんじゃないか 少なくともスッキリの系統だった教え方と比べると難易度高そう 最初から詰め込みすぎてる 逆に基本がわかってる多言語経験者にはよさそう C#が初心者にとって向いてる点は、 ざっとみた限りではどの参考書もVisualStudio Communityの導入と 使い方を紹介して、これを使って学習を進めてるところだな スッキリでは統合環境の説明が薄いせいで自分でeclipseの使い方を調べないといけなかった 初心者であっても統合環境がないと、試行錯誤するのに不便すぎる VisualStudioはビルドすると勝手にexeが実行されてコマンドプロンプトが立ち上がる プログラミングは最終的な実行ファイルを目にしないとやった感じがしない そういう点でもいい windowsユーザーにとってはやはりマイクロソフト製品は親和性が高く感じる C#はJavaとCを足して二で割ったような言語だそうだ 三項演算子とか出てくると、はるか昔にすこしだけCをいじった時の記憶が戻ってくる Javaっぽいんだけど、Cの話がちょくちょく入ってくる どちらも多少やったことがあるおれにはぴったりなのかもしれない 独習の3章まで読んだ 全くの初心者ではないんだけど、内容が重めだから復習しないとすぐに知識が抜けそう スッキリでいえば入門編と実践編が合体してるような感じだ C#はメインメソッドは Main と書かないとダメなんだな Javaみたいな main だとダメ あと、文字列比較では Javaと違って == を使う public static void main(String[] args) public static void Main(string[] args) 微妙に違うのはやめて欲しいわ 👀 Rock54: Caution(BBR-MD5:1341adc37120578f18dba9451e6c8c3b) 独習C#、1/4ぐらい読んだ 読んだとか言っても頭に入ってなかったら意味ないんで 今の5章終わったらもう一度最初から読み直すか 忘れちゃってる部分が多すぎると行き詰まる >>53 の最短一致のことも書かれてるな 網羅性が高いな、このテキストは。 しかし文字列操作分野は重い Javaでも重かったが独習C#はさらに重い Javaやってなかったら挫折コースまっしぐらだ コレクションまだやってないのに出てくるし まさかのラムダ式まで出てくるし ふむむ VisualStudio で Ctrl+F5 で実行したあと、 コマンドプロンプトを閉じると、フォーカスが出力ウィンドウに移ってしまう コードエディタに戻ってコードの編集を続けたいのだが マウスを使って戻すのがめんどくさい ctrl+tab でコードエディタに戻る事ができる 机の上にキーボードおいてカチャカチャやってると深夜だと結構うるさい タオルを下に置いたら劇的に音が小さくなった これはいい Javaでファイルやらstream系のクローズを自動化する書き方があったが C#も同様の方法がある 独習C#では最初からこの方法で教えている ●C# using () {} ●Java try () {} using (var writer = new StreamWriter(@"../../data.log")) {} で2つ上のフォルダにファイル作成 ドット2つ+/ で上のフォルダ ドット1つ+/ で現在のフォルダ ファイル操作の練習するわけだけど exeが作られているフォルダの階層が深いから exeよりちょい上の方にテスト用のファイルを作る事にする 文字コードはほんとやっかいだ ぐぐるとHTMLではUTF-8を使えと書いてある これが主流だと。 でもPC上のファイルを開くとSJISしかない この差は一体なんなんだ これはJavaでも遭遇した問題だ ちなみにSJISと判断したのは自分が使っているエディタで開くとそう表示されてるからだ さらにぐぐってwindowsのメモ帳での文字コードの扱いを調べる メモ帳では 「名前を付けて保存」 で文字コードを選択して保存ができるようになっている 選択肢にはSJISなどというものはない ANSIとやらで保存するのがデフォルトのようだ ANSI 日本語 Windows で ANSI と呼ばれているのは CP932 であり、 これは Shift_JIS が拡張されたもの https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1490895514 SJIS シフトJISコードは、SJISとも呼び、Microsoft社が決めたコードで Windows95やMS-DOSやMacなどで使用されています。 http://ash.jp/code/code.htm ざっくり捉えると、ANSIもSJISもShift-JISということか ウェブ上ではUTF-8を使えといいつつローカルではShift-JISがデフォルトとは。 でもって、C#でもJavaでもUTF-8が標準的な扱いとなっている そのためローカルのテキストファイルを実験台として開くと、文字化けの問題が生じる 文字化け回避手段はこんなところか メモ帳の別名保存によりUTF-8を選択すると 自分の使っているエディタで開いた時にりUTF-8と表示されている このテキストに日本語を書き込んでから、C#のStreamReaderで開いてみると文字化けしない もしくは、StreamReaderのインスタンス生成時コンストラクタに Encording.GetEndording("SJIS") を渡すと文字化けしない StreamWriter に Encording.GetEndording("UTF-8") を渡して作ったファイルを使ってもおk その他 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11160634546 日本語 Windows 9x 系列は、システム内部、DOS プロンプト、 ファイルシステム(FAT16/FAT32)などがほぼ CP932 で統一されていました。 対して、Windows 10/8/8.1/7/Vista/XP/2000 などの 現在主流になっている Windows NT 系列は、ちょっと話が複雑になります。 まず、OS のシステム内部は Unicode UTF-16 に統一されました。 DOS プロンプトは廃されましたが、代わりに搭載されたコマンドプロンプトは、 未だ CP932 を標準で使います(切り替えは可能)。 ファイルシステム(NTFS)も Unicode UTF-16 を使うようになりましたが、 FAT32 は使用可能であり(この場合ファイル名は CP932 になる)、 またファイル内容は CP932 だったり Unicode UTF-8 BOM有りだったり Unicode UTF-16 だったりします。 https://laboradian.com/char-encoding/ Shift_JIS Windows の「メモ帳」で何か文章を書いてそのまま保存すると、 文字エンコーディングは「Shift_JIS」になり(厳密には CP932)、 改行コードは「CR + LF」になります。 UTF-8 Unicodeという文字コードを使って、文字を表現する方式の1つです。 現在(2017年)、ウェブサイトの多くは「UTF-8」を使っています。 Shift_JIS では、英語・日本語以外の文字を使うことができませんが、 UTF-8 であれば様々な言語の文字を一緒に使うことができます。 × encording ○ encoding コードの補完機能であるインテリセンス(マイクロソフトの造語か) 頼りっきりになっているとスペル間違えて覚えてたりするんでよくない eclipseにも補完機能あったけど、わざと手打ちしてた C#でもそうした方がよさそうだわ 英単語思い出すきっかけにもなるし ファイル操作で、テキストファイルの読み込みやってるんだけど Javaみたいに FileReader fr = new FileReader("test.txt", FileMode.Open); StreamReader sr = new StreamReader(fr); でもいけるし StreamReader sr = new StreamReader("test.txt"); でもいけちゃう Encoding.GetEncoding("SJIS") はどちらのケースも StreamReader に渡す C# は、こういう方法もOKだし、ああいう方法もOKだよってのが多いような >>315 間違えた 修正 FileReader fr = new FileReader("test.txt", FileMode.Open); ↓ FileStream fs = new FileStream("test.txt", FileMode.Open); >>257 と同じで、Writer/Reader が入ると文字ストリームかな FileStream はバイトストリーム NetworkStream MemoryStream もバイトストリーム Console.WriteLineに渡す文字列だけど 変数混じりの場合、Javaと同じような記述方法でもいけるんだな string st = "あああ"; Console.WriteLine(st + "と叫んだ"); みたいな感じ こんな風↓しかダメと思ってた Console.WriteLine(@"{st}と叫んだ"); Console.WriteLine(Math.Pow(3, 300)); 結果 1.36891479058588E+143 >>285 と比較すると、しょぼ! 1/3読んだけど このまま先に進んでもスッカスカな知識になるんで 復習に入るか 覚えないといけない量はスッキリ1冊分ぐらいありそう >>318 そりゃMath.powの戻り値はdouble型やからな javaだとlong型の最大値を超える計算はBigInteger型使ってnew BigInteger("3").pow(300)で可能やけど、C#でも似た感じでできるんとちゃう? 一見するとPythonの方が便利に思えるけど、どのくらいメモリを食うかわからんちゅうことやから、システム開発なんかには不向きなんやな テキストのちょい先でBigIntegerはやったけどね そもそも目的というか得意としてる分野がハッキリしてるというのがいい 言語ごとに特徴が明確なら選択しやすい intの範囲ぐらい正確に覚えても罰は当たらないだろう まいなすにじゅういちおくよんせんななひゃくよんじゅうはちまんさんぜんろっぴゃくよんじゅうはち〜(絶対値1つ小さいプラス値) -21 4748 3648 +21 4748 3647 テキストにいろいろ書込みながら きちんと復習してる 今日はおしまい int i = 128; Console.WriteLine((sbyte)i); 結果:-128 これの説明で 「残りのビットを反転させる」 なんていう説明が出てくる この辺を数学的にしっかり学んだ人はなんてことはないんだけど、 そうでないと不思議な感じがする 突然おもちゃを扱うような雑な操作が唐突にあらわれたような印象を受ける 127 (10) 01111111 (2) 127 (sbyte) 128 (10) 10000000 (2) -128 (sbyte) 8bitで表した2進数の最初のビットは符号を表現するために使われる これが 1 になったら、つまり10進数で言えば 127 から 128 になった時、 残りのビットを反転させてから、10進数にして 1 を加えてマイナス記号つければ sbyte にキャストした値になるというものだ 10000000 の最初の 1 を除いた7つの 0 、0000000 を反転させると 1111111 となる これは10進数でいうと 127 で 1 加えてマイナスを付けると -128 10000000 ↓ 0000000 ↓ 1111111 ↓ 127 ↓ -128 この気持ち悪い唐突感を取り除くためにぼけぇと考えてたんだけど これは2進数を持ち出さないでも10進数の範疇で自然なイメージを持てるのではないかと そういう結論に至った つまり、10進数で桁が変る瞬間、例えば 99 100 のような場合 上と同じような変遷を書くことができる 100 ↓ 00 ↓ ←ここが「反転」の操作を10進数で表現したもの 99 ↓ 99 ↓ -100 反転とは補数の関係を使った変換なのでこれでいいだろう 数直線で考えたとき、0 から順にたどっていって 100 になった瞬間に、 ぽ〜んと 0 を挟んで真反対の側に飛ばされる感じがわかる 101 を同じように考えると 101 ↓ 01 ↓ 98 ↓ 98 ↓ -99 なるほどと 2進数というスイッチカチャカチャの世界を、人が常用する10進数に重ねていくこの作業は見事だ コンピュータが作られていく過程で試行錯誤を重ねてこういうものを作ってきた人たちがいたんだなと まだテキストで勉強してない分野をJavaと同じように書いてどこまでいけるか試してた コンストラクタ付きのクラス作って、インスタンス化したり。 同じソースファイル内に定義したクラスをインスタンス化する場合であっても コンストラクタにpublicがついてないとエラーがでるのな この辺Javaより厳しい Java 文字列の長さを求めるには String.length() 配列の長さを求めるには 配列.length C# 文字列の長さを求めるには String.Length 配列の長さを求めるには 配列.Length () がついてりゃメソッドね、で終わるんだけどね C#だとメンバの1つにプロパティというものがあって セッターゲッター的な役割を担うようなことが書いてあった どうやらC#の Length はこれっぽい https://docs.microsoft.com/ja-jp/dotnet/api/system.string.length?view=netframework-4.7.2#System_String_Length Javaの配列の length はもっとわかりにくそうなんで放置^^ string st1; string st2; st2 = st1 + "あああ";//未割り当てのローカル変数'st1'が使用されました。 string st1 = null; string st2; st2 = st1 + "あああ";//OK! string st1; string st2; st2 = null + "あああ";//OK! 中身がnullだからどうのこうのの話でもないようだ とにかく初期化されてないものを使うなみたいな? st2みたいに代入される変数が初期化されてないならまぁいいやとか 独習C#80ページのコードを書いていて気づいたわけなんだけど テキスト上ではstringの初期化として "" を使っている var st = ""; string st = ""; みたいな感じで。 一応初期化は必ずやれと35ページに書いてある Console.WriteLine(Math.Floor((0.7 + 0.1) * 10));// 7 ダメ double num2 = (0.7 + 0.1) * 10; Console.WriteLine(num2.ToString("G16"));// 7.999999999999999 Console.WriteLine(Math.Floor((0.7 + 0.2) * 10));// 9 OK! double num1 = (0.7 + 0.2) * 10; Console.WriteLine(num1.ToString("G16"));// 9 浮動小数点数に計算誤差がでちゃう例なんだけど 出る場合と出ない場合を予め区別して把握するのは難しそうだ //正の小数・正の整数を2進数に変換 using System; using System.Text; using System.Text.RegularExpressions; public class Program { public static void Main(string[] args) { const int Digit = 16; string input = Console.ReadLine(); Regex rgx = new Regex(@"^([1-9]\d*|0)(.\d+)?$"); double num = 0; if (rgx.IsMatch(input)) { num = Double.Parse(input); var num1 = Math.Floor(num); var num2 = num - num1; string num1_byte = Convert.ToString((int)num1, 2); double a1 = 0; StringBuilder sb = new StringBuilder(); sb.Append(num1_byte); sb.Append("."); for (var i = 0; i < Digit; i++) { a1 = num2 * 2; a1 = Math.Floor(a1); sb.Append(a1.ToString()); if (a1 >= 0) { num2 = num2 * 2 - a1; } else { num2 = num2 * 2; } } Console.WriteLine(sb.ToString()); } else { Console.WriteLine("適正な数値ではありません"); } } } いちいち紙に書いて計算してたけど あほらしくなって自分で作ってみた 正規表現だけはコピペしてズル 小数部分の桁数は定数で指定 対象となる10進数はキーボードからの入力 独習の「同一性(Identity)」=スッキリの「等値(equality)」 →同じオブジェクトを参照、つまり完全一致(==) 独習の「同値性(Equivalence)」=スッキリの「等価(equivalent)」 →オブジェクトが同じ値をもっていれば十分(equals) この辺業界で統一した用語使って欲しいもんだ どちらかというと、独習の用語の方が直感的で「スッキリ」してる感じする >>337 は 独習88ページ スッキリ実践編115ページ Equals の s は三単現の s で SequenceEqual に s がついてないのは配列という複数要素の一致を要求してるからなのかとか ぼけぇ〜と考えてたが でもSequence自体は単数だよなとか まぁいいや bool? b = true; if (b) {} というのはダメみたいだ if 文の条件式は bool でないとだめ bool? はダメ @ null条件演算子(P.64) 非nullのときだけメンバにアクセス string unspace = str?.Trim(); A null合体演算子(P.92) nullの時のデフォルト値を与える Console.WriteLine(num ?? 100); B 論理積のショートカット演算(P95) 非nullのときだけメソッドにアクセス if (str != null && str.StartsWith("http://" ;) { } nullを予見したいろんな手法 Bの時に@を使えないか考えてみたんだけど 条件式に str?.StartsWith() を置いてしまうと、ここが bool? つまりnull許容型の bool と判定されてしまう if文の条件式に bool? は使えないようなのでエラーが出てしまう null がきちゃうと判断出来なくなっちゃうから仕方ないのか Bは大事なんじゃないかと思ってる VBAのプログラム組んでたときに論理積・論理和系の条件式でよくわからないエラーがでてたのは これじゃないかと、今思えばだけど。 当時は null を放置しておくと条件式でエラー出ちゃいがちだということを経験からわかってたんで とりあえず適当な値入れて回避してたんだけど。 >>324 >>325 これ>>335 でぽちぽちやりながら このへんをさらに掘り下げてたんだけど 根本的な部分が理解できた 一つ一つの処理であったりルールは理解できるんだけど なんだかもやもやがついて回る 複数の疑問点が浮かび上がるんだけど、最終的に集約されていくのはこの疑問 Q.「なぜ負の数を表すのにわざわざ補数を使うのか」 言ってることはわかるけど、そもそもなんでこんなことしてんの的な疑問というのは どこが謎の源泉になっているのか、自分の思考を分析するのがやっかいだ 自分なりにたどり着いた答えがこれ A.「コンピュータは引き算をしたくないから」 もっというと A.「スイッチON/OFFの世界だけで計算したいから」 細かく経緯を説明し始めると長くなるんだけど、 ビット演算やらこの辺の分野全てにわたる話なんだと思う 補数が関係してくるのはbit演算のうち否定演算 では、 & 論理積 | 論理和 これらはどう使われるのか まだ学んでいないので想像でしかないんだけど、例えばこんな感じなのか 絵がいくつかあって A,B,Cと名前を付けるとする これらの絵は4色の絵の具(赤・青・緑・黒)を使って描かれているのだが 全ての色を使っているわけではない どの色を使っているかによって場合分けして処理していきたい このような処理をするときに、ある工夫をしてみる まず色ごとに特定の2進数を割り当てる(()内は10進数) int r = 0b0001; //赤(1) int g = 0b0010; //緑(2) int b = 0b0100; //青(4) int w = 0b1000; //白(8) 見て分かるように1をずらしただけのものだ スイッチのように考える 一番右のスイッチがONのものは赤、みたいな感じ そして絵A・B・Cについても2進数で表現する このとき、それぞれの絵がどの色を使っているかによってスイッチON/OFFを切り替える int artA = 0b0011; //A(3) 緑と赤を使用 int artB = 0b1001; //B(9) 白と赤を使用 int artC = 0b1111; //C(15) 全色使用 前提はここまでで、具体的にこれらをどうつかっていくかを説明(想像)する 例えば、絵Aが赤の絵の具を使っているかどうかによって条件分岐させたいならこうする if ((artA & r) == 0b0001) { } 絵Aと絵Bで使っている色を全部列挙したいなら int result = artA | artB; としてから result について分析すれば分かるだろう 分析方法を想像すると・・・ if ((result & w) == w) { } //白を使っている みたいな感じか 似たようなことがTCP/IPの本を読んだときも書いてあったような気がする 結局、スイッチ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つ目の方法を使っている >>444 の3通りについてはちゃんとやろうと思う 特に入門本は3つ目の方法でGraphicsを取得しているんだけど 入門本ではImageではなくBitmapを使っている この辺の違いも明確にしていきたい ちなみにImageは抽象クラスなのでnewできないが Bitmapは抽象クラスではないのでnewできる 入門本で玉が跳ね返りながら動くコードを学んだので 高速で跳ね返って動く玉をクリックして捕まえるゲームを作った クリックのアタリ判定はクリック座標と玉の中心座標の距離を求めてこれが玉の半径以内ならアタリ イライラするだけのゲームになった JavaでグローバルIPアドレスを毎日記録するアプリを作って これをタスクスケジューラに登録してあるんだけど、何日か経つと勝手に無効化してしまう これは一体何が原因なのか いろいろ調べてみたんだがイマイチわからない とりあえず正常に動いているタスクの設定を真似して設定を見直してみた これで動くといいのだが 自分で作ったJavaのプログラムが常時起動しているせいで タスク実行時にすでに実行中だと判断されてしまっているとか・・・? JavaでグローバルIPアドレスを記録するアプリをつくって これを毎日起動するようにタスクスケジューラに登録してあるんだけど* 使っているwindowsアプリの入門本は 「作って覚えるVisualC#2017」 なんだけど、VisualStudioの基本操作が紹介されてるという点 どういう流れでアプリをつくっていくのかが分かるという点 この辺がいい 学習の通過点としてこういうテキストは必要だと思う ただ、このテキスト通りに作っていくと次第に分かっていくんだけど 背後で自動生成されている膨大な量のコードがあるという事 結局これが理解できてないと応用が利かなくなるという点に気づかされる もちろん俺はまだ一部しか理解できない、というか一部しか見てない 「プログラミング経験ゼロでもしっかりわかる」と銘を打っているんだけど さすがにこれは言い過ぎ感が否定できない アマゾンのレビューをみると、誤植を指摘している人がいる 正確にどのページのどの部分かと指摘してるわけではないのだが、 大文字と小文字を間違えてるとかうんぬん おれはまだ全て読み終えたわけではないが、 ここのことを言っているのではないかと思い当たる部分に出くわした 結論から言うと、誤植ではないと思う あるフォーム@のボタンを押すことで別のフォームAを一時的に立ち上げるという機能を考える Aは利用後すぐに閉じられるが、必要な時に何度も立ち上げることになる このときにAで使うデータを@で作って置いて、 Aを立ち上げるたびに引数を使って渡していきたい ここで、Aを立ち上げるとは、コード上ではインスタンスを生成することになる Aクラスのコンストラクタに引数を渡してAインスタンスを生成するのだ ここで引数がintやstringなら簡単なのだが、 引数自体も自作クラス(CategoryDataSet)のインスタンスなのだ @の側で引数となるインスタンス内にデータを入れてから、インスタンスごとAに渡す流れなのだ こうなると 1.@の側で生成する実引数となるインスタンス(categoryDataSet1) 2.Aのコンストラクタでの仮引数(dsCategory) という2つの変数が登場する これだけでも初心者は混乱する さらにだ、Aの側ではdsCategoryとは別に、同じ型の空の変数を用意して、これと dsCategoryをMergeするという手法を使っている(401ページList2) この変数が 3.Aの側で用意してある変数(categoryDataSet) つまりだ、 クラス名CategoryDataSet @の変数categoryDataSet1 Aの変数categoryDataSet この3つがごっちゃごちゃになって、別々のものだと理解できず、その結果、 誤植だろこれ!となったのではないかと思う 独習なみにしっかりとした説明があればいいんだけど、背後に生成されるコードについては ほとんど説明はなく、変数categoryDataSetに至っては、俺の見落としがなければなんだけど、 テキスト内に唐突に出現しているのだ この変数は、背後で自動生成されているFormItem.Designer.cs内の InitializeComponentメソッドでnewされているのだが、そんなことに触れようものなら パンドラの箱をあけるようなもので収拾が付かなくなる 仕方なかったのだろう・・・・・ DataGridViewとDataSet、DataTableの関連についていろいろ調べてた 一体どれがどういう目的で使われているのかとか なんとなく分かった 引き続き入門本(作って覚えるVisual C#)を読んでるんだけど DataTableに格納されたデータを取得してこれをcsvファイルに書き込むという場面で こういうコードがテキスト内に書かれている foreach (MoneyDataSet.moneyDataTableRow drMoney in moneyDataSet.moneyDataTable) 唐突になにやら面妖なコードが出現 foreachに続く丸括弧内のコードなのだが 普通ここに書くコードの内容を考えると、こう推測できる @「moneyDataSet.moneyDataTable」 というコレクション(or配列)があって、 A「MoneyDataSet.moneyDataTableRow」 という型の要素が入っている DataSetはエクセルでいうブック DataTableはエクセルでいうワークシート ということらしいので、ワークシートの中の行をコレクションの要素をして扱っているようなイメージか これぐらいで納得できればいいのだが、じゃ実際にこういう機能、 つまりDataTable内に格納されたデータを取り出す場合に 具体的にどういうコードを書けばいいのかを考えると、この程度の理解では書けないのではないかと思う そこで、ひとまず@、Aは一体何なのかを実際のコードから読み取ってみよう、と思ったわけだ が、見事に打ち砕かれた @「moneyDataSet.moneyDataTable」 moneyDataTableがコレクションまたは配列ということであれば、どこかでそういった宣言が なされているはずだと考えた。もちろん自分でそういったコードを書いた覚えはないので 自動生成されているコードがあるのだろう そこで、moneyDataTableにカーソルを合わせ右クリ→定義へ移動 するとMoneyDataSetDesigner.cs(これをデザイナと言うそうだ)内に移動する MoneyDataSetクラスのプロパティとしてmoneyDataTableが定義されているようだ public moneyDataTableDataTable moneyDataTable { get { return this.tablemoneyDataTable; } } これによるとmoneyDataTableを取得すると同じクラス内の変数tablemoneyDataTableが かえされると・・・もうここでギブアップしたくなるが先に進む つまり、moneyDataTableはtablemoneyDataTableのゲッターのようなもんで moneyDataTableの正体はtablemoneyDataTableという認識でいいのか いや、ゲッターならスペルは同じにして頭文字の大文字小文字変えるだけにしてくれとか そういうのはなしなんだろうな・・・ 取り合えずそういうことみたいなんで、tablemoneyDataTableを同様に右クリ→定義へ移動 すると同じクラス内のここに移動する private moneyDataTableDataTable tablemoneyDataTable; 「moneyDataTableDataTable」というクラスの変数として宣言されている この辺のクラス名や変数名をみてると頭が痛くなってくる moneyDataTableDataTableを右クリ→定義へ移動 public partial class moneyDataTableDataTable : global::System.Data.TypedTableBase<moneyDataTableRow> ふぅ・・・もうやめたほうがいいのか・・・ これはよくみると同じMoneyDataSetクラスの内部に設けられたインナークラスのようだ TypedTableBaseクラスを継承している わからん! が、このクラスの中をずっと見ていくと、これか・・・と思い当たるメソッドを発見 public moneyDataTableRow this[int index] { get { return ((moneyDataTableRow)(this.Rows[index])); } } 独習を復習し直さないとこれは理解できない インデクサーを使っているんだよねこれ 独習441ページのコードと類似点が多い この辺からコレクション的な何かを「感じる」 これぐらいにしておこうか・・・ 俺の実力だとこれ以上やっても理解するまでにメリット以上の時間がかかりそうだ それより独習をちゃんと復習してもう少しコードを読解する能力を身につけた方がよさそう https://ohke.hateblo.jp/entry/2016/12/03/231909 >・DataSet、DataTable、DataColumn、DataRowを継承したクラスを使う >・プロパティを介してDataTable、DataColumn、DataRowの値へアクセスできる デザイナを使った、つまり自動生成されたコードの特徴だそうだ 継承とプロパティを介したアクセス 知識ある人には便利なんだろうが、おれにとってはこの2つが理解を拒む壁となってそびえ立つ DataSet関連のコードはデザイナを使わなくても組めるので 分からなかったら自分で一から書いていった方が良いのかもしれない そう思って基礎的なコードをいくつか書いてDataGridViewで表示させてみた この辺はこれぐらいでいいかと思う 続けていけばそのうち分かることもあるだろう >>452 の最後のコードはメソッドではなく、まさにインデクサーそのものか (再掲) public moneyDataTableRow this[int index] { get { return ((moneyDataTableRow)(this.Rows[index])); } } 今、独習のインデクサーのところを見直しているんだけど、 インデクサーはぶっちゃけて言えばインスタンスの配列化をするための技法 つまり、moneyDataTableDataTableクラスのインスタンスを配列化しているといえる そして、moneyDataTableDataTableクラスのインスタンスがtablemoneyDataTable で、こいつをそのまま戻り値として返しているのがmoneyDataTableプロパティ >>451 @「moneyDataSet.moneyDataTable」は MoneyDataSetクラスのインスタンスmoneyDataSetのプロパティmoneyDataTableであり これにより上に書いたような流れで、最終的には moneyDataTableDataTableクラスの配列化されたインスタンスを意味することになる この配列の要素となっているのが ((moneyDataTableRow)(this.Rows[index])) であり 簡単にいえば Rows[ ] の要素となるのだろう Rowsにカーソルを合わせると DataTable.Rows このテーブルに属している行のコレクションを取得します と出てくる。継承元となっているDataTableがここででてくるわけだ そしてついに、コレクションという言葉にたどり着いた 道が険しく長すぎる これでいいだろと言いつつ、調べた結果なんとなく分かった気がしてきた (配列配列といっているが実際にはインデクサーによる配列的ななにかで実際に配列と行って良いのかは知らない) 独習読んでると、いや、こんなの使わないだろ〜 少なくとも自分では使わないよ、とか思うところが結構あるんだけど デザイナ使った場合、デザイナで自動生成されたコードから 何かを取得して自分のコードで使いたいと思った時、 つまり上に書いたような場合なんだけど、 こういうときに自動生成されたコードが理解できてないと全くコードを書けない とするとやはり独習レベルの知識は頭に入れておかないとダメなんだろう 道は長いぞ! テキストボックスをデザイナでForm1上に置くことにより自動生成されるコード テキストボックスのNameプロパティをmyTextBoxとした 特に大事なのはmyTextBoxがTextBoxクラスのインスタンス変数名として「も」利用されているという点。 private System.Windows.Forms.TextBox myTextBox; //↑Nameへの代入値がそのままインスタンス変数名としても使われる // // myTextBox // this.myTextBox.Location = new System.Drawing.Point(13, 13); this.myTextBox.Name = "myTextBox"; this.myTextBox.Size = new System.Drawing.Size(100, 19); this.myTextBox.TabIndex = 0; // // Form1 // this.Controls.Add(this.myTextBox); StreamReaderを使う時、一行ずつ読み込むとして whileの繰り返し条件として使う部分 StreamReader sr = new StreamReader(path); @while (sr.EndOfStream) { } Awhile (sr.Peek() >= 0) { } Bwhile (sr.ReadeLine != null) { } @、Aは正解 Aは少し古い方法で次に読み込む文字のint型整数値(Char型の中身)を返す 読み込む文字がないと「-1」を返すので、0 以上で有る限り、という条件にする @のEndOfStreamがプロパティであるのに対してPeekはメソッドなので丸括弧忘れないこと Bはダメ 読み込む行がないとReadLineがnullを返す事を利用しようとしたものだが、これはダメ。 理由は、ReadLineは単純にチェックのために使いたかったのだが、 実際にここで使ってしまうと、読み込み済として一行進めてしまい、 whileブロックの中で読もうと思っていた行を先取りしてしまう エラーが出るわけではないが使えない 別途変数を用意して使う方法も考えられるが、そこまでしなくても@、Aがあるので・・・ >>451 @「moneyDataSet.moneyDataTable」関連のコードの位置 【moneyDataSet】はForm1.Designer.csで宣言されるインスタンス private MoneyDataSet moneyDataSet; ↓ 【moneyDataTable】はMoneyDataSet.Designer.cs(以下同じ)、MoneyDataSetクラスのプロパティ public moneyDataTableDataTable moneyDataTable { get { return this.tablemoneyDataTable; } } ↓ 【tablemoneyDataTable】MoneyDataSetクラスのフィールド private moneyDataTableDataTable tablemoneyDataTable; ↓ 【moneyDataTableDataTable】MoneyDataSetクラスのインナークラス public partial class moneyDataTableDataTable : global::System.Data.TypedTableBase<moneyDataTableRow> { } ↑のインデクサー↓ public moneyDataTableRow this[int index] { get { return ((moneyDataTableRow)(this.Rows[index])); } } A「MoneyDataSet.moneyDataTableRow」関連のコードの位置 【MoneyDataSet】MoneyDataSet.Designer.csの中のクラス public partial class MoneyDataSet : global::System.Data.DataSet { } ↓ 【moneyDataTableRow】↑のインナークラス public partial class moneyDataTableRow : global::System.Data.DataRow { } 頼まれたんでVBAやってるんだけど VBAでも普通に正規表現使えたのか 知らなかったわ IEがらみのライブラリかなんか使うみたいだけど C#で正規表現結構やったんで役に立った VBAに没頭 自分が作ったものじゃないんだけど、あるwebアプリがある 現在ブラウザに表示してる特定のデータをCSVで吐き出す機能を持っている このCSVからデータをエクセルに取り込んで加工するということをやってる ただ、 大したデータ量ではないのに、CSVを作らせるのに1分ぐらいかかったりして結構とろい ローカルで作成するんじゃなくて、鯖に作らせているようだ そこで、IEによってローカルに取込み済のHTMLを横取りして加工できないかと。 つまり、HTMLスクレイピングをVBAでできないかと思って ボトルネックになりそうな部分をちょっと触ってみたんだけど、 意外といけそうなんだよなぁ とりあえず、CSVを使うバージョンを作ってから 暇な時にHTMLスクレイピングやってみようかな メソッドたくさん作ってからどれ使うかあとから決めると頭が整理できていいな 以前はひとつのメソッドを作り込んでたんっだけど これをやってしまうと、別のメソッドとして切り出した方が いい機能まで突っ込んでしまって融通が利かなくなる ちょっとした機能でもどんどん独立させて作る 同じ機能でも少し違うやつが考えられるなら、全部作ってみる 作ってからどれ使うか選びながら組み立てていく あと、Functionを作ったら、すぐ下にテストのためのメソッドを作っておくと何かと便利 あと、複雑なロジックは紙にシャーペンで書く 絵や図を書き加えながら、コードを書いていく 消しゴムも必須 やっぱ深く考えるにはアナログが一番いい HTMLスクレイピングというかウェブスクレイピングをVBAでやってるんだけど Dictionaryないかなと思って調べたら、一応使えるようだ しかし、使ってみたら、ソートの機能すらない 仕方ないので自分で書いてたんだけど、どうもうまく動かない この原因探しが大変だった 結論から言えば、forのカウンタの部分で最大値を指定するわけだけど ここに同じforブロックのなかで変化してしまう変数を使ってしまっていた 繰り返し処理の途中で予期せず最大値が変化してしまい、エラーに繋がっていたのだ VBAのDictionaryで使うソートの機能をネットで調べると、いろいろと洗練されたコードが出てくる こぴぺの誘惑にかられたのだが、無骨なコードになってしまうとは言えども この程度自分で書けないのも悔しくて、、あー疲れた 列挙体初めて実戦で使ってみた これ便利だな 要はbool系は2つしか選択肢ないけど これをいくつも増やした感じか switchというかvbaだとselectなんだけど これにも列挙体使えるし 正規表現をまともに使えるようになるとグンと幅が広がるわぁ 戻り値のないFunctionはSubとどう違うのだろうか ふぅ大体終わったぜ・・・・ 今回のVBAプログラムは処理が重くて表示が固まるのが特徴のひとつだった これをどうやって軽くしていくかが課題 もっと速くなると思うけど、一応固まらないようにはなった C#に戻るとするか・・・とか言いながらVBAに足引っ張られそうだ 昔書いたコードみると書き直したくなるわ あまりに酷すぎる プログラミングばかりやってたらアジアカップ見るの忘れてたわ 次の試合から録画する このタイミングで決勝が日韓戦だと妙な盛り上がりを見せそうだ! 凄くがんばってるなぁ・・・頭の下がる思いでみてる。 独習最初から読み直してる コードかきかきしながら おれぐらいすぐ忘れる人間はこうでもしないとな >>473 ぐへへへへへ これからはクラスを作ったらドキュメンテーションコメントを使っていくことにする /// これ 時間がなくてちょびっとずつしか独習読めないが これでいいのだ いままでちゃんと覚えてこなかった基本的な事を読み返しながら覚えるようにしてる 例えば値型のサフィックスとか表になって紹介されてるようなやつ vbaでのIE操作に脱線してた これ面白そうなの作れそうなんだよなぁ null条件演算子 null許容型 三項演算子 null合体演算子 ? を使うこいつら if とか switch とかすごく基本的なもの復習した 基本とかいいつつ独習は細かい論点も触れるので忘れてるところもあった ん〜 いろいろ試しているがvbaからhtmlが取得できない いろんなもの作れるようになってきた IEコントロールおもろいな VBAだけど 今日もずっとVBAいじってた リンククリックしてウィンドウを閉じたり開いたりしてると いろいろエラーが出てくるんだよね 再現性の高いエラーならいんだけど、ネットと関わるエラーはそうじゃないものが多くてやっかい とりあえずはエラーがでないようなのを作ってみたんだけど 時間を置いて何度も繰り返さないと確信もてない なぜか時間を置いてからもう一度やるとエラーがおきてたんでその辺気をつけないといけない 新しいウィンドウをIEで開いた時なんかに 開ききる前にIEを捉えようとするとエラーが出る 見た目開いたように見えても読み込みが不十分だったりすることがあるから IEを掌握する処理をループで回すのがキモとなるようだ CStr と Str の違い Str()は、符号の1桁分が必ず確保されていて、 数値が正の時の戻り値の頭にはスペース(空白)が入ります。 Cstr()は、プラスのときにスペースは入りません。 これな・・・・これなんだよ やっと原因見つけたわ windows10だとIE使えないと思ってたんだけど 機能追加でInternet Explorer11が使えるのか 知らなかったわ ウェブアプリでIE使ってる場合はそのまま移行できるってことかな その辺勉強してないからわからんが ふ〜む EdgeをVBAから操作することもできるようだ でもWebDriverとやらをダウンロード・インストールしないといけない これができない環境だとやはり厳しいのかもしれない https://www.ka-net.org/blog/?p=6018 WebDriverを使わない方法もある https://www.ka-net.org/blog/?p=6033 しかし公式サポートないそうだ 最近VBAでプログラミングするときは public宣言をできるだけ避けるようにしてる Subプロシージャはメインとなるひとつだけにして あとはFunctionを使う 戻り値が欲しいときFunctionの戻り値を使えば良いんだけど 使い勝手が悪いときは、Subプロシージャ内で変数宣言してから これを参照渡しすることにしてる 昔は大量のPublic宣言された変数があって見通しが悪かったんだけど この方法に変えてからマシになった感じがする こういうやり方が正しいかどうかは知らないんだけど windowsのタイムスケジューラってなにが原因かよくわからんけど いつのまにか無効になってて一日一回設定してあるプログラム起動が 実行しないようになっちゃうのな 設定変えていろいろやってるんだけど、もういっそのことC#で常時起動の何か作って そこから実行するようにしようかな 常時起動のJavaプログラムもあるからそこからやってもいいんだけどせっかくだし 忙しくてなかなか再開できないわい また秋ぐらいから再開しようかなぁ その頃になれば時間ができるだろうから VBA漬け エラー処理までちゃんと作らないと気が済まなくて 暇な時間がVBAに吸い取られていくのだ 今期は正規表現が使えるようになったのが大きな収穫だった C#の独習で覚えたんだけどVBAでも使えるんで大活躍 今日はVBAの入力フォームを作らなくてはならぬ 入力フォームのテキストボックスに特殊なデータを貼り付けたいとおもって SendKeysってのが使ってみたんだけど、今のところうまくテキストボックスに入れることができない が、その代りに、VBEのコードのカーソルが当たったところに指定した文字列が入力されてるのに気づいた コードを操作出来ちゃうことになるんだけどどゆことよw 正規表現を使えるようになったとか書いたけど よくやってしまううっかりミスに気づいた しかも自分ではそう簡単に間違いだと気づけないやっかいなやつ アホみたいなミスなんだけど "\d" "\D" を "{\d}" "{\D}" と書いてしまう これまでにも何度もやってて、気づけなくて結局他の表現方法使ってたんじゃないかと思う ほんとにアホみたいなんだけどなぜか自分では気づけなかった 今回相当時間かけて悩んでようやく気づいたw たぶんだけど、 "\s" "\S" とかでも同じような事をやってたと思う まじで注意 今作ってる入力用フォームでエンターキー押したときにあるテキストボックスから別のコントロールに フォーカスが移るのを阻止したいと思っていた 別のコントロール全てにTabStop=Falseを設定すれば実現できるんだけど それだと別の問題が生じるので、できたら他の方法をとりたかった そこで、 対象となっているテキストボックスに MulitiLine = True EnterKeyBehavior = True を設定することで解決 このテキストボックスは一時的に入力を受け付けるだけの特別なものなので 表示される内容は問題にならないのでこれでOK ちなみに、EnterKeyBehaviorプロパティはTextBox内でエンターキーを押した時に 改行する機能を持たせるもの。(デフォルトだとTextBox内での改行はctrl+Enter) KeyDownのプロシージャを作って、 If KeyCode = vbKeyReturn Then 〜 を記述することでエンターキーの無効化を試みたんだけどこれは失敗だった Ifブロック自体は働くんだけど、おそらくそのあとに、フォーカスが移る機能が働いてしまうみたいだ フォーカスが移ったあとに戻す方法もやってみたけど、これは成功した しかし、フォーカスが移った先のコントロールに影響が波及するのでこれも避けたかった よって>>501 の方法がベスト 上とは関係ないけど 別のところで使えるかもしれないプロパティを見つけたので書いておく TakeFocusOnClickプロパティ コントロールがクリックされたときにフォーカスを取得するかどうかを指定します。 True ボタンはクリックされた場合にフォーカスを取得します (既定)。 False ボタンはクリックされた場合にフォーカスを取得しません。 以前つくったものについて高速化を図ろうと思っている そのうちだけど。 グローバル変数が多い糞仕様を直したいんだけど ここをいじるとグローバルが故に影響の大きさが怖い グローバル変数をさわるとしたら、もう一度全部一から作り直す気持でかからないといけない 今のところは、ネストの深い場所で、ワークシート関数へ置換えができないかを考えている 特に、遅くなりがちなセルの値を取得するようなもの 具体的にはforで回しながらIfで一致を試みるようなコードに Find関数やCountIf関数を使えないか模索したい 二点 ・TextBox1_Changeは、テキストボックスに、他のボタンやプログラムを使って 今表示されているものと同じ内容を表示させた場合には働かない 当たり前といえば当たり前だけど、文字列の再入力全てに反応するのではなく 文字列の内容が変化したかどうか、そこに反応する ・Val は文字列を数値に変換する Valueの略か? TextBoxとかのKeyDownイベントで Ctrl + c とかを判別する時、 If Shift = 2 and KeyCode = vbKeyC とするのが正解 If KeyCode = vbKeyC and Shift = 2 とするのは不正解 下のコードだとCtrlを押した時点ではCを押していないため Cを押す前にifブロックをそのまま抜けてしまう ちょい時間なくて未確認だけどたぶんこうかなと思っている >>506 は間違い どちらもちゃんと機能する ただしだ、 明日書こう ただしだ、 上に書いた例だと Ctrl+c の話なんだけど c だけを押した時も別の機能を持たせたいとする このときに If KeyCode = vbKeyC Then (処理) ElseIf Shift = 2 And KeyCode = vbKeyC Then (処理) End If とするとctrl+cが働かない If Shift = 2 And KeyCode = vbKeyC Then (処理) ElseIf KeyCode = vbKeyC Then (処理) End If だとうまくいくようだ あと、今まで知らなかったことを知った なんでこんなことを知らなかったんだろうと今更ながら衝撃を受けた VBAで書いたFunctionプロシージャを ワークシート関数として使う事ができる これは知らなかった たぶんVBAやってる人は当たり前に知ってることなんだろうけど 独学でやっていたせいかこんな大事な事を知らなかった ワークシート関数をVBAのコードで使うと便利だし高速化に繋がることは知っているんだけど 逆があるとは! ワークシート関数の優れたところは、簡単な記述でリアルタイムにセルに 値を反映させることができる点。 これを使えば、今まで躊躇してきた問題も解決できそうだ VBAのクラスモジュールはほとんど使ったことなかったんだけど ネットでざっと読んでみるとJavaやC#のクラスと同じような仕組みだとわかる どちらかというとC#か 以前数回使ったことあるんだけど、あまりよく分からないまま使ってた オブジェクト指向の言語勉強してからもう一度学び直すと、なるほどなって思える そこでVBAのもう少し高度な参考書をぽちってみた 入門レベルでは決して足りない実務に必須のスキルとは ExcelVBA 実戦のための技術 単行本 ? 2018/5/24 沢内 晴彦 (著) 今まで作ってきたものを見直すために使えるかもしれない 昔作ったVBAのコードを数時間いじって高速化を試みてみたんだけどことごとく失敗に終わった 高速化とか考えずにとりあえず作ってみたっていうコードが一番速かったという結末 コードの5カ所ぐらいで時間計測してみたら、処理が遅くなっている場所を読み違えていたようだ ただ、主因となっているところは複雑なコードではなく、改善の余地があまりない 難しいもんだ うぉ・・・高速化成功した・・・ 所要時間が1/5に短縮! 5000個ぐらいのセルの値をクリアするコードなんだけど クリアしちゃだめなセルもある セルの値が、10パターンぐらいの文字列のどれかに当てはまるなら、そのセルはクリアしちゃダメ んで、 たぶん一致不一致の判定で時間かかっているんだろうと思って Likeとアスタリスク使う方法、正規表現使う方法、10パターンの文字列を配列に格納したり コレクションに格納したり・・・ いろいろやってみたんだけど大差なし どうやら、実際に消し込む作業に時間がかかっているということが判明 Cells(i, j).Value = "" や Cells(i, j).Clear より Cells(i, j).ClearContets の方が速いということはわかったんだけど それ以上の方法が見当たらなかった で、いろいろググってたんだけど、解決方法は以下の通り 10パターンの文字列は配列だろうがコレクションだろうが大差ないから適当になんかに入れておく 一旦5000個のセル値を配列CellsDataに格納する方向で進むんだけど、 CellsDataの値をひとつずつ10パターンに当てはまるか判定して 当てはまる時だけセル値をCellsDataに入れていく 当てはまらない時は入れないから、そのセルに対応するCellsDataの要素には何も入らないことになる こうすることで、CellsDataの中身は、必要なセル値を消去した後の表と同じ内容となる そして、この消去用配列CellsDataを使って、一気に書き込んでいく Range(Cells(), Cells()) = CellsData これ↑が突破口だった よく考えるとこれまで何度か読んだことがある話だったんだけど、思いつかなかった 大量のデータ消去には消去用配列をRangeに一括書き込みすることで高速化が図られるのだ! これは何も消去だけに限った話ではないのかもしれないんだけど、 単なるデータのセルへの書込みで目立って遅くなったことはない とするとやはり消去時に特に効果が出る手法なのかもしれない データ書込みも同じようにしたら所要時間がさらに短くなった! 新しく買ってきた本ちょっと読んだけど知らなかったこと多い Dim i, j as integer とかいまだにやってる人がいるが・・・・ と書いてあったのだが、はい、わたくしです 知らなかったわぁ これ i がVariant型になっちゃうそうだ たぶん勉強始めた頃にこう書いてあったサイトを真似しちゃったんだと思う こう書いてあるサイトや参考書が結構あるから勘違いしてるひとが多いそうだ 正確には Dim i As Integer, j As Integer カウンターぐらいじゃそう問題は起きないかもしれないけど 他の型の変数も同じように定義してきたから これが原因でわけわかんなくなったエラーもあっただろうな >>515 の続きだけど、ワークシートからのデータ取得も 一旦Range型変数に一括取得してから Rangeから配列に一括代入 そのあと、必要な操作をしたほうがよさそう 今までは必要なデータのみを for や If とかを使って ワークシートから抽出して配列に代入してた ちょいおかしいか とにかく不要部分も含めて配列に一括取得してから操作したほうが速いかもって話だ 列挙体便利すぎ 可読性が全然違うわ セルに書き込んだ設定値を拾って配列に入れて使ってたんだけど Ary1(1, 1) = Ary2(1, 2) & StrConv(Ary2(1, 1), vbWide) みたいな書き方してたから、わけわからんコードになってた 今時間見つけては、過去に作ったでかいプログラムを作り直してる 作り直す上での課題はたくさんあって書き切れないんだけど この前買った本をもう少し読んでから本格的に取りかかった方がよさそうなんだよな とか言いながらコードどんどん書いちゃってるけど 列挙体はネストができるともっとよかった vbaでクラスモジュールを使う必要性はない、あっても限定的だ とも言われている でも、ざっと勉強した感じでは、コードの可読性やメンテナンスのしやすさを考えるとそうとも言えないという印象を持った 一度しっかり使えるようにしておきたいので 実用的なお手本コードを何度か書いてものにしようと思う 参考書にはColectionやDictionaryと組み合わせた処理が書いてあるので これをちゃんと理解して使えるようにしたい https://qiita.com/pregum/items/071f72969d72d90cf826 ここにもCollectionとDictionaryを組み合わせるコードが載っている 使い方は参考書に載っているものとは違うんだけど、 基本的に大事な事は DictionaryはExistsメソッドによる検索機能が優れているので 検索機能を強化するために使っているという点 CollectionとDictionaryは似ているので 何のために使い分けているのか把握しておかないといけない じゃCollectionの利点はというと Dictionaryと違ってItemのみの登録ができるという点なのか なので、一次元配列を使おうかという場面でCollectionはいい対抗馬になる ここに検索機能をつけたい場合は 何かを媒介としてDictionaryとつなげる ここも参考にした http://blog.livedoor.jp/minus_alpha/archives/4233055.html ええっと、>>525 の何かっていうのは、Collectionのインデックス番号だな Dictionaryにはこのインデックス番号をItemとし、Keyを検索ワードとして登録していくわけだ IndexNum = myDic.Exists(検索ワード) とすると検索ワードに対応するインデックス番号を取得できるので、 こいつを使って、Collectionの要素を参照していく myCol.Item(IndexNum) とかいう感じで プログラムの組み直し終わったわ 以前の1/4ぐらいの時間で終了 まぁ以前のコードも参考にしてるから当然なんだけど 改変部分も結構ある 以前より使い勝手がよくなったと思うし処理速度は1/10ぐらいになっている Dictionaryを組み込んでないのが心残りだわ やっちゃおうかな・・・メインの部品に組み込んでいくから影響範囲が大きいんだよな んー VBAでも構造体が使えたのか これってクラスモジュール使うのと同じような場面で使えるなぁ https://www.sejuku.net/blog/39307 構造体がデータを格納する機能だけであるのに対して クラスモジュールはメソッドがついてくるから、その辺まで拡充した役割が必要な時は クラスモジュールに軍配があがるのかなぁ あと、セッターで適正値に直したり排除したりできるし やっぱ複雑なものはクラスモジュールに任せると可読性あがりそう 今回のプログラムも結局クラスモジュールは中心的な処理の中には入れなかったし これも心残りだわ Dictionary は Exists を目当てに使うのが正解なのもしれない これ便利 だけど、Key が対象となるわけなので、同じものが重複するようなデータには使えないな それがネックか ふぅぅぅぅぅ やっとわかったぜ・・・ ユーザーフォーム上に動的配置したコントロール間で相互にアクセスする方法 もし静的配置であれば簡単で 例えば TextBox2のクリックイベントプロシージャ内で MsgBox UserForm1.TextBox1.Value と書けばいいだけ 動的配置した場合はこういう風にはアクセスできない 今までも動的配置によるコントロール配置はやってきてるんだけど 相互アクセスはやったことがなかった クラスモジュールにイベントプロシージャを置く事になるんだけど この中で 動的配置されたテキストボックスのコントロール名を使ってアクセスするというのが解答のようだ つまり、ユーザーフォームで動的配置したときに、アクセスしやすいように Nameプロパティで名前をつけておく。 例えばTargetTextとしよう その上で、クラスモジュールで Dim tempTextBox as Control Set tempTextBox = UserForm1.Controls("TargetText") とすれば MsgBox tempTextBox.Value でアクセス可能 疲れたああああああああああああああああああああああああああああああああああああああ ユーザーフォーム上のコントロール動的配置についてもう少し理解を深めるために 単純なプログラムを作ってテストを重ねてみた ぐぐっても出てこない部分は想像に頼ってるんだけど、大体理解出来たと思う たまにこういう事をやらないと無駄なコードを書くことになる 今回は今まで書いてたコードの間違いというか、無駄な部分をいくつか見つけたのが収穫だった よし、機能的には大体やりたいこと全部できた あとはエラーが出ないか現場でチェックだな 一仕事終わった クリップボードを経由しないコピーを勧める理由 http://blog.sbe.tokyo/20150909/470/ なるほどなぁ こういう考えもあるんだな 確かにいろいろと問題あってめんどくさいとは思っていた これに関連して 罫線のコピー http://blog.sbe.tokyo/20150115/203/ VBAでエラー処理をSubプロシージャごとに書いていく作業が刺身にタンポポ乗っける作業と同じぐらい苦痛 これC#で自動化するプログラム書いちゃおうかな 単なる文字列操作だからできるよな ここ数ヶ月やってなかったんで忘れてしまったが、C#の課題としておくか >>537 を参考に罫線をコピーするコードを書いてみたんだけど死ぬほど遅い やっぱりCopyメソッド使った方がよさそうだ C#の参考書少しずつ読んでるんだけどVBAとダブる部分は VBAだとどうなのかをメモしてる この辺ちゃんとやっておかないと記憶があやふやになる VBAとしっかり比較しながらやると勉強になる C#の知識が増えるころにはVBA忘れる現象に少しは歯止めがかかりそう というか比較しながらやると知識の固定にも役に立ちそうだわ 除算系の算術演算子とか基本的なのも忘れるからなぁ 独習読み込むのと同時に C#でちょっとしたウィンドウズアプリ作ってる URLをテキストボックスに入れてボタン押すと サーバーにアップロードしてあるZipをダウンロードして解凍して 日付で名前をつけたフォルダに入れるってやつ こういうのってエラー処理やら利便性無視すれば簡単にできるんだけど いろいろ考えちゃうと難しくなる 適当なところで見切りつけて終わる予定だけど。 ググって出てくるコードみると、イベントにマルチキャストデリゲートだったか そんなの使ってたりするんで理解しようとすると大変だ GUI関連をきちんと理解するのに役に立つ本があるといいな 今日の学習は終わり! 4章の途中まで復習した switch-case文、 VBAだとSelect Case-Case文 これがたまに混同する If文の条件式みたいにC#だと丸括弧を使うので注意だな すぐ忘れる ローカル変数の整数型、初期化しないと VBAのIntegerだとゼロ C#のintだとコンパイルエラー フィールドだとC#はゼロ埋めのようだ 配列も同様 この辺VBAの方が易しい コンソールアプリの強制終了はctrl+c 無限ループになった時とかね delegateをごちゃごちゃいじってる 簡単なプログラムを何個も作ってテストしてる いろいろ分かってきたわい ラムダ式をごちゃごちゃいじってる 独習のラムダ式の説明はいまいちだな 理解はできたんだけど、これじゃ挫折する人いると思う デリゲートを用いる最も簡単な例、つまり、メソッドの引数としてメソッドを引き渡すケースではなく メソッドを変数に代入して使うだけの簡単なケースを ラムダ式の紹介の一番最初に出してくれないと。 おそらく紙面を節約しないといけない都合でこうなったんだろうけど 配列とかコレクションとかで、全ての要素を順に操作する目的で ラムダ式が多用されるのな これ便利だわ ちなみに独習の標準ライブラリの章で配列にAnyメソッドを使ってる場面があるんだけど これはListでも使えて、たぶんListにあるExistsメソッドと機能は同じだ Anyはusing System.Linqが必要 この辺の知識はForの代用として使えるから、すっきりとしたコードをかけるようになれそう ラムダ式の構文でこんなのが独習に書いてある TResult Func<T, TResult>(T arg) こういうのをこれまで半ば無視しつつも、時に参考にしてきた 厳密な使い方を理解したいなら、この「構文」とやらをちゃんと理解しておいたほうがいいんだろうなとは思ってる この構文の形式に近いものがコードに現れてくるのは ラムダ式で表現されたメソッドを受けとるメソッドの定義部分 例えば void DoMethod(Func<int, string> output) { Console.WriteLine(output(10)) } みたいな。 TResult Func<T, TResult>(T arg) において、 <T, TResult> は、T型を引数とし、TResult型を戻り値とする、の意味。ジェネリックだ 頭のTResultは、TResult型の戻り値をおけ、の意味 (T arg)は、T型の引数argをおけ、の意味 argは、argument 引数 の意味 引数というのはparameterじゃなかったっけと思って調べてみたんだけど argument 実引数 parameter 仮引数 みたいな違いがあるという記述があるという一方 それほど厳密な定義でもないという話も。 エントリーポイントのメインメソッドの引数、つまりコマンドライン引数でも args として複数の引数を示している argとかargsが構文に書かれていたら、実際にここに引数を書けということだと理解すれば足りるということだな 少し違和感を感じるのは、なぜ引数だけargという記述を用いて、 戻り値の方はTResultという型しか書いてないのかという点だけど、 まぁこれはよく考えたら、例えば仮引数に変数を使うけど、 戻り値にあらためて変数を使う事はないし、戻り値はメソッド名を書くことで取得できるわけで そういう意味では、引数にargの記述があり、戻り値にはこういう記述がないのは当たり前か 戻り値を そう考えると、こう書くのが正確なのか TResult Func<T, TResult>(T arg) において、 Func<T, TResult> は、Func<>の<>の中に2つの型を書けということを示す。そして、 (T arg)の記述により、一つ目のTが引数の型として使われることを説明 構文の冒頭に記述されるTResultの記述により、2つ目のTResultが戻り値の型として使われることを説明 みたいな感じか まずFunc<T, TResult>という風に書け そして、TおよびTResultが何なのかを説明するために TResult Func<T, TResult>(T arg) というようにFunc<T, TResult>の前後に追加して記述されていると。 順番を意識したほうがよさそうだ LINQで分からないところがあって、ずっと考えてた やっと分かった(気がする)んで今日はこれで終わろう もう少しちゃんと説明が書いてあるといいんだけど、難しかったんだろうな ぐぐってもなかなかヒットしないしね LINQを使う前に、IEnumerable<T>の理解はしておかなきゃね ということでその辺の復習してる 独習に例示してあるコードは実践的にしたいためか 学習するには要点がぼけてしまってるものがある なので、自分でぱっとみてポイントが分かるようなコードに書き直して ちっこくプリントアウトして独習に貼り付けるというアナログなことをしている なんだかんだいって勉強は紙の方がいいんだよなぁ 検索ができないという点をのぞけばだけどさ リアル本と電子書籍のハイブリッドなナニカができるといいな 見てくれはリアル本なんだけど、一ページ一ページが電子的な処理が施されていて 印刷内容だけでなくメモった内容も表紙に内蔵されたストレージに保存される これを使って検索も容易に出来るとか 俺しか需要がないか 頭の中で、抽象クラスというものの存在意義と ポリモーフィズムがしっかりと関連づけられていなかった ここがちゃんと結びついてるといろんなルールもすんなり頭に入ってくる (ような気がする あるクラスのプロパティAやメソッドAが、別のクラスBのオブジェクトを返す場合 AとBの名前が同じなことが多いのかな これまで適当に捉えてたから気づかなかったんだけど、正確に捉えて置いた方がよさそうだ 例えば、 正規表現で、RegexクラスのメソッドMatchがMatchクラスのオブジェクトを返すから Matchメソッドの構文は Public Match Match(string input [, int beginning [, int length]]) とMatchが2つ連なっている で、戻り値として得たMatchオブジェクトというかインスタンスのメンバを使っていろいろと 詳細データを引き出すことになる なので、最低限この2つのMatchが別物だと認識することは必要 正規表現で サブマッチ文字列を取り出しすとする foreach (Group item in m.Groups) { Console.WriteLine(item.Value); } みたいにするんだけど、このとき、Groupをvarにすると Valueプロパティが使えなくなる foreach (var item in m.Groups) { Console.WriteLine(item); } ならいける ん〜なんでだろと思って調べてみたんだけど、varを使うとitemにobject型が入るみたいだ そのため、Group型であれば使えたはずのメンバーが使えなくなる 単純に表示させるだけなら別に問題ないんだけど。 ここで大事なのはvarを使っても具体的な型を使っても同じだと思っていたけど そうではないケースがあるということだ 上の例だとGroupを使った時はvarを使った時と比べると、6個も追加のプロパティが使えるようになる 複雑な操作を必要とする場合、影響大きいかも 正規表現おもろいなぁと思って 正規表現の聖書と言われているオライリーの「詳説 正規表現」をアマゾンでみたら \5,184 https://www.amazon.co.jp/dp/4873113598/ ふぇ・・?正規表現だけで5せんえんですか! しかしそのうち買ってしまう予感がする・・・・ public static void Main(string[] args) { Console.WriteLine("aaa"); } みたいなJavaでやってたカッコの付け方に変更できるようだ Visual Studioの ツール→オプション→テキストエディタ→C#→書式設定 「始め中カッコ」 という名称があるようだ 変更しようか迷うところだ DateTimeの復習してて令和を含んだ文字列をParseできないか試したけどだめだった VisualStudioをアプデしたらいけるかなと思ってやってみたら、 これ数ギガ分、つまりファイル全部アプデすんのな DL待ちで使えなくなってしまった windowsアプデのKB4493453を手動でいれたら、令和認識するようになったわ var str = "令和1年5月1日"; var d = DateTime.Parse(str); Console.WriteLine(d); 結果: 2019/05/01(日) 0:00:00 IFormatProviderとかいうのがいろんな構文に引数の型として出てくる 引数の型として指定されているにもかかわらず、実際のコードをみると 「IFormatProvider」という文字はどこにも書かれていない 見て見ぬフリしてたがちゃんと調べてみた 通常はIFormatProviderを実装したクラスであるCultureInfoクラスを利用するようだ 日本独自の表現をしなければならないような場合に使うようだ 例えば日付情報なんか 「2019年」というだけで「年」という日本語を使うので、正確に言えばこういうものを表示する場合だって含まれる IFormatProvider provider のようにメソッドの引数として指定されている場合、実際のコードではこう書く ・new CultureInfo("ja-JP") ・CultureInfo.CurrentCulture ・CultureInfo.GetCultureInfo("ja-JP") のどれでも結果は同じだった 要はIFormatProviderを実装するCultureInfoクラスを使って 日本だってことが伝わればいいようだ var dt = DateTime.Now.AddDays(2); var ci = new CultureInfo("ja-JP"); ci.DateTimeFormat.Calendar = new JapaneseCalendar(); Console.WriteLine(dt.ToString("f", ci)); 結果: 令和元年5月1日 12:03 おぉ・・・でたでた ci.DateTimeFormat.Calendar = new JapaneseCalendar(); が大事 DateTimeFormatプロパティは戻り値がDateTimeFormatInfoオブジェクト つまりCultureInfoクラスは、DateTimeFormatInfoオブジェクトをフィールドとしてデータ保持していることになる そんでもってDateTimeFormatInfoクラスはCalendarプロパティを持っている CalendarプロパティはCalendar型のフィールドに繋がっている ここにJapaneseCalendarオブジェクトを代入する 継承Object→Calendar→JapaneseCalendar だから代入可ということか おっしゃ 実際に役立つアプリができた ランチャー的なものなんだけど練習にはちょうどいいし 自分で使う分には相当便利で満足 令和の初日に完成か もう1個作った Javaで作ったやつをC#で作り直したんだけどずっと簡単だった VSの恩恵を受けてるだけなんだけど。 夏時間も反映する海外の時間も表示する時計なんだけど ついでにこいつをタイムスケジューラ代わりに使っていこうと思う Windowsのタイムスケジューラはなぜかそのうち機能停止するので役に立たない webスクレイピングまで行かなくてもhtmlもらってくる処理をしたりするときのお手本コードを 調べてるとasync awaitをつかったものがでてくる この辺は独習で飛ばしてしまったのでやり直すことにしよう async awaitのところ、独習の説明だと分かったのか分かってないのか分からないという 経験から言えば、これはちゃんと理解できてないなという程度 もう一冊買ってある参考書を読むことにする 実戦で役立つ C#プログラミングのイディオム/定石&パターン を読んでるんだけど、わかりやすいわぁ 独習は基本的な所を網羅してる点でいいんだけど、少し難しい所に入ると 紙面節約のためか学習の順序ってのをすっとばして説明するから困る 独習もう一度しっかり読んでから実戦を読もうと思ってたけど、 こっちも読み進めていった方が効率あがりそうだ Javaで作った定期的なグローバルIPアドレス記録を時計アプリに組み込んだ ローカルIPアドレスもついでに記録するようにしたんだけど、これが案外手間取った あとTimerのインターバルが100mm秒だとなかなか気づけなかった 1秒だと思い込んでた タイムスケジューラ的な使い方がうまくいくなら これからはこいつがwindowsのタイムスケジューラのかわりとして利用できることになるわけだ 今回は基本的な非同期処理も取り入れていろいろ勉強になった タスクスケジューラに登録してたのものをすべて時計アプリから実行するようにした バッチファイルもいけるかなと思っていろいろ調べてやっと問題なく起動できるようになったんだけど よくよく考えてみたら、exeにコマンドライン引数を渡すためのバッチファイルだった つまり、普通にexeを時計アプリから引数付きで起動すればいいだけの話だった もっと言えばそのexeも自分がプログラミングができないから、ネット上から誰かの作ったフリーソフトをダウンロードしたもので、すでにある程度自分でやれるんだから、自作すればいいだけの話なのだが。 少しずつ自作のプログラムに置換えていこうと思う エスケープシーケンス関連の理解が不正確 もっと厳密に理解することにする なんとなく適当にやってるとできちゃうからよくない Console.WriteLine("aa\naa");//aa[改行]aa Console.WriteLine("aa\\naa");//aa\naa Console.WriteLine(@"aa\naa");//aa\naa Console.WriteLine("aa\daa");//エラー Console.WriteLine("aa\\daa");//aa\daa Console.WriteLine(@"aa\daa");//aa\daa Console.WriteLine((new Regex("aa\naa").IsMatch("aa\naa")));//true(これは特殊な例か) Console.WriteLine((new Regex("aa\\naa").IsMatch("aa\naa")));//true Console.WriteLine((new Regex(@"aa\naa").IsMatch("aa\naa")));//true Console.WriteLine((new Regex("aa\daa").IsMatch("aa1aa")));//エラー Console.WriteLine((new Regex("aa\\daa").IsMatch("aa1aa")));//true Console.WriteLine((new Regex(@"aa\daa").IsMatch("aa1aa")));//true んー正規表現のパターンの中でエスケープシーケンスを用いる場合 基本的には逐語的な表現をしないといけないと思うんだけど、 \nのようにそうでないものもある 上の単純なConsole.WriteLineでの出力で\nについてエラーがでないことと関連するんだろうなぁとは思うんだけど、まぁそういうことなんだろうな 非同期処理async-awaitはC#7.1以降、Mainメソッドでも使えるようになった しかし、デフォルト設定だと 「最新のメジャーバージョン」を適用することになっているためC# 7.0までしか使えない そこで、プロジェクトのプロパティ→ビルド→詳細設定から7.1以降を選ぶ もう一つ DateTime型は算術演算子を使った比較ができるんだけど DateTime.Nowを使って取得した現在時と、new DateTime()で取得した固定時間を比較して イコールになったタイミングで何かをするみたいなことをしようとしてもなぜか一致しない これは、DateTime型がミリ秒まで格納してるから。 Nowの方はミリ秒が半端なのに対して固定時間はゼロなので、大抵一致しない そこでミリ秒部分を無視できるように、ToString()でミリ秒がないような文字列に変換して比較するといい ちなみに、この実験をするときに、VBAでつかったSleepみたいなメソッドがあるといいなと思ったんだけど、 非同期処理をするTask.Delay(1000)を使った方がよいということだ。 これを繰り返し処理と合わせて、1秒おきに処理させて一致させると。 んで、Task.Delayをメインメソッドで使えたら楽できると思って、・・・・最初の話につながる 時計アプリでTimerを使ったんだけど whileとTask.Delayを組み合わせる方法とどちらがいいんだろうか そういやTimer使った時、非同期処理なんて考えても行かなかったんだけど https://qiita.com/kenji-yokoi/items/3115dbf876e6ed30ba50 こんな感じにやったほうがいいわけか 結局どちらの方法を使っても非同期処理をうまくやればいいってことかな >>577 DateTime型は関係演算子を使った比較ができるんだけど* 引き続いてasync-awaitやってるんだけど 自分で適当に練習コード書こうとするといろいろ気づく Mainメソッドでasyncを使う時 public static async Task Main(string[] args) みたいにTaskを戻り値の型としないといけない これをvoidとするとエラー これは理解できる C#7.1以前は別にasyncのメソッドを作ってたわけだ static async Task RunAsync() みたいなの。 これをMainとかから呼び出す形で使ってたわけだけど そのままMainに組み込めるようになったということなので Mainの戻り値がTaskになるのはごく普通 そもそもここをTaskとするのは、そのメソッドを呼び出したメソッドに非同期処理の状況などを 通知するためなんだけど、Mainを呼び出すメソッドに通知するって話になる ん・・・?ってなるけどここはまぁいいとする 問題は、GUIアプリでつかうイベントハンドラを非同期にした場合 private async void button1_click() これはなんでvoidなんだ?って話 これがおかしいのかこれは普通でほかがおかしいのか、その辺を突き止めるのがやっかいだったけど 結論としては、イベントハンドラの方が特別で例外的な仕様になっているようだ ここでvoid Taskとするとエラーがでる そもそもイベントハンドラを呼び出すのはコードではなくてユーザだから Taskで通知を返しても意味ないじゃんとかいうことらしい なるほどね //@ public static async Task Main(string[] args) { await Task.Run(() => DoSomething()); } //戻り値のない同期メソッド static void DoSomething() { var str = "aaabccc"; var result = str.Split('b'); Console.WriteLine(string.Join(".", result)); } //A public static async Task Main(string[] args) { var str = await Task.Run(() => DoSomething()); Console.WriteLine(str); } //戻り値のある同期メソッド static string DoSomething() { var str = "aaabccc"; var result = str.Split('b'); return string.Join(".", result); } //B public static async Task Main(string[] args) { await DoSomethingAsync(); } //戻り値のない非同期メソッド static async Task DoSomethingAsync() { await Task.Delay(2000); } //C public static async Task Main(string[] args) { var str = await DoSomethingAsync(); Console.WriteLine(str); } //戻り値のある非同期メソッド static async Task<string> DoSomethingAsync() { await Task.Delay(2000); return "aaa"; } 非同期Mainではwaitは使わないでいいってことかな 呼び出し元でwaitを使うわけだけど そもそも呼び出し元がないような形になっているのでwaitを使いようがない https://www.kekyo.net/2016/12/06/6186 ここにすごく大事な事が書いてあるような気がする 自分なりにまとめると、 非同期Mainでwaitを使わないでよいのと同じような理由で GUIアプリのイベントハンドラでもwaitを使わなくてもよい、というようなことになるのかな 使っちゃうと「デッドロック」とやらを引き起こしてしまうそうな waitをつかわなくちゃだめな例としてはコンソールアプリで非同期メインを使ってないケース メインメソッドから非同期メソッドを呼び出す すると、呼び出し先の非同期メソッドではawaitで当該非同期処理の終了を待機することになる その間にメイン「スレッド」はメインメソッドを抜けてしまってプログラムが終了してしまうことになる つまり、非同期メソッドの終了を待たずしてプログラム全体が終わってしまうことになる これは呼び出し元がメインメソッドだからこそ起きるとも言える @非同期メインでwaitを使う必要がない理由 非同期メインではメインメソッドの中で「await」(waitではなく)を使う事になる これによってawaitに続く非同期処理が終了するまでメインスレッド自体が待機することになる これによってメインスレッドが勝手に終了してプログラムが終わってしまうなんてことはないということだ コンソールアプリで非同期メインを使わないケースでは「await」が置かれているのはメインメソッドではなく、メインメソッドから呼び出される非同期メソッドの中であるという点に注目すれば違いが分かる この場合は、非同期メソッドの流れがそこでawait(待機)状態になるわけだ 非同期メインではメインメソッド内にawaitが置かれるためメインメソッドの流れがそこでawait(待機)状態になる A AGUIアプリのイベントハンドラでwaitを使っちゃだめな理由 イメージ的な説明なんだけど、 コンソールアプリで非同期メインを使っているときのメインメソッドと GUIアプリの非同期イベントハンドラは同じような位置づけになるんじゃないかと。 つまり、 非同期のイベントハンドラ内でawaitを使う事になるので、そこで非同期処理が終わるまで待機してもらえるためwaitの必要がない これは@とまったく同じこと いまんところはこういう理解をしている そのうち変るかもしれないが FileInfoとかDirectoryInfo使う時のパス指定で 「 . 」カレントディレクトリ 「 .. 」一つ上のディレクトリ が使えるんだけど、一般的ではないのか独習にも書いてない FileInfoのコンストラクタに渡す引数なんだけど " data.txt " " . / data.txt " " . \data.txt " この3つはどれを渡してもカレントディレクトリのdata.txtの意味になる (5ch上では判別しにくいので半角スペースをいれてある) / と \ が同じ意味で使えるっていうのは・・・・ さらに " .. /data.txt " " .. \data.txt " この2つはどちらも一つ上のディレクトリのdata.txtを意味する まさかと思ってやってみたんだけど、 これまで出てきたパス指定なんだけど、¥のかわりに/を使っても大丈夫だった なら逐語的表現を指定する@を使う必要がなくなるのか なんで独習には書いてないんだろうか 思い出してきたんだけど、スラッシュをフォルダの区切りとして使うのはもともとUNIXでの書き方か http://www.tohoho-web.com/ex/draft/path.htm windowsだとバックスラッシュを使うのが基本 HTMLだと/が使える この辺は混在してるわけか 地道に独習の復習 やってて思うんだけど、簡単なコードの使い方ぐらいは調べなくても さっさと書けるようにしないと、難しいコードの使い方を覚えようとしたときに行き詰まるんだよな 記憶力がいまいちだからしっかり覚えるために工夫していかないといけないなと思ってる VBAのプログラム作ってた windows API呼び出すものなんだけど DoEventsを使わないとうまく行かないということにやっと気づいた うまく作れた VBAのプログラム作ってて思うんだけど windowsAPIを使いこなすための基本知識が欲しい なんだかんだこぴぺで足りてしまうんでちゃんと勉強してこなかった 何かいい本ないかと思ってアマゾンで検索して よさそうなのポチろうとしたら、すでに購入済だって表示されててワロタ 今その本発掘してきた これはVBAだけじゃなくて他の言語もやってないと難しいな ずっと前に少しだけ読んで結局途中で挫折したの思い出した 今読むとそこそこ理解できる C言語の知識も使うようだ ずっと昔に少しだけやったけど忘れてしまっている VBAで引数にカッコつけるかどうかの話は大事なんだけど結構忘れる 細かい仕様を理解してないとどうしてこのバグがおきてるのか理解できない ここはちゃんと押さえないといけないんだが・・・ 括弧()はどんなときに使うの? http://officetanaka.net/excel/vba/beginner/07.htm もう一つこれ VBA 関数に引数を渡す https://www.tipsfound.com/vba/02002 ここの「ByVal と ByRef の違い」の「注意点」ところ もう一度読んでおかないといけない これたぶん知らなかったと思う 「これは引数に括弧 () を付けると、強制的に ByVal (値渡し) にする仕様のためです。」 callをつけない場合にバラエティに富んだ動きをするみたい いままで経験的にcallをつけた方がエラーが起きにくいと思っていたのは この辺の仕様を理解出来てなかったからだな http://officetanaka.net/excel/vba/statement/Call.htm myFunctionが引数を受け取り値を返すユーザー定義関数だった場合の書式は、 次のとおりです。 myFunction 123 正常 myFunction(123) エラー Call myFunction 123 エラー Call myFunction(123) 正常 rc = myFunction 123 エラー rc = myFunction(123) 正常 rc = Call myFunction 123 エラー rc = Call myFunction(123) エラー こう書いてあるんだけど、2番目のこれ myFunction(123) エラー 実際にVBEで書くとこんな感じに半角スペースが自動的に挿入されて表示される myFunction (123) でもって、エラーなしで通ってしまう myFunctionの中身次第で通らないこともあるのかもしれないんだけど、解釈としてはこう myFunction 123 '戻り値を利用しないからカッコをつけないパターン myFunction(123) '戻り値を利用しないからカッコをつけるとエラー(しかし実際にはこう書くことはできない) myFunction (123) '戻り値を利用しないからカッコをつけると本来エラーなのだが、半角スペースが自動ではいることで、このカッコは別の意味を持つ。つまりこのカッコはByValを強制するカッコとなる。 Win32APIの知識はVBAだけじゃなくて他でもそのうち役に立つかもしれない と思ってやってるんだけど、それより C言語が絡んできたのが面白い まさかVBAやっててC言語の知識を使うとは思わなかった ある言語から他言語を使うようなパターンは今まで一度もやったことがなかったから そういう意味でも面白い 固定長のnull埋めされた文字列を定義して渡したあと 戻ってきた文字列からnullを抜いた残りを取り出すとか またVBAのプログラム作ってた 正規表現盛りだくさんやつ やっぱ正規表現の本買っちゃおうかなぁ これ使えるわ あーまたVBAにはまってきた C#と文法がぐちゃぐちゃになって次第にVBA勢に脳内が支配されて・・・・ うがああああああああ functionの作り方で、配列とかを引数としてfunctionに渡して適切な値を入れてもらう んで戻り値をbooleanにして成否を伝えるっていう Win32APIの勉強しててこのパターンがよく出てきたんで真似てみたんだけど悪くない たくさんプログラム作ってると、以前作ったもののメンテナンスしないと いけない場面によく出くわすんだけど 共通した処理を関数に切り出したり、共通した値を定数として宣言したりするのってほんと大事だ 昔つくったのはこの辺ができてないから、少しいじるだけでも大変 いろんな所に同じものが散らばってるから全部直さないといけない メンテナンスまでやると大事さがわかってくるなぁ VBAのプログラムを3つ同時に作ってる 一つは昔作ったやつで、これまでは使われてなかった でも使う事になったんで見直したらいろいろいじりたくなってきた マジックナンバーが多すぎるし共通部分の洗い出しが全然できてない これじゃメンテナンスに苦しむのは目に見えてる 今後変更されそうな部分は簡単に取っ替えられるようにしておかないとね ほんとはもっと大きくいじってもよさそうなんだけどキリがない 10個ぐらいのデータを並べて1セットとして このセットを1ページに複数行複数列タイルを貼るかのように 並べていくパターン この処理が3つのシートそれぞれにあって、それぞれ別個のコードを書いてた セットの中身も違うし、並べるタイルの数も違うんだけど これを一般化して関数として作り直した 数列の一般項を求めるのがポイント 関数に渡す引数が多いので構造体を使って一気に引き渡すと同時に 構造体によるインテリセンスによって間違いを減らす これによって、タイルの中身が変更されたときにもすぐに対応できるし タイルの並べ方が変更されても与える定数を変更することで簡単に対応できる ちなみにこれまでのコードでは、 タイルを並べるような概念はなくて、項目のひとつひとつを適切な場所に個別に配置していくパターン セットの並べ方が変ると、10項目ひとつひとつについて修正が必要になっていた コードの見通しも悪かった オライリーの詳説正規表現買っちまったぜ・・・・正規表現だけで5せんえんとか・・・ VBAのコード書いてると 配列は全部要素番号1からの方が処理しやすくて統一してるんだけど ほかの言語やるとゼロからだし、VBAだってsplitが返す配列はゼロから始まるし やぱ配列はゼロからに統一したほうがいいのかなって最近考えてる どの言語やるにしても必ずゼロから始まると意識して気をつけてれば慣れるものかもしれないし 今日はいろいろテクを学んだ 配列関連だから今後使えると思う Rangeで列や行を一括取得したときに作られてしまう二次元配列を 1次元配列にする方法 とか あとListBoxにアイテム追加するのにAddItem使ってたけど これ表示がバグることがあるんで、Rangeや配列から一括代入したほうがよさそう バグらなくなったんでたぶんこうしたほうがいいんだと思った ん〜まだまだ完成しないな 少しずつやっていくしかない 大分進んで、構造的なものも明確になってきたんで あとは間違いないように組んでいくだけだ よーし、大体できたぞー あとは細かいバグがないかチェックしないと 俺が以前作った使えなさそうなプログラムが知らない所で意外な活躍をしてた 役にたつことはあまりなさそうなものでも 使う人が用途を見つけた途端にとんでもないものに化けるから面白い がちがちに固めずふんわり系のインフラ的ソフトは特にね ん〜大体これでいいかな つけた方がいい機能は全部つけた やっぱ入力フォームは鬼門だなぁ 各コントロールが複雑に入り組んでて制御が大変だ 特にListBoxがらみ でもこれで大きなバグは潰したと思うから これ以上でないことを祈るばかり・・・・ まだそんなことしてたんか ワイのwebアプリはMongoDBからAjaxでデータ抽出してクライアントサイドでD3js使って視覚化できるようになったからひとまず完成かな AdSense貼って月二万弱くらいの収益は得られるようになったで 次はサーバサイドでTensorFlowの処理結果をブラウザでインタラクティブに操作できるアプリ作れないか考えてる 深層学習を一から勉強せんとあかんから完成はだいぶ先やな とりあえず引き渡してきた まだバグ見つかるかもしれないけど ほぼ大丈夫だろー こういう風に変えたいなって思った時に すんなり変える事ができるようになってきた 新機能を追加する場合も昔と比べたらずっと楽 最初から変更に備えたコードを書いているというのもあるし いろんな技術も身についてきた感もある VBAに関して言えば、できる限り設定値を外に出して コード外で変更に対処できるようにもしてるから 小さな変更はかなり楽 VBAのDictionaryだけど とりだすときの順番は先入先出で保証されてるみたいだな 保証されてないとか書いてあるサイトもあったけど 大丈夫みたいだ 知らなかったのかよw dictionaryは連想配列なんだからやり方次第でスタックとしてもキューとしても使えるやろ プログラミングは自分の頭と手を使って作らないと身につかんで ワイもオライリーJavascriptの分厚い本読んで模写したりしたが、自分でアプリ開発するまで依存性の注入とかmvcモデルとかイマイチ本質を理解できんかったな 最後に一度だけレスしておくけどさ、 順番保証ってのは当然foreachで回した場合の話でしょ 順序の保証の話は基本書ちゃんと読んでいればforeachとのからみで 幾度となく説明されてるはず Javaなら拡張For文だっけ? それぐらい感づいて欲しい まともに勉強していれば分かったはず 当然Stack Queueの話ではない 後入れ後出しとか先入先出の話は そもそも配列のように順序保証されたList系のコレクションの特徴 仮に連想配列でそういった使い方をするとしてもそれはキーの自由度を犠牲にした上でのことでしょ 連装配列ってのは基本的には順序保証はされていないと考える もともとKeyを媒介にしてデータをとりだすことを想定したものだから。 C#で言えばDictionaryが連想配列 これに順序保証の機能が追加されたものとしてSortedDictionaryが用意されている 基本的には、「連装配列は順序は保証されていない」と考えるべき これは、「基本的」学習事項 Javaでも連想配列の基本となるのがHashMapだが、順序保証されていない HashMapの順序保証のことを説明するのに、StackとかQueueの話は出てくる余地はない VBAのDictionaryについて順序保証されていないと想定するのはごく自然な流れで 順序保証されていることが特殊であると考えるべき たぶんな、金目当てに新しいものにどんどん飛びついているから 基本的な部分が抜けちゃってると思うわ 「プログラミングは自分の頭と手を使って作らないと身につかんで」 とりあえず組みおえたVBAプログラムだけど 機能の一つを使えるようにするのに障害があるってことで 急きょ代替案を選択することになった ちゃっちゃと組み直すか 順序が保証されるかどうかなんて勉強始めて1か月目で確認することやんw それを知らなくて今までどんなプログラム書いてきたん? 大体こんなもんか いくつかの関数でListBoxやら他のコントロールを引数として受けとっているんだけど これってインテリセンスが働かないからイマイチなんだよなぁ プロパティ覚えりゃいいんだけどキーボード叩くのが面倒 今組んでるのが安定運用されるようになればしばらくはVBAから離れられそう これまでいくつかのファイルに分離されていたものを統合したもので 処理上の様々なパラメータもシート上に出して利用者が設定できるようにした いろんな意味で使う人にとっては便利になるんだけど、コードは複雑化する バグも出やすいので慎重になってる シビアな場所で使うようなんで間違いがないといいんだが。 ちょっとした便利ツールみたいなもんか JavaやC#学んでるなら何か作って公開してみたら? あんま個人開発向きの言語やないけど ワイもJava勉強したが、結局今はサーバサイドじゃphpとpython、クライアントサイドはJavascriptやな スマホのネイティブアプリも作ろうかと思ったけどPWAの技術使えばwebアプリをネイティブのように扱えるから辞めにした UserForm上のCommandButton.Font.Bold プロパティだけど 一旦Trueにした後、他の処理でFalseにしようとしても戻らない現象がある まっさらなファイルで試すと問題ない 何が干渉しているのやら。 内部的には細字に戻っているのに表示上Boldのままになってしまっているのかと思いきや If .Font.Bold = True then を入れると反応するので、どうやら内部的にもFalseへの設定を受け付けていないようだ Fontの他の設定を挟んだりいろいろやってみたが受け付けてくれない これは後々の課題としておいて、この場は違うフォントに変える事で我慢することにした VBA関連は一段落したんだけど 貯まってるお仕事にも取りかからないといけない なかなかC#に時間を割けない 休みないん? ワイは土日に開発してるが 趣味がプログラミングみたいなもんやし それで収入も得られるんだからおいしいもんやな あらら、逃げちゃったw 所詮、お遊びでやってただけか ちょい不安定な動きが報告されたんで修正 ListBoxの背景色変更が原因で 勝手にリストのトップにフォーカスが飛んでしまう 発見に手間取ったわ こんなんエクセルのバグだよなぁ しゅんごい順調だが ちょい別のやつの手入れすることになった 三項演算子はIIf ->三項演算子大好き(個人的趣味) 例) Dim value As String value = IIf(i > 10,"10より大きい","10以下") https://yyyank.blogspot.com/2014/09/microsoftvbadont-do-careless.html こんなのあったのか 三項演算子がVBAにあったとは 2019/8/14配信のWindowsUpdateを適用すると、Windows 7/8.1/10(全バージョン)で、 ・VBVisual Basic 6 (VB6)で作成したアプリケーション ・Visual Basic for Applications (VBA)で作成したマクロ ・Visual Basic Scripting Edition (VBScript)で作成したマクロやアプリケーション が応答しなくなり、『invalid procedure call error.』と表示される場合があるという 不具合が発生している模様。 ってことなんだけど、引数にparamarray使ってるとダメとか 使ってないから大丈夫と言えるのかどうか 確認しておかないといけない たまに「俺、何千行のコード書いたことあるぜ」って自慢するやつがいるが、自分のこと無能って言ってるのわかっとるんかねぇ いかに効率的なコードを書くかがエンジニアの腕の見せ所なのに 今週の応用情報技術者試験受けるから、模擬試験やってみた 午前問題86点、午後問題74点 両方とも60点以上で合格だから無事クリア システムアーキテクチャや情報システム開発は年度によっては難しいときもあるが、まぁ大丈夫やろ ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる