Viewについては、"Main.storyboard"をGUI操作で画面を作っていくようです。
単一画面の場合は
1. Main.storyboardをクリック
View Controller Sceneが配置されている
2. View ControllerにUIパーツを貼っていく
3. IBAction / IBOutletでViewController.swiftとView controllerを紐付けする
4. ViewController.swiftにコードを書いていく
と言った手順で
- ViewController (View)
- *.swift (ソースコード)
を紐付けて作っていくようです。
画面が二つ以上の場合は、"Navigation Controller"を使う事で画面を切り替えていくようです。
1. Main.storyboard をクリック
View Controller Sceneが配置されている << ここまでは同じ
2. View Controller Sceneを選択
3. メニューの"Editor -> Embed In -> Navigation controller"を選択
> (Document outline = 左から2ペイン目に)Navigation Controller Sceneが追加される
> GUIでMain.Storyboardの"-> Navigation controller -> View Controller"に接続されている事を確認
※ Navigation controlleにより、View controller(defaultの画面)と2画面目を階層的にコントロールできる為に上記そうさをするとの事
4. 1画面目(View controller)の画面を作っていく
> "Bar Button Item"をドラッグするとNavigation Barの中にNavigation Itemが追加される(画面遷移に関連)
2画面目を作る
5. (際左ペインで)MainStory boardを選択
6. Object library(toolboxみたいなの)でview controllerを探して、story board(GUI画面)にドラッグドロップ
> 画面が追加される...但し、矢印は接続されていない
> Document outline (= 左から2ペイン目)にも"View controller Scene"が新たに追加される
Segueを追加する
7. 1画面目(最初からあった画面)から遷移する場合、1画面目をクリック
> 画面上の"View controller"の□が選択される
※ うまく行かなかったので、menu barのボタンからドラッグした
8. command key を押しながら追加した画面(2画面目)にドラッグドロップする
9. 黒い(segue用の)ポップアップが出るので"Show"を選択する
> これにより、1画面目から2画面目に矢印が接続される
> 2画面目上部にもNavigation Barが追加されている
10. Segue object(矢印部分)を選択して-^-(Atribute Inspector)の"Identifier"でSegueの名前を変えられるので、必要に応じて変更する
※ この状態では実行させても、(4で追加したコントロールをクリックして)画面遷移させようとしても出来ない。下記操作をする事
ViewControllerの追加(2画面めに対応した*.swiftの事)
11. Project Navigator(再左ペイン)でFile-> New -> New File をクリック
> "choose a template for your new file"ダイアログが表示される
12. iOS -> Source -> Cocoa Touch Classを選択してnext (上記ダイアログ)
13. クラス名を記載(***ViewControllerとか)
14. sub classをUI View Controllerにする
15. (言語はSwiftのままで)Next、そしてCreateボタん
> ***ViewController.swiftが生成される
ViewController(2画面めのGUI)と紐付けする
16. Main.storyboard -> 2画面目のViewController Scene -> ViewControllerを選択
17. (際右ペインを)Identifer Inspector(-^-の隣の□アイコン)とする
18. Custom classの項目のclassに****ViewControllerを記載する (***ViewController.swiftのクラス名)
> Document outline (= 左から2ペイン目)で"View controller scene"となっていた部分が*** View Controller Seceneに変わる
これで関連付け完了
やり方その1
2画面目から戻る (遷移時と同様、GUIで設定)
19. 決定ボタンなどを追加したら、同様にCtrl + ドラッグで1画面目にドラッグする
20. 同様にIDを設定
やり方その2
2画面目から戻る (コードで記述)
// コードで戻る (返り値対応で、_をつけるらしい) / ボタン押下で戻る
@IBAction func returnButtonAction(sender: AnyObject) {
_ = navigationController?.popViewControllerAnimated(true)
}
とりあえず、これで行ったり来たりは出来るようになった...
参考
https://iphone-app-tec.com/ios/tap_gesture.html
2017年1月6日金曜日
2017年1月5日木曜日
jsonのdataを取得して解析する
urlからdataを取得する辺りから書くと下記のような感じ
class ViewController: UIViewController,NSXMLParserDelegate {
@IBOutlet weak var jsonTextView: UITextView!
@IBAction func Button_GetJson(sender: AnyObject) {
// let url:NSURL = NSURL(string: "http://editors.ascii.jp/c-minamoto/swift/swift-5-data.xml")!
// let request = NSURLRequest(URL: url)
//make URL of google feed api
let urlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml&num=8"
let url = NSURL(string: urlString)
// var titles:String = ""
//download by NSSession
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler:{data, response, error in
//convert json data to dictionary
var dict:NSDictionary
do {
dict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
//get responseData, feed, entries
let responseData = dict["responseData"] as! NSDictionary
let feed = responseData["feed"] as! NSDictionary
let entries = feed["entries"] as! NSArray
//extract entries
// print(entries.count)
var titles:String = ""
for entry in entries {
// print(entry["title"])
let title:String = entry["title"] as! String
titles += title + ":"
}
// print(titles)
dispatch_async(dispatch_get_main_queue()){
self.jsonTextView.text = titles
}
} catch {
print("error")
return
}
// print(dict)
})
task.resume()
// self.jsonTextView.text = titles
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
class ViewController: UIViewController,NSXMLParserDelegate {
@IBOutlet weak var jsonTextView: UITextView!
@IBAction func Button_GetJson(sender: AnyObject) {
// let url:NSURL = NSURL(string: "http://editors.ascii.jp/c-minamoto/swift/swift-5-data.xml")!
// let request = NSURLRequest(URL: url)
//make URL of google feed api
let urlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml&num=8"
let url = NSURL(string: urlString)
// var titles:String = ""
//download by NSSession
let task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler:{data, response, error in
//convert json data to dictionary
var dict:NSDictionary
do {
dict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
//get responseData, feed, entries
let responseData = dict["responseData"] as! NSDictionary
let feed = responseData["feed"] as! NSDictionary
let entries = feed["entries"] as! NSArray
//extract entries
// print(entries.count)
var titles:String = ""
for entry in entries {
// print(entry["title"])
let title:String = entry["title"] as! String
titles += title + ":"
}
// print(titles)
dispatch_async(dispatch_get_main_queue()){
self.jsonTextView.text = titles
}
} catch {
print("error")
return
}
// print(dict)
})
task.resume()
// self.jsonTextView.text = titles
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
2017年1月3日火曜日
jsonのdataをswift2で解析する
取得するデータの構造は
responseData:
feed:
value
feeUrl : "value"
... // *** 以下"キー:value"のメンバが続く
entries: // *** ここがおめあて
value配列
...
とした場合、以下コードで最終亭なentriesキーのvalue配列が取得できました。
var dict:NSDictionary
dict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
//get responseData, feed, entries
let responseData = dict["responseData"] as! NSDictionary // dictからresponseDataキーを探す
let feed = responseData["feed"] as! NSDictionary // responseData からfeedキーを探す
let entries = feed["entries"] as! NSArray // feedからentriesを探す..."entries"が配列として格納
entriesの配列の各titleを表示させる場合は以下になります。
//extract entries
// print(entries.count)
var titles:String = ""
for entry in entries {
// print(entry["title"])
let title:String = entry["title"] as! String
titles += title + ":"
}
// print(titles)
dispatch_async(dispatch_get_main_queue()){
self.jsonTextView.text = titles
}
responseData:
feed:
value
feeUrl : "value"
... // *** 以下"キー:value"のメンバが続く
entries: // *** ここがおめあて
value配列
...
とした場合、以下コードで最終亭なentriesキーのvalue配列が取得できました。
var dict:NSDictionary
dict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
//get responseData, feed, entries
let responseData = dict["responseData"] as! NSDictionary // dictからresponseDataキーを探す
let feed = responseData["feed"] as! NSDictionary // responseData からfeedキーを探す
let entries = feed["entries"] as! NSArray // feedからentriesを探す..."entries"が配列として格納
entriesの配列の各titleを表示させる場合は以下になります。
//extract entries
// print(entries.count)
var titles:String = ""
for entry in entries {
// print(entry["title"])
let title:String = entry["title"] as! String
titles += title + ":"
}
// print(titles)
dispatch_async(dispatch_get_main_queue()){
self.jsonTextView.text = titles
}
2017年1月2日月曜日
Jsonで取得したデータは??
いろいろなページを参考にさせていただき、swiftでjsonを取得できました。
順序が逆になりますが、「実際はどんな風になっているか」を先に見てみます。
おそらく、"[]"については見えていないので、解る部分を見てみます。
取得したデータを字下げすると..(あと、注釈を追記)
{"responseData": // *** ここのキーに対して、以下がvalueになる
{"feed": // *** ここのキーに対して、以下がvalueになる
{ "feedUrl":"http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml", // *** キーとvalueのペアが続く
"title":"ITmedia News 速報 最新記事一覧",
"link":"http://www.itmedia.co.jp/news/bursts/",
"author":"",
"description":"ITmedia News 速報 の最新記事一覧です。",
"type":"rss20",
"entries":[ // *** ここから"entries"キーに対するvalueの配列が続く
{ // *** "num=8"で要求したから? "entries"は8要素
"title":"Raspberry Piの「PIXEL」が旧型PCやMacで稼働可能に",
"link":"http://rss.rssad.jp/rss/artclk/XXtgw_wVjwMW/aa457f16b6ee2da4867bda91a84c3112?ul\u003dsWKI1zepQzDjpc7XC5rf2ewet1rxJmiV3BfQpFpgnr_Gr3.DNzTmu3CCs_zsy5TrxdEQvaf_o0e.p0eWYi3NUsxMHLApbJ70ELi0D_9ACLaN8lSZTT7.lFJN5cfjipmt5hi0Set",
"author":"",
"publishedDate":"Thu, 22 Dec 2016 14:18:00 -0800",
"contentSnippet":"小型コンピュータ「Raspberry Pi」のデスクトップ環境「PIXEL」のx86版が公開された。まだ実験的な段階だが、USBメモリに入れて起動ディスクとし、古いPCやMacでブートできる。\n",
"content":"\u003cp\u003e小型コンピュータ「Raspberry Pi」のデスクトップ環境「PIXEL」のx86版が公開された。まだ実験的な段階だが、USBメモリに入れて起動ディスクとし、古いPCやMacでブートできる。\n\u003cimg border\u003d\"0\" width\u003d\"1\" height\u003d\"1\" src\u003d\"http://rss.rssad.jp/rss/artimg/XXtgw_wVjwMW/aa457f16b6ee2da4867bda91a84c3112\"\u003e\u003c/p\u003e",
"categories":[]
}, // *** ここまでが"entries"キーに対するvalueの配列の一つ目、そして次のvalueが続く
...
まとめると、以下のような感じと思ってます
responseData:
feed:
value
feeUrl : "value"
... // *** 以下"キー:value"のメンバが続く
entries: // *** ここがおめあて
value配列
...
具体的にswiftで取得する方法は次回
順序が逆になりますが、「実際はどんな風になっているか」を先に見てみます。
おそらく、"[]"については見えていないので、解る部分を見てみます。
取得したデータを字下げすると..(あと、注釈を追記)
{"responseData": // *** ここのキーに対して、以下がvalueになる
{"feed": // *** ここのキーに対して、以下がvalueになる
{ "feedUrl":"http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml", // *** キーとvalueのペアが続く
"title":"ITmedia News 速報 最新記事一覧",
"link":"http://www.itmedia.co.jp/news/bursts/",
"author":"",
"description":"ITmedia News 速報 の最新記事一覧です。",
"type":"rss20",
"entries":[ // *** ここから"entries"キーに対するvalueの配列が続く
{ // *** "num=8"で要求したから? "entries"は8要素
"title":"Raspberry Piの「PIXEL」が旧型PCやMacで稼働可能に",
"link":"http://rss.rssad.jp/rss/artclk/XXtgw_wVjwMW/aa457f16b6ee2da4867bda91a84c3112?ul\u003dsWKI1zepQzDjpc7XC5rf2ewet1rxJmiV3BfQpFpgnr_Gr3.DNzTmu3CCs_zsy5TrxdEQvaf_o0e.p0eWYi3NUsxMHLApbJ70ELi0D_9ACLaN8lSZTT7.lFJN5cfjipmt5hi0Set",
"author":"",
"publishedDate":"Thu, 22 Dec 2016 14:18:00 -0800",
"contentSnippet":"小型コンピュータ「Raspberry Pi」のデスクトップ環境「PIXEL」のx86版が公開された。まだ実験的な段階だが、USBメモリに入れて起動ディスクとし、古いPCやMacでブートできる。\n",
"content":"\u003cp\u003e小型コンピュータ「Raspberry Pi」のデスクトップ環境「PIXEL」のx86版が公開された。まだ実験的な段階だが、USBメモリに入れて起動ディスクとし、古いPCやMacでブートできる。\n\u003cimg border\u003d\"0\" width\u003d\"1\" height\u003d\"1\" src\u003d\"http://rss.rssad.jp/rss/artimg/XXtgw_wVjwMW/aa457f16b6ee2da4867bda91a84c3112\"\u003e\u003c/p\u003e",
"categories":[]
}, // *** ここまでが"entries"キーに対するvalueの配列の一つ目、そして次のvalueが続く
...
まとめると、以下のような感じと思ってます
responseData:
feed:
value
feeUrl : "value"
... // *** 以下"キー:value"のメンバが続く
entries: // *** ここがおめあて
value配列
...
具体的にswiftで取得する方法は次回
2017年1月1日日曜日
jsonって??
最近はXMLからJSONに移行しつつあるそうです。
(SOAP->REST, XML->JSONなんですかね)
urlからデータを取得すると複雑な感じですが、基本は下記のような感じだそうです。
[
{
"番号":0,"タイトル":"とある本","ISBN":12345678
},
{
"番号":1,"タイトル":"次に読む本","ISBN":2345678, "ユーザ":["mr a", "mr b", "miss a"]
},
...
]
読み方は以下が基本のようです
{...} オブジェクトの表記(カッコ内がオブジェクト)
key:value ペアをコロンで記述する。ペアが複数ある場合はカンマで区切る << "メンバー"というようです
["value a", "value b", value c"] valueを配列で表すことができる
こちらのページが参考になりました
http://dev.classmethod.jp/etc/concrete-example-of-json/
(SOAP->REST, XML->JSONなんですかね)
urlからデータを取得すると複雑な感じですが、基本は下記のような感じだそうです。
[
{
"番号":0,"タイトル":"とある本","ISBN":12345678
},
{
"番号":1,"タイトル":"次に読む本","ISBN":2345678, "ユーザ":["mr a", "mr b", "miss a"]
},
...
]
読み方は以下が基本のようです
{...} オブジェクトの表記(カッコ内がオブジェクト)
key:value ペアをコロンで記述する。ペアが複数ある場合はカンマで区切る << "メンバー"というようです
["value a", "value b", value c"] valueを配列で表すことができる
こちらのページが参考になりました
http://dev.classmethod.jp/etc/concrete-example-of-json/
2016年12月31日土曜日
HP 210aで年賀状を印刷する 2017年版
今年も結局昨年と同様のスケジュール
なぜもっと早くできない!! の反省会
設定・手順は昨年版を参照(の方が詳しい)
レイヤーの写真を張り変えるテンプレ作業はいつもより早かったと思うが...やはりいろいろトラブルがあって大掃除しながら2.5日程度かかっている感じ
---
画像のリサイズ
0. お好みの写真を選択し、1071x832の縦横比でトリミング
1. 画像 -> 画像拡大縮小 で 1071x832
2. 画像 -> キャンバスサイズ で、↑になっていなければ同じサイズにする
こんな感じで行けたような...
---
画像をはがきテンプレに貼る
1. はがきテンプレとしたxcfのファイルを開く
2. ("レイヤー"ダイアログが表示されていない場合は、画像が出ているウィンドウの"ダイアログ -> レイヤー"を選択すると表示される)
3. 写真が表示されているレイヤーに、上記"画像のリサイズ"で作ったxcfをドラッグアンドドロップ
4. 古い写真レイヤーが表示されているが、不要なので削除
5. "The GIMP"ダイアログの移動アイコン(矢印の十字)を選択して、写真のレイヤーをつかんでよさそうな位置に移動する
---
レイヤーを重ねた上で、写真を鮮やかにしたい
1. "レイヤー"ダイアログで、写真を配置したレイヤーを選択
2. レイヤー -> 色 -> 色相・彩度で、彩度を思いっきり上げると派手な感じになってよさげ
---
印刷
- GIMPから印刷する
1. レイヤー -> 下のレイヤーと結合 を繰り返して、レイヤーを1枚にする
2. GIMPからファイル -> 印刷
3. プリンターを"ネットワーク"に設定(印刷する度にリセットされるようだ)
給紙トレイ : フォト
用紙サイズ : はがき
メディア : インクジェット紙
4. 詳細設定で
出力品質 : 高画質 にする
(ICMが"写真"になっていたりするのは"3"の設定で反映されている模様?)
フチあり印刷で良い
---
HP-209aはがきトレイ不具合
なかなか給紙しない -> 宛名面にそらせたり、給紙する際に押してやると有効
---
インク
- amazonで350円代で3本のが、一昨年とは別の店で売っているので、プリンタを動作確認してよさそうなら早めに買っておく
- で、28日くらいに注文すると、年明けになってしまうので、今年もあきらめ
- チェックすると 青・赤・黒(つまり黄色以外)がテスト印刷でカスレ始める
- 近所だと意外に高い(4000円程度)ので諦め
- 互換インクがあったので、4色買う (約3000円。ポイント使用)
実は、スーパーにもあって値段は一緒。バーゲンで5%オフならスーパー有利だが、
今回はipad買ったときのポイントで購入(他に購入予定のものもないし...)
- 結局黄色も途中で切れたので、よかったのだが... 黒が5枚程度の印刷でカスレる orz
- 古いカートリッジ(純正)につけかえると、いくらかましな印刷だったので、ヘッド目詰まりではなさそう
- 翌日(12/31)にお店で交換
- とりあえずこれで今回はなんとかなった (損失5枚)
インクは毎回もめる...
早めにプリンタのテストして、amazonで買っておくのがよさそうだ
(値段が全然違うので、不良品ならそこだけ純正買えばよいのだし)
なぜもっと早くできない!! の反省会
設定・手順は昨年版を参照(の方が詳しい)
レイヤーの写真を張り変えるテンプレ作業はいつもより早かったと思うが...やはりいろいろトラブルがあって大掃除しながら2.5日程度かかっている感じ
---
画像のリサイズ
0. お好みの写真を選択し、1071x832の縦横比でトリミング
1. 画像 -> 画像拡大縮小 で 1071x832
2. 画像 -> キャンバスサイズ で、↑になっていなければ同じサイズにする
こんな感じで行けたような...
---
画像をはがきテンプレに貼る
1. はがきテンプレとしたxcfのファイルを開く
2. ("レイヤー"ダイアログが表示されていない場合は、画像が出ているウィンドウの"ダイアログ -> レイヤー"を選択すると表示される)
3. 写真が表示されているレイヤーに、上記"画像のリサイズ"で作ったxcfをドラッグアンドドロップ
4. 古い写真レイヤーが表示されているが、不要なので削除
5. "The GIMP"ダイアログの移動アイコン(矢印の十字)を選択して、写真のレイヤーをつかんでよさそうな位置に移動する
---
レイヤーを重ねた上で、写真を鮮やかにしたい
1. "レイヤー"ダイアログで、写真を配置したレイヤーを選択
2. レイヤー -> 色 -> 色相・彩度で、彩度を思いっきり上げると派手な感じになってよさげ
---
印刷
- GIMPから印刷する
1. レイヤー -> 下のレイヤーと結合 を繰り返して、レイヤーを1枚にする
2. GIMPからファイル -> 印刷
3. プリンターを"ネットワーク"に設定(印刷する度にリセットされるようだ)
給紙トレイ : フォト
用紙サイズ : はがき
メディア : インクジェット紙
4. 詳細設定で
出力品質 : 高画質 にする
(ICMが"写真"になっていたりするのは"3"の設定で反映されている模様?)
フチあり印刷で良い
---
HP-209aはがきトレイ不具合
なかなか給紙しない -> 宛名面にそらせたり、給紙する際に押してやると有効
---
インク
- amazonで350円代で3本のが、一昨年とは別の店で売っているので、プリンタを動作確認してよさそうなら早めに買っておく
- で、28日くらいに注文すると、年明けになってしまうので、今年もあきらめ
- チェックすると 青・赤・黒(つまり黄色以外)がテスト印刷でカスレ始める
- 近所だと意外に高い(4000円程度)ので諦め
- 互換インクがあったので、4色買う (約3000円。ポイント使用)
実は、スーパーにもあって値段は一緒。バーゲンで5%オフならスーパー有利だが、
今回はipad買ったときのポイントで購入(他に購入予定のものもないし...)
- 結局黄色も途中で切れたので、よかったのだが... 黒が5枚程度の印刷でカスレる orz
- 古いカートリッジ(純正)につけかえると、いくらかましな印刷だったので、ヘッド目詰まりではなさそう
- 翌日(12/31)にお店で交換
- とりあえずこれで今回はなんとかなった (損失5枚)
インクは毎回もめる...
早めにプリンタのテストして、amazonで買っておくのがよさそうだ
(値段が全然違うので、不良品ならそこだけ純正買えばよいのだし)
2016年12月15日木曜日
タスクとUI表示 その1
(長い処理を行いたい場合など)Worker threadとUI threadの関係はやや面倒で、
- 描画はUI threadで行う
- UI threadで長い処理を行うと描画が固まる
- 長時間処理はworker threadで行えば画面固まらない
- でも描画はUI threadで行わないといけない
ということで、background workerだったり、invokeで描画させたりなど、昔から面倒だった訳ですが、最近?はasync/awaitが非同期処理の流行りのようです。
実験的に作ったアプリは
- 長時間処理用と仮定したtaskを生成する
- 上記taskから描画表示を行う
という処理を、async/awaitとinvokeを使って書いてみます。
formのデザイン画面には
- taskを開始するボタン
- 状態を表示するUIとしてtextbox
を配置します。
textboxでは、taskから1秒ごとに時間を表示させます。
taskが終了したらUI threadで"終了した"表示を行います。
表示部分のポイントは
textBox_dispTime.Invoke(new Action(() => { textBox_dispTime.Text = DateTime.Now.ToString(); }));
の部分で、
UI部品.Invoke(デリゲート);
という感じの模様。
これでtask側からtextBox_dispを操作する事ができました。
taskについてのポイントは
- await Task.Run(() => workThread()); として、awaitキーワードをつけたTask.Run()する
- awaitキーワードを使うメソッドには"async"キーワードを付ける
となり、動作としては、
- UIスレッドはawaitで待ち
- task側からUI(textBox)を操作
- workThread()が終了すると、その次のメソッド(UIスレッドからtextboxに"終了"を書く)実行
という感じでした。
ソースコード
using System.Threading;
namespace TestAwait01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// awaitキーワードを使うメソッドはasyncキーワードをつけておく
private async void button_TaskStart_Click(object sender, EventArgs e)
{
await Task.Run(() => workThread()); // workThreadの処理をtaskで実行
textBox_dispTime.Text = "終了";
}
// threadとして実行するメソッド
private void workThread()
{
for(int i = 0; i < 10; i++) {
// textBox_dispTime.Text = DateTime.Now.ToString(); // コレは表示されない
textBox_dispTime.Invoke(new Action(() => { textBox_dispTime.Text = DateTime.Now.ToString(); }));
Thread.Sleep(1000);
}
}
}
- 描画はUI threadで行う
- UI threadで長い処理を行うと描画が固まる
- 長時間処理はworker threadで行えば画面固まらない
- でも描画はUI threadで行わないといけない
ということで、background workerだったり、invokeで描画させたりなど、昔から面倒だった訳ですが、最近?はasync/awaitが非同期処理の流行りのようです。
実験的に作ったアプリは
- 長時間処理用と仮定したtaskを生成する
- 上記taskから描画表示を行う
という処理を、async/awaitとinvokeを使って書いてみます。
formのデザイン画面には
- taskを開始するボタン
- 状態を表示するUIとしてtextbox
を配置します。
textboxでは、taskから1秒ごとに時間を表示させます。
taskが終了したらUI threadで"終了した"表示を行います。
表示部分のポイントは
textBox_dispTime.Invoke(new Action(() => { textBox_dispTime.Text = DateTime.Now.ToString(); }));
の部分で、
UI部品.Invoke(デリゲート);
という感じの模様。
これでtask側からtextBox_dispを操作する事ができました。
taskについてのポイントは
- await Task.Run(() => workThread()); として、awaitキーワードをつけたTask.Run()する
- awaitキーワードを使うメソッドには"async"キーワードを付ける
となり、動作としては、
- UIスレッドはawaitで待ち
- task側からUI(textBox)を操作
- workThread()が終了すると、その次のメソッド(UIスレッドからtextboxに"終了"を書く)実行
という感じでした。
ソースコード
using System.Threading;
namespace TestAwait01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// awaitキーワードを使うメソッドはasyncキーワードをつけておく
private async void button_TaskStart_Click(object sender, EventArgs e)
{
await Task.Run(() => workThread()); // workThreadの処理をtaskで実行
textBox_dispTime.Text = "終了";
}
// threadとして実行するメソッド
private void workThread()
{
for(int i = 0; i < 10; i++) {
// textBox_dispTime.Text = DateTime.Now.ToString(); // コレは表示されない
textBox_dispTime.Invoke(new Action(() => { textBox_dispTime.Text = DateTime.Now.ToString(); }));
Thread.Sleep(1000);
}
}
}
登録:
投稿 (Atom)