HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2012
0922
CON擬似スクロールバーを作っているのですが・・・6未解決


CON

リンク

2012/9/22(Sat) 15:23:43|NO.49485

デザインを工夫したくて擬似スクロールバーを作りたいのですが
自分のスクリプトに無駄を感じてしまうので皆さんに改善していただきたいです。


x=6 //アイコンの横の数 ix=96 //アイコンの横幅 scx=15 //スクロールバーの幅 winx=640-scx //スクロールバーを除くウィンドウの横幅 winy=480 //ウィンドウの縦幅 spax=(winx-6*ix)/(x+1) //アイコンの横間隔 spay=15 //アイコンの縦間隔 pcs=300 //アイコンの数 num=pcs/x //縦列の数 //スクロールバーの↑↓ボタンの縦幅 scbut=(winy-2*scx)*((winy-2*scx)*100)/(num*(ix+spay))/100 //スクロールバーの↑↓ボタンのy座標(↑ボタン抜き) scpos=0 //アイコンだけをずらーっと並べるバッファ buffer 1,640,(ix+spay)*pcs repeat pcs/x //ずらーっと描画 pos 0,ix+spay gcopy 1,0,0,winx,(ix+spay)*lin repeat x i=cnt+1 color:boxf winx-(spax+ix)*i,spay,winx-(spax+ix)*i+ix,spay+ix pos winx-(spax+ix)*i,spay+3 color 255,255,255:mes 6*lin+i loop lin+=1 await 0 loop //メインウィンドウ screen 0,640,480 onclick gosub *onc color:boxf winx,0,winx+scx,winy gosub *draw color 255,255,255 gosub *onup:gosub *ondown:gosub *onbutton //ホイールの動きを監視するメインループ(?) repeat mw=mousew if mw!0{ scpos+=mw/-20 //ここは適当にしたので動くかどうか gosub *draw title "wheel "+scpos } wait 1 loop stop *onc mx=mousex:my=mousey if mx>(640-scx){ //マウスがスクロールバー内に入っていたら //マウスが↑ボタンを押したとき if my<scx{ color 0,255,255:gosub *onup repeat getkey key,1 if key=0:break scpos-=2 gosub *draw title "↑ "+scpos wait 1 loop color 255,255,255:gosub *onup } //マウスが↓ボタンを押したとき if my>(winy-scx){ color 0,255,255:gosub *ondown repeat getkey key,1 if key=0:break scpos+=2 gosub *draw title "↓ "+scpos wait 1 loop color 255,255,255:gosub *ondown } //マウスが↑↓ボタンを押したとき if my>(scx+scpos) and my<(scx+scpos+scbut){ my=my-scx-scpos repeat getkey key,1 if key=0:break scpos=mousey-my-scx gosub *draw title "↑↓ "+scpos wait 1 loop color 255,255,255:gosub *onbutton } }else{ //マウスがアイコンを押したとき if mx\(ix+spax)-spax>0 and (my+y)\(ix+spay)-spay>0{ //マウスの座標とscposからアイコンの番号を取得 title "hit "+(pcs-((my+y)/(ix+spay)*x)-mx/(ix+spax)) }else:title "out" } return *draw //画面の描画とスクロールバーの↑↓ボタンの描画 //---ここでscposの超えすぎを防ぐ if scpos<0:scpos=0 if scpos>(winy-scx*2-scbut):scpos=(winy-scx*2-scbut) y=scpos*(num*(ix+spay)-480+scx)/(winy-2*scx-scbut) redraw 0 color:boxf winx,scx,winx+scx,winy-scx color 0,255,255:gosub *onbutton pos 0,0:gcopy 1,0,y,640-scx,480+y redraw 1 return *onup //↑ボタンの再描画 boxf winx+1,1,winx+scx-2,scx-2 return *ondown //↓ボタンの再描画 boxf winx+1,winy-scx+1,winx+scx-2,winy-2 return *onbutton //↑↓ボタンの再描画 boxf winx+1,scx+scpos+1,winx+scx-2,scx+scpos+scbut-2 return

