0から始めるVisualStudio2022:ソフト開発塾

今回、スクロールバーを表示してみる。
いつものように
『ファイル』『追加』『新しいプロジェクト』
C++の空のプロジェクトを選んで
sample008のプロジェクトを作成
sample008を『プロジェクト』『スタートアッププロジェクトに設定』で変更しておく
sample006のプロジェクトのソースファイル sample006.cpp を、コピー
sample008のプロジェクトのソースファイルに、貼り付け
名前の変更、sample006.cpp から sample008.cppにする。
『プロジェクト』『プロパティ』の「リンカー」「システム」
サブシステムを「コンソール」から「Windows」に変える
ソースの CreateWindowEx を修正
   HWND hWnd = CreateWindowEx(
      WS_EX_OVERLAPPEDWINDOW,
      szWindowClass,
      szTitle,
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT,
      500, 100,
      NULL,
      NULL,
      hInstance,
      NULL
   );
から、WS_VSCROLL | WS_HSCROLL を追加する。
   HWND hWnd = CreateWindowEx(
      WS_EX_OVERLAPPEDWINDOW,
      szWindowClass,
      szTitle,
      WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,   // ここに追加
      CW_USEDEFAULT, CW_USEDEFAULT,
      500, 100,
      NULL,
      NULL,
      hInstance,
      NULL
   );
WS_VSCROLL | WS_HSCROLL を追加するだけ、表示自体はできるが、
機能はしない。
テキストのスクロールの例が
https://learn.microsoft.com/ja-jp/windows/win32/controls/scroll-text-in-scroll-bars
にあったので、これを参考に修正、その前に、テキストのスクロールの例の解説。
WM_CREATE で、なにをやっているか?
(平均の)キャラクタサイズ(文字のサイズ)を、取得・変数に保管。
WM_SIZE で、なにをやっているか?
変更されたWINDOWのサイズから、縦・横 それぞれのスクロールバーの設定
・最大値
・ページ移動サイズ
WM_HSCROLL(WM_VSCROLL)で、なにをやっているか?
LOWORD (wParam)のモードによって、ポジション(位置)の変更を設定
WM_PAINT で、なにをやっているか?
当然、文字表示。
スクロールバーの設定値(GetScrollInfo)から、取得して表示位置を決定している。
で、本来の sample008.cpp の修正
WndProc の、switch case 追加(修正)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    static int xChar;       // horizontal scrolling unit 
    static int yChar;       // vertical scrolling unit 

    switch (message)   {
    case WM_CREATE:
        proc_wm_create(hWnd, &xChar, &yChar);
        return 0;
    case WM_SIZE:
        proc_wm_size(hWnd, lParam, xChar, yChar);
        return 0;
    case WM_HSCROLL:	// 水平スクロール バー
        proc_wm_hscroll(hWnd, wParam, xChar);
        return 0;
    case WM_VSCROLL:	// 垂直スクロール バー
        proc_wm_vscroll(hWnd, wParam, yChar);
        return 0;
    case WM_PAINT:
        int yPos, xPos;
        SCROLLINFO si;
        // Get vertical scroll bar position.
        si.cbSize = sizeof(si);
        si.fMask = SIF_POS;
        GetScrollInfo(hWnd, SB_VERT, &si);
        yPos = si.nPos;

        // Get horizontal scroll bar position.
        GetScrollInfo(hWnd, SB_HORZ, &si);
        xPos = si.nPos;

        sample_text_print(hWnd,-xPos * xChar,-yPos * yChar);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }
    return 0;
}
として、各関数は、次の通り
void proc_wm_create(HWND hwnd,
    int* ptr_xChar,
    int* ptr_yChar) {

    TEXTMETRIC tm;
    static int xUpper;      // average width of uppercase letters 

    HDC hdc;
    // Get the handle to the client area's device context. 
    hdc = GetDC(hwnd);

    // Extract font dimensions from the text metrics. 
    GetTextMetrics(hdc, &tm);
    *ptr_xChar = tm.tmAveCharWidth;
    xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * (*ptr_xChar) / 2;
    *ptr_yChar = tm.tmHeight + tm.tmExternalLeading;

    // Free the device context. 
    ReleaseDC(hwnd, hdc);
}

