Lesson19 PoEdu培训第二课 C语言篇(11) 循环 随堂作业
文章类别: 培训作业 0 评论

Lesson19 PoEdu培训第二课 C语言篇(11) 循环 随堂作业

文章类别: 培训作业 0 评论

老师未批改

作业

完成如下程序题
#include <windows.h>

#define WINMAXIMUM 100
HWND g_hwnds[WINMAXIMUM] = { 0 };
int g_winnum = 0;

BOOL CALLBACK EnumWindowsProc(
    _In_ HWND   hwnd,
    _In_ LPARAM lParam) 
{
    char classname[MAXBYTE] = { 0 };
    GetClassNameA(hwnd, classname, MAXBYTE);
    if (strcmp("TXGuiFoundation", classname) == 0)
    {
        g_hwnds[g_winnum] = hwnd;
        g_winnum++;
    }
    return TRUE;
}

int main()
{
    EnumWindows(EnumWindowsProc, NULL);
    //每排3个窗口分4列排列

    //让所有窗口依次从左向右飞过
    
    //让所有窗口依次挨个从左向右飞过

    //让窗口排列成
    //*
    //**
    //***
    //**
    //*

    //让窗口排列成
    //                *
    //               **
    //              ***
    //               **
    //                *

    //让窗口分3行,每次每行飞入一个

    //模拟窗口反弹

    //将数组中奇数下标的窗口从下往上飞,偶数下标的窗口从上往下飞。每次都需要反弹效果

    return 0;
}

作答

程序代码如下:
#include <stdio.h>
#include <windows.h>
#include <shellapi.h>
#include <conio.h>

#define WINMAXIMUM 100

#define WINDOW_HEIGHT    180        // 窗口高度
#define WINDOW_WIDTH    300        // 窗口宽度
#define BORDER_PADDING    20        // 距离边界的长度
#define OUTPUT_LINE_MID    3        // 输出三角形的中间行数
#define MOVE_SPEED        10        // 窗口移动速度

HWND g_hwnds[WINMAXIMUM] = { 0 };
int g_winnum = 0;

RECT g_rect;    // 定义保存第一个启动的程序的大小, 在最后还原使用.

BOOL CALLBACK EnumWindowsProc(
    _In_ HWND   hwnd,
    _In_ LPARAM lParam)
{
    char classname[MAXBYTE] = { 0 };
    GetClassNameA(hwnd, classname, MAXBYTE);
    // if (strcmp("TXGuiFoundation", classname) == 0)
    if (strcmp("Notepad", classname) == 0)
    {
        g_hwnds[g_winnum] = hwnd;
        g_winnum++;
    }
    return TRUE;
}

