web-dev-qa-db-ja.com

画面を継続的に更新してリアルタイムで更新する方法

Linuxで画面を継続的に更新してリアルタイムで更新するCプログラムを作成したい(たとえば、ターミナルのtopコマンドと同様)。誰かが私を正しい方向に向けることができますか?.

22
GP007

端末タイプ間で移植性を維持するには、 ncurses などのライブラリを使用する必要があります。そのリンクをチェックしてください。その完全なチュートリアルです。

画面の左上隅に増え続ける数字を印刷する基本的なプログラムは次のとおりです。

_#include <stdio.h>
#include <ncurses.h>

int main (void)

{
        /* compile with gcc -lncurses file.c */
        int c = 0;
        /* Init ncurses mode */
        initscr ();
        /* Hide cursor */
        curs_set (0);
        while (c < 1000) {
                /* Print at row 0, col 0 */
                mvprintw (0, 0, "%d", c++);
                refresh ();
                sleep (1);
        }
        /* End ncurses mode */
        endwin();
        return 0;
}
_

これがウィンドウを更新する方法です。ここで、topのようにデータの行を表示する場合、表示するデータは、順序付けられたデータ構造で維持する必要があります(データによっては、配列やリンクのような単純なものになる場合があります)リスト)。ロジックが指示するものに基づいてデータをソートし、clear()またはwclear()の後で(上記の例に示すように)ウィンドウに書き直す必要があります。

30
jman

Ncursesは進むべき道かもしれません。あなたがプログラムを言ったので、ncurses、c、c ++。それをすべて調べてください。しかし、「シェル」に関連した何かをするつもりなら、Perlを使ってください。

編集:私の要点を追加するために、ここにあなたにアイデアを与えることができるいくつかのモジュールがあります。

http://metacpan.org/pod/Curses::UI::Dialog::Progress

http://metacpan.org/pod/Smart::Comments

window.clrtobot()

そして、十分な対策として、ウィンドウ全体をクリアするためのcursesの呼び出し。

7
Sokel

xtermまたはVT100互換の場合は、 コンソールコード を使用できます。例:

#include <stdio.h>
#include <unistd.h> /* for sleep */

#define update() printf("\033[H\033[J")
#define gotoxy(x, y) printf("\033[%d;%dH", x, y)

int main(void)
{
    update();
    puts("Hello");
    puts("Line 2");
    sleep(2);
    gotoxy(0, 0);
    puts("Line 1");
    sleep(2);
    return(0);
}

ほとんどすべてをエスケープシーケンスで実行できますが、 wikipediaで指摘されているようにncursesは、リモートシェルを使用するときに発生するレイテンシを削減するために、画面の変更を最適化します。

7
David Ranieri

状況に応じて、コマンドラインで「watch」コマンドを使用して、topなどのクイックビューを取得できます。複数のコマンドを同時に監視することもできます。

例:

watch 'ls -l <somefile>; ps -fC <someprocess>; ./some_script'
5
gaijin

Ncursesライブラリを使用して画面処理を行うだけでなく、それを「継続的」かつ「リアルタイム」に更新したい場合は、おそらくタイマーと信号処理も調べたいと思うでしょう。 timer_create()およびtimer_settime()を使用すると、タイマーを開始できます。次に、sigaction()を使用して、ハンドラー関数を設定し、SIGALRMシグナルをトラップして、あなたの更新を行います。

編集:要求に応じて、ここにいくつかのサンプルコードがあります:

#define TIMESTEP 200000000

timer_t SetTimer(void) {
    struct itimerspec new_its;
    struct sigevent sevp;
    timer_t main_timer;

    sevp.sigev_notify = SIGEV_SIGNAL;
    sevp.sigev_signo = SIGALRM;
    timer_create(CLOCK_REALTIME, &sevp, &main_timer);

    new_its.it_interval.tv_sec = 0;
    new_its.it_interval.tv_nsec = TIMESTEP;
    new_its.it_value.tv_sec = 0;
    new_its.it_value.tv_nsec = TIMESTEP;

    timer_settime(main_timer, 0, &new_its, NULL);
    return main_timer;
}

void SetSignals(void) {
    struct sigaction sa;

    /*  Fill in sigaction struct  */

    sa.sa_handler = handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);

    /*  Set signal handler  */

    sigaction(SIGALRM, &sa, NULL);
}

void handler(int signum) {
    switch (signum) {
    case SIGALRM:
        update_stuff();    /*  Do your updating here  */
        break;
    }
}
3
Crowman

他の人が言ったように、あなたはおそらくncursesライブラリを見たいと思うでしょう。しかし、高度なフォーマットが必要ない場合は、おそらく次のような単純なもので十分です。

#include <stdio.h>
#include <unistd.h>

int main(void) {
    int number = 0;
    while (1) {
        ++number;
        printf("\rThe number is now %d.", number);
        fflush(stdout);
        sleep(1);
    }
    return 0;
}