void proc_wm_size(HWND hwnd, LPARAM lParam , int xChar, int yChar) {
    static int xClient;     // width of client area 
    static int yClient;     // height of client area 
    // Retrieve the dimensions of the client area. 
    yClient = HIWORD(lParam);
    xClient = LOWORD(lParam);

    SCROLLINFO si;
    // Set the vertical scrolling range and page size
    si.cbSize = sizeof(si);
    si.fMask = SIF_RANGE | SIF_PAGE;
    si.nMin = 0;
    si.nMax = 1024;			// サンプルのため適当なMAX値
    si.nPage = yClient / yChar;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

    // Set the horizontal scrolling range and page size. 
    si.cbSize = sizeof(si);
    si.fMask = SIF_RANGE | SIF_PAGE;
    si.nMin = 0;
    si.nMax = 2 + 500;			// サンプルのため適当なMAX値
    si.nPage = xClient / xChar;
    SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
}

int proc_wm_scroll(HWND hwnd, WPARAM wParam, int nBar) {
    SCROLLINFO si;
    // Get all the vertial scroll bar information.
    si.cbSize = sizeof(si);
    si.fMask = SIF_ALL;

    // Save the position for comparison later on.
    GetScrollInfo(hwnd, nBar, &si);

    int mmPos;        // current horizontal scrolling position 
    mmPos = si.nPos;
    switch (LOWORD(wParam)) {
        // User clicked the left arrow.
    case SB_LINELEFT:
        // User clicked the top arrow.
//    case SB_LINEUP:
        si.nPos -= 1;
        break;
        // User clicked the right arrow.
    case SB_LINERIGHT:
        // User clicked the bottom arrow.
//    case SB_LINEDOWN:
        si.nPos += 1;
        break;
        // User clicked the scroll bar shaft left of the scroll box.
    case SB_PAGELEFT:
        // User clicked the scroll bar shaft above the scroll box.
//    case SB_PAGEUP:
        si.nPos -= si.nPage;
        break;
        // User clicked the scroll bar shaft right of the scroll box.
    case SB_PAGERIGHT:
        // User clicked the scroll bar shaft below the scroll box.
//    case SB_PAGEDOWN:
        si.nPos += si.nPage;
        break;
        // User dragged the scroll box.
    case SB_THUMBTRACK:
        si.nPos = si.nTrackPos;
        break;

    default:
        break;
    }
    // Set the position and then retrieve it.  Due to adjustments
    // by Windows it may not be the same as the value set.
    si.fMask = SIF_POS;
    SetScrollInfo(hwnd, nBar, &si, TRUE);
    return mmPos;
}
//  
void proc_wm_hscroll(HWND hwnd, WPARAM wParam, int xChar) {
    static int xPos;        // current horizontal scrolling position 
    xPos=proc_wm_scroll(hwnd, wParam, SB_HORZ);
    SCROLLINFO si;
    GetScrollInfo(hwnd, SB_HORZ, &si);

    // If the position has changed, scroll the window.
    if (si.nPos != xPos) {
        ScrollWindow(hwnd, xChar * (xPos - si.nPos), 0, NULL, NULL);
    }
}
// 
void proc_wm_vscroll(HWND hwnd, WPARAM wParam, int yChar) {
    static int yPos;        // 
    yPos = proc_wm_scroll(hwnd, wParam, SB_VERT);
    SCROLLINFO si;
    GetScrollInfo(hwnd, SB_VERT, &si);

    // If the position has changed, scroll window and update it.
    if (si.nPos != yPos) {
        ScrollWindow(hwnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
    }
}
表示処理は、表示位置補正を追加
void sample_text_print(HWND hWnd,int mp_xx,int mp_yy) {
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    TextOutA(hdc, mp_xx, mp_yy, "SAMPLE008", 9);
    TextOutA(hdc, mp_xx, 200+mp_yy, "SAMPLE008", 9);
    TextOutA(hdc, 100+mp_xx, 250 + mp_yy, "SAMPLE008", 9);
    EndPaint(hWnd, &ps);
}






Top