ためしに組んだスクリプトです

複数のボタンを扱うのにif文で個別に処理さしているので
その分無駄が多い気がします。

まだ初心者なのでどのように改善すれば良いが分かりません。

分かりにくいスクリプトだと思いますが、よろしくお願いします。



この記事に返信する


あり

リンク

2012/9/22(Sat) 15:56:49|NO.49486

ざっと見た感じでは無理に最適化させない方が
構造が理解しやすく応用させやすい様に私は感じます。

実際にプログラムに組み込む時の事を考えて
変数名を分かりやすくしたりモジュール化する程度でも
十分使えるものだと思います。



てん

リンク

2012/9/22(Sat) 16:04:05|NO.49487

よく作りこまれていてびっくり。
擬似コントロールを自作しようとすると、大抵想定外の操作に対応できなくてバグを起こすんですけど、そんなこともなく。

さて、

マウスが押されてから離れるまでの間、常にマウスのボタンの状態を監視しているため、
その他の処理が中断してしまいます。

HSPではマウスが押された時の処理をonclick命令で指定できますね。
これは、Windows側から「マウスが押されたぞ!」っていうお知らせ(ウィンドウメッセージ)が届いて、
それを受け取って処理をするというものなんですが、別にクリックに限らずWindowsからは大量にメッセージが届きます。

おそらく今回使えそうなメッセージは

WM_LBUTTONDOWN…マウスの左ボタンが下がった
WM_LBUTTONUP…マウスの左ボタンが上った
WM_MOUSEWHEEL…マウスのホイールが回転した

の3つだと思われます。

このメッセージがWindowsから届いた時だけ、処理をするように改良すると早くなると思われます。
詳しくは HSPヘルプから「oncmd」という命令を調べてみてください。

なお、メッセージは実際には上記の名前ではなく、数字で届きます。各メッセージがどのような値で届くのかは
「WM_LBUTTONDOWN msdn」などで検索するとすぐに見つかると思われます。






少し難しい話ですが、コントロールを作るときは
・各種イベント(マウスのボタンが下がった・上がった、ドラッグされた、etc...)の処理
が最大のポイントになってきます。

HSPではなく、他言語での開発の場合は「クリックされたらこの処理を呼び出してくれ!」と
予め、各種イベントが発生した際の処理を登録しておくことができます(コールバックといいます)

しかし残念ながら、HSPでは言語仕様上、部分的にしかこのコールバック処理を実装できません
(onkey, oncmd, onclickや、button命令のジャンプ先ラベル指定など)
基本的には、ウィンドウのみがメッセージを受け取れて、その他のコントロールは受け取れません。

たとえば、「テキストボックスのテキストの内容が変化したときに処理をする」などといった処理は
通常、無限ループで監視をするしか手がありません。

ですので、HSPで独自のコントロールを作ろうとした場合
今回のようにウィンドウに直接描く方法以外にも
①既存のコントロールをオーナードローすることで対処する
②もし、ゼロからつくるならbgscr命令で縁無しウィンドウを作り、子ウィンドウ化してコントロールとして使用する。

などの方法が考えられます。

①の場合は、本来Windows側に任せている、コントロールの描画を自分で行うというものです。
この方法の場合、デザインは変更できますが、機能は追加できません。
今回の例ですと、これだけでも要件を満たせそうな気はします。

②の方法は、HSPの「ウィンドウのみがウィンドウメッセージを受け取れる」という言語制約をむりやり突破したものです。
まだ詳しくないうちは特に知らなくてもいいでしょう。



CON

リンク

2012/9/22(Sat) 16:55:03|NO.49488

>>ありさん
自分の英単語力が無さ過ぎて
変数に適してる単語が出てこなくて適当につけちゃいました

たしかにこのままじゃ応用がしにくいですね・・・
ためしに別のプログラムに組み込んでみましたが大変でした;

