1兰亭序 发表于 2015-3-10 21:40:58

求助 windows窗口标题菜单和右键菜单问题

我用GetSystemMenu获得系统菜单,用点击右键弹出,处理WM_SYSCOMMAND消息 。标题菜单用WM_COMMAND处理。两个东西分开都没问题,放在一起时右键菜单没问题,但是标题菜单点击没反应。大神告诉下怎么处理才能让标题菜单有反应,,谢谢

freeparty 发表于 2015-3-11 15:37:42

楼主可以让我们看下窗口过程的代码吗?

1兰亭序 发表于 2015-3-11 16:06:33

freeparty 发表于 2015-3-11 15:37
楼主可以让我们看下窗口过程的代码吗?

#include<Windows.h>
#include<math.h>
#include"resource.h"

#define ID_TIME 1
#define ID_TOP100
#define ID_HELP 101

LRESULT CALLBACK MainWndProc(HWND vHwnd, UINT vMsg, WPARAM wParam, LPARAM lParam);
void drawClockFace(HDC vHdc);//绘制时钟的外观
void setCoordinate(HDC vHdc, int vX, int vY);//设置笛卡尔坐标系
void setFont(HDC vHdc, HFONT *vFont, int vFontBig);//设置字体大小
void drawHand(HDC vHdc, int vLength, int vWidth, int vDegrees, COLORREF vColor);

int APIENTRY WinMain(HINSTANCE hInstance,
                                       HINSTANCE hPreInstance,
                                       LPSTR lpCmdLine,
                                       int nCmdShow)
{
        char ClassName[] = "MainWinClass";
        WNDCLASSEX wndClass;
        // 用描述主窗口的参数填充 WNDCLASSEX 结构
        wndClass.cbSize = sizeof(wndClass);// 结构的大小
        wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// 指定如果大小改变就重画
        //CS_OWNDC让Windows 将每次对DC的设置都保存下来
        wndClass.cbClsExtra = 0;// 没有额外的类内存
        wndClass.cbWndExtra = 0;// 没有额外的窗口内存
        wndClass.lpfnWndProc = MainWndProc;// 窗口函数指针
        wndClass.hInstance = hInstance;// 实例句柄
        wndClass.hIcon = ::LoadIcon(hInstance, (LPSTR)ID_CLOCKICON1);// 使用预定义图标
        wndClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);//使用预定义的光标
        wndClass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);// 使用白色背景画刷
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = ClassName;// 窗口类的名称
        wndClass.hIconSm = NULL;//没有类的小图标

        // 注册这个窗口类
        ::RegisterClassEx(&wndClass);

        //创建主窗口
        HWND hwnd = ::CreateWindowEx(
                0,                                        // dwExStyle,扩展样式
                ClassName,                        // lpClassName,类名
                "时钟", //lpWindowName,标题
                WS_OVERLAPPEDWINDOW,//dwStyle,窗口风格
                CW_USEDEFAULT,                // X,初始 X 坐标
                CW_USEDEFAULT,                //Y,初始 Y 坐标
                500,                // nWidth,宽度
                500,                //nHeight,高度
                NULL,                                // hWndParent,父窗口句柄
                NULL,                                //hMenu,菜单句柄
                hInstance,                        //hlnstance,程序实例句柄
                NULL                                // lpParam,用户数据
                );
        if (hwnd == NULL)
        {
                ::MessageBox(NULL, "创建窗口出错! ", "error", MB_OK);
                return -1;
        }


        // 显示窗口,刷新窗口客户区
        ::ShowWindow(hwnd, SW_SHOWNORMAL);
        ::UpdateWindow(hwnd);


        // 从消息队列中取出消息,交给窗口函数处理,直到 GetMessage 返回 FALSE,结束消息循环
        MSG msg;

        while(::GetMessage(&msg, NULL, 0, 0))
        {
                // 转化键盘消息
                ::TranslateMessage(&msg);
                // 将消息发送到相应的窗口函数
                ::DispatchMessage(&msg);
        }
        // 当 GetMessage 返回 FALSE 时程序结束

        return msg.wParam;
}

