ファイヤープロジェクト
マルチウィンドウ
2003-07-20T15:13+09:00   matsu
cursesでは複数のウィンドウを作成,操作できる.あとサブウィンドウも作成,操作できる.
cursesでは1つ以上のウィンドウがある.いいかえると必ずstdscrというウィンドウがある.ウィンドウはWINDOW構造体で,ウィンドウを作成,操作するにはこの構造体を作成,操作すればよい.もちろんstdscrもWINDOW構造体である.WINDOW構造体はプラットフォームによって実装が異なるかもしれないので,操作はcursesの関数を通して行なう.まず,WINDOW構造体の作成.
WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x);
nlines,ncolsは作成するウィンドウの行数と各行幅である.begin_y,begin_xは作成するウィンドウの左上の,画面(stdscr)における座標緒である.ウィンドウは画面からはみ出してはいけない.はみ出すようなパラメータを指定するとnewwinは失敗し,NULLを返す.次にWINDOW構造体を削除するには,
int delwin(WINDOW *win);
を使用する.stdscrをdelwinしてはいけない.そしてウィンドウの移動には
int mvwin(WINDOW *win, int y, int x);
を使用する.ここでもやはりウィンドウが画面からはみ出すようなパラメータを与えるとmvwinは失敗しERRを返す.
ウインドウ表示の更新には
int wrefresh(WINDOW *win);
を使用することは別の項で書いた.ここで問題なのは,最後にwrefreshしたウィンドウが一番手前に表示される(ように見える)ことである.したがって,確実にウィンドウ間の前後関係を保持して見せるには,奥に見せたいウィンドウから順番にwrefreshをしていく必要がある.ここで問題が二つある.一つ目はwrefreshをかけたときに,そのWINDOW構造体が更新されている部分を再表示するが,更新されていない部分は再表示しないという問題である.これはユーザが選択したウィンドウを手前に見せる際に不都合である.これに対処するための関数がある.
int touchwin(WINDOW *win);
これを実行すると,WINDOWS構造体全体に更新がかかっていることになる.touchコマンドみたいなもんだ.二つ目の問題はすべてのウィンドウを「実際に」再表示するのはコストが高く無駄であるという点である.これに対処するために以下の関数がある.
int wnoutrefresh(WINDOW *win);
これは指定したWINDOWS構造体に論理的にrefreshをかけるが画面には反映しない.複数のウィンドウにこの関数を実行し,最後に
int doupdate(void);
を実行することで,最終的に表示されるものだけを画面に表示することができる.これによって実際の画面の再表示のコストを最小限にできる.
複数のウィンドウを扱う(って程でもないが)サンプルを作成してみた.以下仕様.
  1. 起動時にウィンドウをランダムな位置に複数表示する.stdscrを除く各ウィンドウに0から始まる番号を振る.
  2. 一番手前のウィンドウでウィンドウ選択を促し入力を得る.
  3. 選択されたウィンドウを一番手前に表示する.'q'が入力されていれば終了する.
  4. 2に戻る.
サンプルからtouchwinを削除するとtouchwinの効果がよくわかった.
ここまでの複数のウィンドウは,物理画面内に収まってさえいればよく,ウィンドウ同士は独立していた.サブウィンドウはこれらのウィンドウとはちょっと違う.その違いを以下に示す.
  • 親ウィンドウとサブウィンドウは文字情報領域を共有する.
  • サブウィンドウを削除しても親ウィンドウは再度printwなどしないとサブウィンドウの文字が消えない.
  • 親ウィンドウを持ち,親ウィンドウ内に収まっていなければならない.
これらは結局一番最初の項目に起因するように見える.サブウィンドウは以下の関数で作成する.
WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x);
origは親ウィンドウを指定する.サブウィンドウを削除するには,通常通りdelwinでよい.サブウィンドウを再表示するには,
  1. 親ウィンドウでtouchwinする.
  2. refreshまたは,親かサブウィンドウでwrefreshする.
サブウィンドウを使用するサンプルを作成してみた.
このサンプルを実行することによって,親ウィンドウとサブウィンドウが文字情報領域を共有していることが分かる.すなわち親ウィンドウを"P"で埋めておいて,サブウィンドウを"S"で埋め,親ウィンドウを再表示してもサブウィンドウと共有している部分は"S"になっている.逆に親ウィンドウを"*"で埋めてしまうとサブウィンドウを再表示してもその領域は"*"になってしまう.
matsu(C)
Since 2002
Mail to matsu