モジュールについては勉強不足で
自分で作ったことは無いですが一度挑戦してみます

>>てんさん
いろいろ教えていただき、ありがとうございます。

ループで監視する必要の無いonclickやoncmd命令は便利だなと思っていたのですが
そんな便利なウィンドウメッセージが用意されていたんですね

Windowsでデスクトップ開発をする場合は知っておいたほうがよさそうですね

>①の場合は、本来Windows側に任せている、コントロールの描画を自分で行うというものです。
描画だけ自分で行うってことは、①の方法だとスクロールバーの幅が
個人の設定でそれぞれ違っていた場合デザインを統一しにくかったりしますか?

気になっていたのですが、ウェブブラウザのChromeのなどウィンドウは独自のデザインなのに
本物のウィンドウとまったく同じ様な動きをします。

これもその方法で実装されているのでしょうか。

②の方法は枠の無いウィンドウを個別に上に被せるって感じでしょうか
ってことは移動するたびに一緒に移動って感じでしょうか

理解力が無くてすみません;



てん

リンク

2012/9/22(Sat) 18:05:23|NO.49489

ごめんなさいorz
オーナードローはどうやらスクロールバーには実装されていないようです。
ボタンとかならあるんですけどね。
>気になっていたのですが、ウェブブラウザのChromeのなどウィンドウは独自のデザインなのに
>本物のウィンドウとまったく同じ様な動きをします。

>これもその方法で実装されているのでしょうか。

おそらく。
独自のクラスを作っているのではないかと思われます。

>②の方法は枠の無いウィンドウを個別に上に被せるって感じでしょうか
そのとおりです。ただ、かぶせるのではなく、子ウィンドウ化します。
要は、ボタンとかその他のコントロール同様、縁無しウィンドウを縁有りウィンドウの中にしまってしまうのです。
>ってことは移動するたびに一緒に移動って感じでしょうか
ウィンドウの中にしまってしまうので、ウィンドウを動かせばちゃんとついてきてくれますよ。
この方法だと、本来、onclick後にスクロールバーをクリックしたのか、それ以外なのか判定していた作業が不要になります。



CON

リンク

2012/9/23(Sun) 01:15:23|NO.49495

>>てんさん
>ごめんなさいorz
>オーナードローはどうやらスクロールバーには実装されていないようです。
オブジェクトなどを配置した画面をスクロールする予定ではないので
標準のスクロールバーがベースでなくても大丈夫です^^

>要は、ボタンとかその他のコントロール同様、縁無しウィンドウを縁有りウィンドウの中にしまってしまうのです。
そんなことが出来るのですね
実現するにはどのようなソースになるのでしょうか。

てんさんに教えて頂いたWM_MOUSEWHEELで常にホイールを監視する必要がなくなりました
WM_LBUTTONUPも使えそうだったのですが
ウィンドウ外でマウスが離れた場合対処できなかったので、そのままにしました