//******************************************************************
//FUNCTION:
LRESULT CALLBACK MainWndProc(HWND vHwnd, UINT vMsg, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        HFONT hFont;//字体句柄

        //上一次 Windows通知时的时间
        static int PreHour;
        static int PreMinute;
        static int PreSecond;
        //窗口客户区的大小
        static int xClient;
        static int yClient;
        //是否位于最顶层
        static BOOL FlagTop;

        switch (vMsg)
        {
        case WM_CREATE:
                //在窗口刚被创建,即接受到 WM_CREATE消息的时候,要初始化全局变量的值,并安装定时器。
                {
                        HMENU hmenu;
                        hmenu = ::LoadMenu((HINSTANCE)::GetWindowLongPtr(vHwnd, GWL_HINSTANCE), MAKEINTRESOURCE(ID_CLOCK));
                        SetMenu(vHwnd, hmenu);

                        //设置字体
                        hdc = ::BeginPaint(vHwnd, &ps);
                        setFont(hdc, &hFont, 30);

                        // 向系统菜单中添加自定义的项
                        HMENU sysMenu;
                        sysMenu = ::GetSystemMenu(vHwnd, false);
                        ::AppendMenu(sysMenu, MF_SEPARATOR, 0, NULL);
                        ::AppendMenu(sysMenu, MF_STRING, ID_TOP, "总在最前");
                        ::AppendMenu(sysMenu, MF_STRING, ID_HELP, "帮助");

                        //设置时间
                        SYSTEMTIME time;
                        ::GetLocalTime(&time);
                        PreHour   = time.wHour;
                        PreMinute = time.wMinute;
                        PreSecond = time.wSecond;

                        //创建定时器
                        ::SetTimer(vHwnd, ID_TIME, 1000, NULL);
                       
                        break;
                }

        case WM_SIZE:
                {
                        xClient = LOWORD(lParam);
                        yClient = HIWORD(lParam);
                        break;
                }

        case WM_PAINT:
                {
                        // 使无效的客户区变的有效,并取得设备环境句柄
                        hdc = ::BeginPaint(vHwnd, &ps);

                        //::GetClientRect(vHwnd, &Rect);
                        setCoordinate(hdc, xClient, yClient);//设置坐标系
                        drawClockFace(hdc);//绘制时钟外观

                        //绘制指针
                        //经过 1 个小时时针走30 度(360/12 ),经过 1 分钟时针走0.5度(30/60)
                        drawHand(hdc, 200, 8, (PreHour*30 + PreMinute/2), RGB(0,0,0));
                        //经过 1 分钟分针走6 度(360/60 )
                        drawHand(hdc, 400, 6, PreMinute*6, RGB(10,0,0));
                        //经过 1 秒钟秒针走6 度(360/60 )
                        drawHand(hdc, 400, 4, PreSecond*6, RGB(10,10,0));

                        ::EndPaint(vHwnd, &ps);
                        break;
                }

                case WM_COMMAND://菜单响应
                {
                        switch (LOWORD(wParam))
                        {
                        case ID_INFO:
                                {
                                        ::SendMessage(vHwnd, WM_CLOSE, 0, 0);
                                        break;
                                }
                        case ID_HELLO:
                                {
                                        int MsgBox = ::MessageBox(vHwnd, "hello world", "问好", MB_YESNO | MB_DEFBUTTON2);
                                        break;
                                }
                        default:
                                break;
                        }
                        break;
                }

        case WM_TIMER:
                {
                        if (::IsIconic(vHwnd))// IsIconic 函数用来判断窗口是否处于最小化状态
                                break;
                        // 取得系统时间
                        SYSTEMTIME time;
                        ::GetLocalTime(&time);

                        // 建立坐标系
                        hdc = ::GetDC(vHwnd);
                        // 以COLOR_3DFACE为背景色就可以擦除指针了(因为窗口的背景色也是COLOR_3DFACE)
                        COLORREF sysColor = ::GetSysColor(COLOR_3DFACE);

                        // 如果分钟改变的话就擦除时针和分针
                        if (PreMinute != time.wMinute)
                        {
                                drawHand(hdc, 200, 8, (PreHour*30 + PreMinute/2), sysColor);
                                drawHand(hdc, 400, 6, PreMinute*6, sysColor);
                                PreHour = time.wHour;
                                PreMinute = time.wMinute;
                        }
                        // 如果秒改变的话就擦除秒针,然后重画所有指针
                        if (PreSecond != time.wSecond)
                        {
                                //擦除秒针
                                drawHand(hdc, 400, 4, PreSecond*6, sysColor);
                                //重画所有指针
                                //经过 1 个小时时针走30 度(360/12 ),经过 1 分钟时针走0.5度(30/60)
                                drawHand(hdc, 200, 8, (time.wHour*30 + time.wMinute/2), RGB(0,0,0));
                                //经过 1 分钟分针走6 度(360/60 )
                                drawHand(hdc, 400, 6, time.wMinute*6, RGB(10,0,0));
                                //经过 1 秒钟秒针走6 度(360/60 )
                                drawHand(hdc, 400, 4, time.wSecond*6, RGB(10,10,0));
                                PreSecond = time.wSecond;
                        }
                        break;
                }

        case WM_NCHITTEST:
                {
                        UINT HitTest;
                        HitTest = ::DefWindowProc(vHwnd, WM_NCHITTEST, wParam, lParam);

                        ////如果鼠标左键按下,GetAsyncKeyState函数的返回值小于0
                        if (HitTest == HTCLIENT && ::GetAsyncKeyState(MK_LBUTTON) < 0)
                        {
                                HitTest = HTCAPTION;
                        }
                        return HitTest;
                }
       
        case WM_CONTEXTMENU:
                {
                        POINT pt;
                        pt.x = LOWORD(lParam);
                        pt.y = HIWORD(lParam);

                        //取得系统菜单的句柄
                        HMENU SysMenu = ::GetSystemMenu(vHwnd, FALSE);//允许应用程序为复制或修改而访问窗口菜单
                        //通过api函数getsystemmenu来得到它的句柄,然后通过菜单相关的api函数就能改变它了。

                        //弹出系统菜单
                        int MenuID;
                        MenuID = ::TrackPopupMenu(
                                SysMenu,                                                        // 菜单句柄
                                TPM_LEFTBUTTON,                // 此参数指定了一些和弹出的菜单的位置相关的选项
                                pt.x,                                                                //(x, y)是弹出的菜单的基于屏幕的坐标
                                pt.y,                                                               
                                0,                                                                        //保留值,必须为零
                                vHwnd,                                                                // 此菜单属于哪一个窗口所有(也就是WM_COMMAND消息发到这个窗口)
                                NULL);

                        if (MenuID > 0)
                        {
                                ::SendMessage(vHwnd, WM_SYSCOMMAND, MenuID, 0);
                        }

                        return 0;
                }
               
        case WM_SYSCOMMAND:
                {
                        int ID = wParam;

                        if (ID == ID_HELP)
                        {
                                ::MessageBox(vHwnd, "时钟显示", "时钟", 0);
                        }
                        else if (ID == ID_TOP)
                        {
                                HMENU sysMenu = ::GetSystemMenu(vHwnd, false);
                                if (FlagTop)
                                {
                                        // 设置 ID号为 IDM_TOPMOST 的菜单项为未选中状态
                                        ::CheckMenuItem(sysMenu, ID_TOP, MF_UNCHECKED);
                                        // 将窗口提到所有窗口的最顶层
                                        ::SetWindowPos(vHwnd,HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
                                        FlagTop = false;
                                }
                                else
                                {
                                        ::CheckMenuItem(sysMenu, ID_TOP, MF_CHECKED);
                                        ::SetWindowPos(vHwnd,HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
                                        FlagTop = true;
                                }
                        }

                        return ::DefWindowProc(vHwnd, WM_SYSCOMMAND, ID, 0);
                }
               

        case WM_CLOSE:
                {
                        ::KillTimer(vHwnd, ID_TIME);
                        int MsgBox = ::MessageBox(vHwnd, "确定要关闭窗口吗?", "询问", MB_YESNO | MB_DEFBUTTON2);
                        if(MsgBox == IDYES)
                                DestroyWindow(vHwnd);
                        break;
                }
        case WM_DESTROY:
                {
                        // 向消息队列投递一个 WM_QUIT 消息,促使 GetMessage 函数返回 0,结束消息循环
                        ::PostQuitMessage(0);
                        break;
                }
        default:
                return ::DefWindowProc(vHwnd, vMsg, wParam, lParam);
        }

        return 0;
}

//******************************************************************
//FUNCTION:
void drawClockFace(HDC vHdc)
{
        const int SQUAREsize = 20;
        char ClockNum;

        static POINT ClockPt =
        {
                225, 390,    // 1 点
                390, 225,    // 2 点
                450, 0,    // 3 点
                390, -225,    //... 下面的坐标是上面的点的对称点(关于 X 轴、Y 轴或原点对称)
                225, -390,
                0, -450,
                -225, -390,
                -390, -225,
                -450, 0,
                -390, 225,
                -225, 390,
                0, 450    // 12 点
        };
        // 选择一个黑色的画刷
        ::SelectObject(vHdc, ::GetStockObject(BLACK_BRUSH));
        // 画12 个圆
        for (int i =0; i<12; i++)
        {
                ::Ellipse(vHdc, ClockPt.x - SQUAREsize, ClockPt.y + SQUAREsize,
                        ClockPt.x + SQUAREsize, ClockPt.y - SQUAREsize);
                wsprintf(ClockNum, "%d", i+1);
                ::TextOut(vHdc, ClockPt.x - 10, ClockPt.y - 20, ClockNum, strlen(ClockNum));
        }
}

//******************************************************************
//FUNCTION:
void setCoordinate(HDC vHdc, int vX, int vY)
{
        ::SetMapMode(vHdc, MM_ISOTROPIC);
        ::SetWindowExtEx(vHdc, 1000, 1000, NULL);
        ::SetViewportExtEx(vHdc, vX, -vY, NULL);
        ::SetViewportOrgEx(vHdc, vX/2, vY/2, NULL);
}

//******************************************************************
//FUNCTION:
void setFont(HDC vHdc, HFONT *vFont, int vFontBig)
{
        *vFont = ::CreateFont(
        35, 0,//高度20, 宽取0表示由系统选择最佳值
        0, 0,//文本倾斜,与字体倾斜都为0
        FW_HEAVY,//粗体
        0, 0, 0,//非斜体,无下划线,无中划线
        GB2312_CHARSET,    //字符集
        OUT_DEFAULT_PRECIS,      
        CLIP_DEFAULT_PRECIS,      
        DEFAULT_QUALITY,      //一系列的默认值
        DEFAULT_PITCH | FF_DONTCARE,   
        "自定义字体"    //字体名称
        );//自定义字体

        SelectObject(vHdc, *vFont);
        DeleteObject(*vFont);
}

//******************************************************************
//FUNCTION:
void drawHand(HDC vHdc, int vLength, int vWidth, int vDegrees, COLORREF vColor)
{
        double Radian = (double)vDegrees * ( (2*3.1415926)/360 );
        // 计算坐标
        POINT pt;

        pt.x = (int)(vLength * sin(Radian));
        pt.y = (int)(vLength * cos(Radian));
        pt.x = -pt.x/5;
        pt.y = -pt.y/5;

        // 创建画笔,并选如DC结构中
        HPEN hPen = ::CreatePen(PS_SOLID, vWidth, vColor);
        HPEN hOldPen = (HPEN)::SelectObject(vHdc, hPen);
        // 画线
        ::MoveToEx(vHdc, pt.x, pt.y, NULL);
        ::LineTo(vHdc, pt.x, pt.y);

        ::SelectObject(vHdc, hOldPen);
        ::DeleteObject(hPen);
}

1兰亭序 发表于 2015-3-11 16:10:13

我试了下,自己新建一个右键菜单不是用系统菜单就可以,不知道右键是系统菜单时怎样标题栏菜单不能用

freeparty 发表于 2015-3-16 05:55:22

1兰亭序 发表于 2015-3-11 16:06
#include
#include
#include"resource.h"


我不处理MFC代码。

智商是硬伤 发表于 2015-9-11 09:03:36

{:7_146:}
页: [1]
查看完整版本: 求助 windows窗口标题菜单和右键菜单问题