C++游標定位函數詳解

2020-07-16 10:04:40
作業系統函數允許程式設計師對控制台螢幕上的輸出進行控制。

螢幕游標定位

C++ 編譯器提供了用於呼叫作業系統函數的特殊庫,現在來看一下 Windows 作業系統有關螢幕游標定位的函數,此函數是 SetConsoleCursorPosition。

作業系統函數是針對特定作業系統量身客製化的,所以使用它們的程式只能在它們被寫入的系統上執行。這裡描述的函數可以與 Windows 2000 以及更高版本的作業系統配合使用。

到目前為止,我們建立的所有程式都是在螢幕的頂行顯示輸出。然後,當使用者按確認鍵或程式輸出 endl 或“n”時,它們一次移動一行。但是,如果正在螢幕的第 5 行寫入內容,想要回到第 2 行該怎麼辦?或者,如果想在螢幕的正中間顯示某些東西該怎麼辦?要滿足這些要求,可以在 Windows 系統上使用 SetConsoleCursorPosition 函數,在寫入輸出之前將游標移動到所需位置。

要使用此函數,必須做以下幾件事情:
  • 在程式中新增 #include <windows.h>。
  • 通過在程式中包含以下定義,建立標準輸出螢幕的控制代碼:

    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);


典型的文字螢幕具有 25 行,每行具有 80 個列印位置。這些位置中的每一個稱為格。格是一個可以顯示單個字元的小塊,它可以通過行號及其在該行上的位置進行區別。行的範圍是 0?24,其中 0 是螢幕的頂行。每行上的列印位置通常被稱為列,範圍為 0?79,其中最左側為 0。格的行和列可以標識它在螢幕上的位置,它們稱為其坐標。

要將游標放在指定的螢幕格中,必須通過在 Windows 中定義的 COORD 結構中設定兩個變數來指定格坐標。這個結構有兩個名為 X 和 Y 的成員變數,X 儲存列位置,Y 儲存行位置。以下是該結構大致的樣子:
struct COORD
{
    short int X; // 列位置
    short int Y; // 行位置
};
現在來介紹其使用方法。以下程式碼段可以將單詞“Hello”寫入標準輸出螢幕的中心:
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
COORD position;    // position 是一個 COORD 結構
position.X = 38; //設定列在螢幕中心附近
position.Y = 11; //設定行在螢幕中心附近
//將游標放在那裡,然後開始列印
SetConsoleCursorPosition(screen, position);
cout << "Hello" << endl;
注意,在設定一個螢幕位置時,必須在程式的所有輸出後面都跟上 endl,這是確保輸出實際顯示在此位置的必要條件。如果不使用 endl,則在游標位置更改後,輸出可能會緩衝並在很久以後寫入螢幕。如果在輸出後面接著使用換行符“n”則不起作用,因為它不會像 endl 那樣沖刷螢幕緩衝區。

下面的程式定位游標以在螢幕中心附近顯示一組巢狀框:
#include <iostream>
#include <windows.h>
using namespace std;

void placeCursor(HANDLE, int, int);
void printStars (int);
int main()
{
    const int midRow = 12,midCol = 40, numBoxes = 3;
    int width, startRow, endRow;
    //Get the handle to standard output device (the console)
    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
    // Each loop prints one box
    for (int box = 1, height = 1; box <= numBoxes; box++, height+=2)
    {
        startRow = midRow - box;
        endRow = midRow + box;
        width = box*5 + (box+1)%2;// Adds 1 if box*5 is an even number
        //Draw box top
        placeCursor(screen, startRow, midCol-width/2);
        printStars(width);
        // Print box sides
        for (int sideRow = 1; sideRow <= height; sideRow++)
        {
            placeCursor(screen, startRow + sideRow, midCol-width/2);
            cout << '*' << endl;
            placeCursor(screen, startRow + sideRow,midCol+width/2);
            cout << '*' << endl;
        }
        // Draw box bottom
        placeCursor(screen, endRow, midCol-width/2);
        printStars(width);
        Sleep(750); //Pause 3/4 second between boxes displayed
    }
    placeCursor(screen, 20, 0); // Move cursor out of the way return 0;
}
void placeCursor(HANDLE screen, int row, int col)
{
    COORD position;
    position.Y = row;
    position.X = col;
    SetConsoleCursorPosition(screen, position);
}
void printStars(int numStars)
{
    for (int star = 1; star <= numStars; star++)
        cout << '*';
    cout << endl;
}
程式輸出結果:
***************
* *********** *
* *  *****  * *
* *  *   *  * *
* *  *****  * *
* *********** *
***************
請注意,此程式中使用了 Sleep 函數,它可以使程式執行暫停一段時間,所以它不會使事情發生得太快導致使用者看不到它們。傳遞給函數的實參告訴它應該暫停多少毫秒。毫秒是千分之一秒。因此,假如要暫停執行程式半秒鐘,則可以呼叫以下函數語句:

Sleep (500);

建立一個螢幕輸入表單

上面程式執行起來很有趣,但下面程式演示了將游標定位在螢幕上的更實際的應用。

當需要使用者輸入一系列條目時,不必每次提示一個輸入一個,而是可以設計一個螢幕輸入表單。這種更專業的從使用者獲得輸入的方式,需要建立和顯示一個介面,一次性顯示所有提示,然後將游標放置在需要使用者輸入的特定提示旁邊。當使用者輸入此提示的資料並按下確認鍵時,游標移動到下一個提示。
#include <iostream>
#include <windows.h> // Needed to set cursor positions
#include <string>
using namespace std;

struct userInfo
{
    string name;
    int age;
    char gender;
};

void placeCursor(HANDLE, int, int); // Function prototypes
void displayPrompts(HANDLE);
void getUserInput (HANDLE, userInfo&);
void displayData (HANDLE, userInfo);

int main()
{
    userInfo input;
    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
    displayPrompts(screen);
    getUserInput(screen, input);
    displayData (screen, input);
    return 0;
}
void placeCursor(HANDLE screen, int row, int col)
{
    COORD position;    // holds a pair of X and Y coordinates
    position.Y = row;
    position.X = col;
    SetConsoleCursorPosition(screen, position);
}
void displayPrompts(HANDLE screen)
{
    placeCursor(screen, 3, 25);
    cout << "******* Data Entry Form *******" << endl;
    placeCursor(screen, 5, 25);
    cout << "Name: " << endl;
    placeCursor(screen, 7, 25);
    cout <<"Age:       Gender (M/F) : " << endl;
}
void getUserInput(HANDLE screen, userInfo &input)
{
    placeCursor(screen, 5, 31);
    getline(cin, input.name);
    placeCursor(screen, 7, 30);
    cin >> input.age;
    placeCursor(screen, 7, 55);
    cin >> input.gender;
}
void displayData(HANDLE screen, userInfo input)
{
    placeCursor(screen, 10,0);
    cout<<"Here is the data you entered. n";
    cout<<"Name   : "<< input.name << endl;
    cout<<"Age   : "<< input.name << endl;
    cout<<"Gender : "<< input.name << endl;
}
程式輸出結果:

******* Data Entry Form *******
Name: Mary Beth Jones
Age: 19    Gender (M/F) :     F

Here is the data you entered.
Name   : Mary Beth Jones
Age   : Mary Beth Jones
Gender : Mary Beth Jones