あとラベル型配列変数などを使いソースを少し短縮できました
(効率の良さは分かりませんが・・・


scSize=15 //スクロールバーの幅 Viewx=640-scSize //表示する横幅 Viewy=480 //表示する縦幅 iconSide=10 //アイコンの横の数 iconSize=48 //アイコンの大きさ iconNum=300 //アイコンの数(iconSideの倍数限定) Row=iconNum/iconSide //列の数 Spacey=15 //アイコンの縦間隔 Spacex=(Viewx-iconSide*iconSize)/(iconSide+1) //アイコンの横間隔 //スクロールバーの↑↓ボタンの縦幅 scTabSize=(Viewy-2*scSize)*((Viewy-2*scSize)*100)/(Row*(iconSize+Spacey))/100 //スクロールバーの↑↓ボタンの位置 scPos=120 //ホイールの増減量 wheel_Plus=5 ;配列ラベルの割り当て ldim redraw_, 3 redraw_(0)=*onup : redraw_(1)=*ondown : redraw_(2)=*onbutton //アイコンだけをずらーっと並べるバッファ buffer 1,Viewx,(iconSize+Spacey)*iconNum repeat iconNum/iconSide //ずらーっと描画 pos 0,iconSize+Spacey gcopy 1,0,0,Viewx,(iconSize+Spacey)*lin repeat iconSide i=cnt+1 color:boxf Viewx-(Spacex+iconSize)*i,Spacey,Viewx-(Spacex+iconSize)*i+iconSize,Spacey+iconSize pos Viewx-(Spacex+iconSize)*i,Spacey+3 color 255,255,255:mes iconSide*lin+i loop lin+=1 await 0 loop //メインウィンドウ screen 0,640,480 color:boxf dim on_Color,3 //↑↓ボタンの色 on_Color = 255,255,255 gosub *draw:gosub *onup:gosub *ondown:gosub *onbutton oncmd gosub *onc, 0x0201 oncmd gosub *wheel, 0x020A stop *onc xPos = lParam & 0xFFFF // カーソルx座標 yPos = (lParam >> 16) & 0xFFFF // カーソルy座標 if xPos>Viewx{ //マウスがスクロールバー内に入っていたら mode=2 //マウスが↑ボタンを押したとき if yPos<scSize:scplus=-2:mode=0 //マウスが↓ボタンを押したとき if yPos>(Viewy-scSize):scplus=2:mode=1 //マウスが↑↓ボタンを押したとき if yPos>(scSize+scPos) and yPos<(scSize+scPos+scTabSize):Clicky=yPos-scSize-scPos:on_Color = 0,255,255 gosub *click_loop on_Color = 255,255,255 }else{ //マウスがアイコンを押したとき if xPos\(iconSize+Spacex)-Spacex>0 and (yPos+drawy)\(iconSize+Spacey)-Spacey>0{ //マウスと表示している画面の座標からアイコンの番号を取得 title "hit "+(iconNum-((yPos+drawy)/(iconSize+Spacey)*iconSide)-xPos/(iconSize+Spacex)) }else:title "out" } return *click_loop color 0,255,255:gosub redraw_(mode) repeat getkey key,1:if key=0:break if mode==2{scPos=mousey-Clicky-scSize }else:scPos+=scplus gosub *draw:title "mode="+mode+" scPos="+scPos wait 1 loop color 255,255,255:gosub redraw_(mode) return *draw //画面の描画とスクロールバーの↑↓ボタンの描画 //---ここでscPosの超えすぎを防ぐ if scPos<0:scPos=0 if scPos>(Viewy-scSize*2-scTabSize):scPos=(Viewy-scSize*2-scTabSize) //表示するバッファのy座標 drawy=scPos*(Row*(iconSize+Spacey)-Viewy+scSize)/(Viewy-2*scSize-scTabSize) redraw 0 color:boxf Viewx,scSize,Viewx+scSize,Viewy-scSize color on_Color.0,on_Color.1,on_Color.2:gosub *onbutton pos 0,0:gcopy 1,0,drawy,Viewx,Viewy+drawy redraw 1 return *onup //↑ボタンの再描画 boxf Viewx+1,1,Viewx+scSize-2,scSize-2 return *ondown //↓ボタンの再描画 boxf Viewx+1,Viewy-scSize+1,Viewx+scSize-2,Viewy-2 return *onbutton //↑↓ボタンの再描画 boxf Viewx+1,scSize+scPos+1,Viewx+scSize-2,scSize+scPos+scTabSize-2 return *wheel //ホイールが回転したとき scPos+=wParam/(-7864320)*wheel_Plus gosub *draw return

それと変数名を分かりやすい名前に書き換えました
こういうときに「文字の置換」って便利な機能ですね;

あとはmouseyだとウィンドウからでると止まってしまうので
そこの修正と↑↓キーの対応とかですかね・・・

それが出来たら別のプログラムに組み込む予定でつ



初心者

リンク

2012/9/24(Mon) 18:22:16|NO.49525

テストage



ONION software Copyright 1997-2025(c) All rights reserved.