BOOL MoveWindowSelf(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
{
    // 让窗口前置
    SetForegroundWindow(hWnd);
    // 移动窗口
    return MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
}

/************************************************************************/
/* 移动窗口, 从上至下                                                    */
/************************************************************************/
int MoveWindowTopToBottom(int iScHeight, int i)
{
    int iJumpTimes = 1;
    // 计算窗口的left位置 
    int iLeft = BORDER_PADDING;
    int iTop = BORDER_PADDING;

    _Bool bBottom = FALSE;
    int iMaxHeight = iScHeight - BORDER_PADDING - WINDOW_HEIGHT;

    while (bBottom ? iTop > iMaxHeight : iTop < iMaxHeight)
    {
        MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
        // 控制右移
        iLeft += 4;
        // 控制上移还是下移
        // 在到达底部之后需要上移, 在到达上边最高处后需要下移.
        if (bBottom)
        {
            iTop -= MOVE_SPEED;
        }
        else
        {
            iTop += MOVE_SPEED;
        }

        // 设置是否到达底部, 并设置此时的最高点
        if (!bBottom && iTop > iMaxHeight)
        {
            bBottom = TRUE;
            iMaxHeight = iScHeight - BORDER_PADDING - WINDOW_HEIGHT - iMaxHeight / (2 * iJumpTimes++);
        }

        // 判断是否到达最高点, 并还原最高点
        if (bBottom && iTop < iMaxHeight)
        {
            bBottom = FALSE;
            iMaxHeight = iScHeight - BORDER_PADDING - WINDOW_HEIGHT;
        }

        // 不能在弹了
        if (iMaxHeight < MOVE_SPEED) break;
        Sleep(10);
    }
    return 0;
}

/************************************************************************/
/* 移动窗口, 从下至上                                                    */
/************************************************************************/
int MoveWindowBottomToTop(int iScWidth, int iScHeight, int i)
{
    int iJumpTimes = 1;
    // 计算窗口的left位置 
    int iLeft = iScWidth - BORDER_PADDING - WINDOW_WIDTH;
    int iTop = iScHeight - BORDER_PADDING - WINDOW_HEIGHT;

    _Bool bTop = FALSE;
    int iMaxHeight = BORDER_PADDING;

    while (bTop ? iTop <= iMaxHeight : iTop >= iMaxHeight)
    {
        MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
        // 控制左移
        iLeft -= 3;
        // 控制上移还是下移
        // 在到达顶部之后需要下移, 在到达下边最高处后需要上移.
        if (bTop)
        {
            iTop += MOVE_SPEED;
        }
        else
        {
            iTop -= MOVE_SPEED;
        }

        // 设置是否到达顶部, 并设置此时的最高点
        if (!bTop && iTop < iMaxHeight)
        {
            bTop = TRUE;
            iMaxHeight = iScHeight / (2 * iJumpTimes++);
        }

        // 判断是否到达最高点, 并还原顶部
        if (bTop && iTop > iMaxHeight)
        {
            bTop = FALSE;
            iMaxHeight = BORDER_PADDING;
        }

        // 不能在弹了
        // if (iMaxHeight < MOVE_SPEED) break;
        Sleep(10);
    }
    return 0;
}

int main()
{
    //////////////////////////////////////////////////////////////////////////
    // 运行前的准备
    printf("运行前准备开始!\n");
    for (int i = 0; i < 12; i++)
    {
        ShellExecuteA(NULL, "open", "C:\\Windows\\System32\\notepad.exe", NULL, NULL, SW_SHOWNORMAL);
    }
    // 暂停2秒 防止运行缓慢不能获取到全部的窗口
    Sleep(2000);
    printf("运行前准备完成!\n");
    //////////////////////////////////////////////////////////////////////////

    EnumWindows(EnumWindowsProc, NULL);
    //////////////////////////////////////////////////////////////////////////
    // 公共用途
    printf("共找到窗口[%d]个!", g_winnum);

    // 获取屏幕分辨率
    int iScWidth = GetSystemMetrics(SM_CXSCREEN);
    int iScHeight = GetSystemMetrics(SM_CYSCREEN);

    // 设置窗口大小和窗口标题
    for (int i = 0; i < g_winnum; i++)
    {
        if (i == 0)
        {
            // 保存原始窗口大小, 做还原使用
            GetWindowRect(g_hwnds[i], &g_rect);
        }
        SetWindowPos(g_hwnds[i], NULL, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, SWP_NOMOVE);
        char strWindowTitle[20] = { '\0' };
        sprintf_s(strWindowTitle, 20, "花心胡萝卜 & %d", i);
        // 设置窗口标题
        SetWindowTextA(g_hwnds[i], strWindowTitle);
    }

    // 计算窗口的横向间隔
    int iLeftLen = (iScWidth - 2 * BORDER_PADDING) / 3;
    // 计算窗口的纵向间隔
    int iTopLen = (iScHeight - 2 * BORDER_PADDING) / 4;

    //////////////////////////////////////////////////////////////////////////
    
    printf("按下任意键进行窗口4行3列排列!\n");
    _getch();

    /////////////////////////////////////////////////////////////////////////
    // 每排4个窗口分3列排列;
    // 开始进行排列
    printf("开始进行排列, 每排4个窗口, 一共3排.\n");
    for (int i = 0; i < g_winnum; i++)
    {
        // 计算窗口的left位置
        int iLeft = BORDER_PADDING + iLeftLen * (i % 3);
        int iTop = BORDER_PADDING + iTopLen * (i % 4);
        MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
        Sleep(100);
    }
    //////////////////////////////////////////////////////////////////////////

    printf("按下任意键进开始让所有窗口依次从左向右飞过!\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //让所有窗口依次从左向右飞过
    printf("开始让所有窗口依次从左向右飞过!\n");
    for (int i = 0; i < g_winnum; i++)
    {
        // 计算窗口的left位置
        int iLeft = BORDER_PADDING;
        int iTop = BORDER_PADDING;
        MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
        while (iLeft < iScWidth - 2 * BORDER_PADDING - WINDOW_WIDTH)
        {
            MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
            iLeft += MOVE_SPEED;
            Sleep(10);
        }
    }
    //////////////////////////////////////////////////////////////////////////

    printf("按下任意键进开始让所有窗口依次从右向左飞过!\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //让所有窗口依次挨个从左向右飞过
    printf("开始让所有窗口依次从左向右飞过!\n接下来开始列队~");

    for (int i = g_winnum - 1; i >= 0; i--)
    {
        MoveWindowSelf(g_hwnds[i], 0 - WINDOW_WIDTH, BORDER_PADDING, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
    }
    printf("列队完成!开始飞入~~~\n");
    // 计算窗口的left位置
    int iLeft = 0 - WINDOW_WIDTH;
    int iTop = BORDER_PADDING;

    while (iLeft < iScWidth - BORDER_PADDING - WINDOW_WIDTH)
    {
        for (int i = 0; i < g_winnum; i++)
        {
            // 这里不再进行窗口焦点前置, 因为会盖住前边的窗口很不好看
            MoveWindow(g_hwnds[i], iLeft - BORDER_PADDING * i, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
        }
        iLeft += MOVE_SPEED;
        //Sleep(10);
    }
    
    //////////////////////////////////////////////////////////////////////////
    
    printf("按下任意键进开始让窗口排列为以下形状:\n");
    printf("*\n");
    printf("**\n");
    printf("***\n");
    printf("**\n");
    printf("*\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //让窗口排列成
    //*
    //**
    //***
    //**
    //*

    printf("开始让窗口排列为以下形状:\n");
    printf("*\n");
    printf("**\n");
    printf("***\n");
    printf("**\n");
    printf("*\n");

    int iIndex = 0;
    int iLineNumReal = 0;
    _Bool bMid = FALSE;

    for (int iLineNum = 0; iLineNum < OUTPUT_LINE_MID; bMid ? iLineNum-- : iLineNum++, iLineNumReal++)
    {
        if (iIndex + 1 > g_winnum) break;
        if (iLineNum < 0) break;
        if (iLineNumReal == OUTPUT_LINE_MID - 1) bMid = TRUE;

        for (int iColNum = 0; iColNum < iLineNum + 1; iColNum++)
        {
            // 计算窗口的left位置
            int iLeft = BORDER_PADDING + iLeftLen * iColNum;
            int iTop = BORDER_PADDING + iTopLen * iLineNumReal;

            if (iIndex + 1 > g_winnum) break;
            MoveWindowSelf(g_hwnds[iIndex++], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);

            Sleep(100);
        }
    }

    printf("隐藏多余的窗口!\n");
    for (int i = iIndex; i < g_winnum; i++)
    {
        ShowWindow(g_hwnds[i], SW_HIDE);
    }

    //////////////////////////////////////////////////////////////////////////

    printf("按下任意键进开始让窗口排列为以下形状:\n");
    printf("       *\n");
    printf("      **\n");
    printf("     ***\n");
    printf("      **\n");
    printf("       *\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //让窗口排列成
    //                *
    //               **
    //              ***
    //               **
    //                *

    for (int i = iIndex; i < g_winnum; i++)
    {
        ShowWindow(g_hwnds[i], SW_SHOWNORMAL);
    }

    printf("开始让窗口排列为以下形状:\n");
    printf("       *\n");
    printf("      **\n");
    printf("     ***\n");
    printf("      **\n");
    printf("       *\n");

    iIndex = 0;
    iLineNumReal = 0;
    bMid = FALSE;

    for (int iLineNum = 0; iLineNum < OUTPUT_LINE_MID; bMid ? iLineNum-- : iLineNum++, iLineNumReal++)
    {
        if (iIndex + 1 > g_winnum) break;
        if (iLineNum < 0) break;
        if (iLineNumReal == OUTPUT_LINE_MID - 1) bMid = TRUE;

        for (int iColNum = 0; iColNum < iLineNum + 1; iColNum++)
        {
            // 计算窗口的left位置
            int iLeft = iScWidth - (BORDER_PADDING + WINDOW_WIDTH) * (iColNum + 1);
            int iTop = BORDER_PADDING + iTopLen * iLineNumReal;

            if (iIndex + 1 > g_winnum) break;
            MoveWindowSelf(g_hwnds[iIndex++], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);

            Sleep(100);
        }
    }

    printf("隐藏多余的窗口!\n");
    for (int i = iIndex; i < g_winnum; i++)
    {
        ShowWindow(g_hwnds[i], SW_HIDE);
    }
    
    //////////////////////////////////////////////////////////////////////////

    printf("按下任意键开始让窗口分为3行, 每次飞入一个!\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //让窗口分3行,每次每行飞入一个

    for (int i = iIndex; i < g_winnum; i++)
    {
        ShowWindow(g_hwnds[i], SW_SHOWNORMAL);
    }

    printf("开始让窗口分为3行, 每次飞入一个!\n");
    for (int i = 0; i < g_winnum; i++)
    {
        // 计算窗口的left位置 
        int iLeft = 0 - WINDOW_WIDTH;
        int iTop = BORDER_PADDING + iTopLen * (i / 4);
        MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);

        while (iLeft < BORDER_PADDING * (i % 4 + 1) + WINDOW_WIDTH * (i % 4))
        {
            MoveWindowSelf(g_hwnds[i], iLeft, iTop, WINDOW_WIDTH, WINDOW_HEIGHT, TRUE);
            iLeft += MOVE_SPEED;
            Sleep(10);
        }
    }
    //////////////////////////////////////////////////////////////////////////
    
    printf("按下任意键模拟窗口反弹!\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //模拟窗口反弹
    printf("模拟窗口反弹!\n");
    printf("所有窗口初始位置!\n");
    for (int i = 0; i < g_winnum; i++)
    {
        SetWindowPos(g_hwnds[i], NULL, BORDER_PADDING, BORDER_PADDING, 0, 0, SWP_NOSIZE);
    }
    
    for (int i = 0; i < g_winnum; i++)
    {
        MoveWindowTopToBottom(iScHeight, i);
    }
    //////////////////////////////////////////////////////////////////////////

    printf("按下任意键将数组中奇数下标的窗口从下往上飞,偶数下标的窗口从上往下飞。每次都需要反弹效果!\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    //将数组中奇数下标的窗口从下往上飞,偶数下标的窗口从上往下飞。每次都需要反弹效果
    printf("将数组中奇数下标的窗口从下往上飞,偶数下标的窗口从上往下飞。每次都需要反弹效果!\n");
    printf("所有窗口初始位置!\n");
    for (int i = 0; i < g_winnum; i++)
    {
        if (i % 2 == 0)
        {
            SetWindowPos(g_hwnds[i], NULL, BORDER_PADDING, BORDER_PADDING, 0, 0, SWP_NOSIZE);
        }
        else 
        {
            SetWindowPos(g_hwnds[i], NULL, iScWidth - BORDER_PADDING - WINDOW_WIDTH, iScHeight - BORDER_PADDING - WINDOW_HEIGHT, 0, 0, SWP_NOSIZE);
        }
    }

    for (int i = 0; i < g_winnum; i++)
    {
        if (i % 2 == 0)
        {
            MoveWindowTopToBottom(iScHeight, i);
        }
        else
        {
            MoveWindowBottomToTop(iScWidth, iScHeight, i);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    
    printf("按下任意键退出程序!\n");
    _getch();

    //////////////////////////////////////////////////////////////////////////
    // 清理工作
    for (int i = 0; i < g_winnum; i++)
    {
        // DWORD pidWindow;
        // 通过窗口句柄找到进程pid
        // GetWindowThreadProcessId(g_hwnds[i], &pidWindow);
        // 还原原始位置和大小
        SetWindowPos(g_hwnds[i], NULL, g_rect.left, g_rect.top, 
            g_rect.right - g_rect.left, g_rect.bottom - g_rect.top, SWP_SHOWWINDOW);
        PostMessage(g_hwnds[i], WM_CLOSE, 0, 0);
    }

    //////////////////////////////////////////////////////////////////////////
    return 0;
}

运行效果(运行效果是动态图, 67+MB, 如不能观看, 可右键点击我选择另存为后观看):
Alt 运行效果

如有错误,请提出指正!谢谢.

回复