是否无法在CHtmlView上下文菜单上添加我们自己的菜单项? [英] Is it not possible to add our own menu items on the CHtmlView context menu?

查看:98
本文介绍了是否无法在CHtmlView上下文菜单上添加我们自己的菜单项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我继续回到CodeProject上的这篇文章:

So I keep coming back to this article on CodeProject:

https://www.codeproject.com/Articles/4758/How-to-customize-the-context-menus-of-a-WebBrowser

然后我在文章顶部意识到了这一点:

I then realised this statement at the top of the article:

修订后的示例项目正在使用更好的自定义方法,该方法将在本文的下一个更新中进行全面讨论,有望在几周内准备就绪.我正在发布此半文档且未经全面测试的代码,因为有迹象表明某些开发人员可能需要比我的下一次更新之日早得多的时间才拥有此代码.对于每个修订后的样本,还有一个Readme.htm文件,该文件简要描述了样本的工作方式.

The revised sample projects are using a new, much better customization approach that is going to be comprehensively discussed in the next update of this article, which will hopefully be ready in a couple of weeks. I am publishing this semi-documented and not fully-tested code, because I am having indications that some developers may need to have this code much sooner than the day of my next update. For each revised sample there is also a Readme.htm file that briefly describes how the sample works.

我以为我在努力理解文章摘录和下载的源代码中的代码!因此,我阅读了自述文件并指出:

I thought I was struggling to understand the code in the article snippets vs the downloaded source! So I read the readme and it stated:

在MFC 7中,CHtmlView嵌入了对IDocHostUIHandler的支持,因此我只是重写了CHtmlView::OnShowContextMenu方法,然后我调用了::CustomShowContextMenu()函数(在CustomMenus.cpp内部),其工作方式与第5节中所述相同.我的原始文章.

In MFC 7 CHtmlView has embedded support for IDocHostUIHandler, thus I simply override the CHtmlView::OnShowContextMenu method and afterwards I call the ::CustomShowContextMenu() function, (inside CustomMenus.cpp) which works like described in the section 5 of my original article.

因此,我决定在我的项目中添加自己的函数替代:

So, I decided to add my own function override in my project:

HRESULT CChristianLifeMinistryHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt,
    LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved)
{
    return CustomContextMenu(ppt, pcmdtReserved);
}

我添加了类似的自定义菜单功能:

And I added the similar custom menu function:

HRESULT CustomContextMenu(POINT* ppt, IUnknown* pcmdtReserved)
{
    IOleWindow* oleWnd = NULL;
    HWND        hwnd = NULL;
    HMENU       hMainMenu = NULL;
    HMENU       hPopupMenu = NULL;
    HRESULT     hr = 0;
    INT         iSelection = 0;

    if ((ppt == NULL) || (pcmdtReserved == NULL))
        goto error;

    hr = pcmdtReserved->QueryInterface(IID_IOleWindow, (void**)&oleWnd);
    if ((hr != S_OK) || (oleWnd == NULL))
        goto error;

    hr = oleWnd->GetWindow(&hwnd);
    if ((hr != S_OK) || (hwnd == NULL))
        goto error;

    hMainMenu = LoadMenu(AfxGetInstanceHandle(),
        MAKEINTRESOURCE(IDR_MENU_HTML_POPUP));
    if (hMainMenu == NULL)
        goto error;

    hPopupMenu = GetSubMenu(hMainMenu, 0);
    if (hPopupMenu == NULL)
        goto error;

    // Show shortcut menu
    iSelection = ::TrackPopupMenu(hPopupMenu,
        TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
        ppt->x,
        ppt->y,
        0,
        hwnd,
        (RECT*)NULL);

    // Send selected shortcut menu item command to shell
    if (iSelection != 0)
        (void) ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);

error:

    if (hMainMenu != NULL)
        ::DestroyMenu(hMainMenu);

    return S_OK;
}

最后,我添加了一个菜单资源:

Finally, I added a menu resource:

IDR_MENU_HTML_POPUP MENU
BEGIN
    POPUP "CustomPopup"
    BEGIN
        MENUITEM "View Source",                 2139
        MENUITEM SEPARATOR
        MENUITEM "Select All",                  31
    END
END

菜单ID值基于IDM_版本,并且都可以使用.

The menu ID values are based on the IDM_ versions and they all work.

然后我尝试使用自己的事件处理程序将自己的菜单项添加到该列表中,并显示为禁用.

I then tried to add my own menu item into that list with my own event handler and it shows as disabled.

是否无法在CHtmlView上下文菜单中添加我们自己的菜单项?

Is it not possible to add our own menu items on the CHtmlView context menu?

我想添加我自己的菜单项打印预览",该菜单项又简单地向我的父级编辑器"发布了一条消息,以模拟单击那里的打印预览".但是似乎添加到此菜单的所有自定义项目始终显示为灰色.

I wanted to add my own menu item "Print Preview" which in turn simply posted a message to my parent "Editor" to simulate clicking "Print Preview" there. But it seems that any custom item that is added to this menu is always greyed out.

如果我添加打印预览"菜单项并将其值设置为2003(IDM_PRINTPREVIEW),它将仅触发原始的打印预览机制.而且我无法将自己的事件处理程序添加到我的CChristianLifeMinistryHtmlView类中,因为它没有兑现.

If I add a "Print Preview" menu item and give it a value of 2003(IDM_PRINTPREVIEW) it just triggers the original print preview mechanism. And I can't add my own event handler for the same to my CChristianLifeMinistryHtmlView class as it is not honoured.

我发现了文章,其中提到:

如果您选择用自己的菜单替换标准菜单,则可以 仍将菜单扩展附加到您的自定义菜单.只需添加一个 菜单定义中的空白IDM_MENUEXT_PLACEHOLDER菜单选项为 指示要将自定义命令插入的位置.菜单扩展 在此占位符之前插入.您也可以添加自己的 通过插入菜单选项将定制命令发送到标准菜单 如以下示例所示,在IDM_MENUEXT_PLACEHOLDER之前.

Should you choose to replace the standard menu with your own, you can still append menu extensions to your custom menu. Simply include a blank IDM_MENUEXT_PLACEHOLDER menu option in your menu definition to indicate where the custom commands are to be inserted. Menu extensions are inserted just before this placeholder. You can also add your own custom command to the standard menu by inserting the menu option before IDM_MENUEXT_PLACEHOLDER, as shown in the following example.

#define IDM_MENUEXT_PLACEHOLDER  6047

// If the placeholder is gone or was never there, then just exit if
(GetMenuState(hMenu, IDM_MENUEXT_PLACEHOLDER, MF_BYCOMMAND) != (UINT)
  -1) {  InsertMenu(hMenu,                    // The Context Menu
             IDM_MENUEXT_PLACEHOLDER,         // The item to insert before
             MF_BYCOMMAND|MF_STRING,          // by item ID and str value
             IDM_MENUEXT_FIRST__ + nExtCur,   // the command ID
             (LPTSTR)aOpts[nExtCur].pstrText);// The menu command text

// Remove placeholder  DeleteMenu(hMenu, IDM_MENUEXT_PLACEHOLDER,
MF_BYCOMMAND); }

扩展的菜单ID介于IDM_MENUEXT_FIRST__IDM_MENUEXT_LAST__之间,最多33个自定义 命令.

The menu IDs for extensions fall between IDM_MENUEXT_FIRST__ and IDM_MENUEXT_LAST__ for a maximum of 33 custom commands.

我知道我的设计不正确,但是我为占位符添加了一个菜单项,然后为菜单项ID为IDM_MENUEXT_FIRST__的打印预览添加了一个菜单项.然后,我向其中添加了一个菜单处理程序.菜单项不再被禁用,这样很好.但是单击它没有任何作用.

I know I didn't design it right but I added a menu item for the place holder and then another for Print Preview with a menu item id of IDM_MENUEXT_FIRST__. I then added a menu handler to it. The menu item is no longer disabled so that is good. But clicking it does nothing.

这个问题涉及:

我想我已经找到了解决方案,并将很快提供答案.

I think I have found a solution and will provide an answer shortly.

推荐答案

我已经了解了这一点.一路上我学到了一些关键的东西.

I have got to the bottom of this. There were a few key things that I learned along the way.

我并没有离开

I was not away of the CHtmlView::OnShowContextMenu function which I needed to implement:

HRESULT CChristianLifeMinistryHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt,
    LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved)
{
    return CustomContextMenu(ppt, pcmdtReserved);
}

为防卫,Visual Studio中的IDE并未在列表中提供它作为可能的替代.但是它仍然存在.

In my defence, the IDE in Visual Studio did not offer it in the list as a possibly override. But it existed non-the-less.

所有自定义菜单项的菜单ID介于IDM_MENUEXT_FIRST__IDM_MENUEXT_LAST__之间,最多可包含33个自定义命令.就我而言,我在resource.h文件中手动创建了一些#define值:

The menu IDs for all custom menu items fall between IDM_MENUEXT_FIRST__ and IDM_MENUEXT_LAST__ for a maximum of 33 custom commands. In my case I manually create some #define values in my resource.h file:

#define CUSTOM_MENU_PRINT_PREVIEW       3700
#define CUSTOM_MENU_EXPORT              3701

请注意,我对使用文字值不满意.我希望我可以在定义中使用IDM_MENU_EXT_FIRST + 1等,但是我不知道该怎么做.有可能吗?

Note that I am not happy using literal values. I wish I could use IDM_MENU_EXT_FIRST + 1 etc. for my definitions but I do not know how to do that. Possible?

在设计自定义菜单时,您也可以使用IDM_XXX值填充现有命令:

When you design your custom menu you can infill existing commands with the IDM_XXX values too:

IDR_MENU_HTML_POPUP MENU
BEGIN
    POPUP "CustomPopup"
    BEGIN
        MENUITEM "Select All",                  31
        MENUITEM SEPARATOR
        MENUITEM "Export",                      CUSTOM_MENU_EXPORT
        MENUITEM SEPARATOR
        MENUITEM "Page Setup",                  2004
        MENUITEM "Print Preview",               CUSTOM_MENU_PRINT_PREVIEW
        MENUITEM SEPARATOR
        MENUITEM "Refresh",                     2300
        MENUITEM SEPARATOR
        MENUITEM "View Source",                 2139
    END
END

尽管如此,相同的注释仍然适用.我不知道如何将IDM_ *常量分配给自己的#define,而不是使用文字值.

The same note still applies though. I can't work out how to assign the IDM_* constants to my own #defines rather than using literal values.

如果您使用的ID值不正确,您的自定义菜单项将显示为灰色.

Your custom menu items will be greyed out if you don't use the right ID values.

然后,您必须创建上下文菜单(有关该代码,请参阅原始问题).

Then you have to create the context menu (see original question for that code).

这与项目4密切相关.TrackMenuPopup在我的情况下需要进行如下调整:

This is closely related to item 4. TrackMenuPopup needed to be adjusted in my situation as follows:

// Show shortcut menu
iSelection = ::TrackPopupMenu(hPopupMenu,
    TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
    ppt->x,
    ppt->y,
    0,
    hwnd,
    (RECT*)NULL);

// Send selected shortcut menu item command to shell
if (iSelection != 0)
{
    if (iSelection == CUSTOM_MENU_PRINT_PREVIEW)
    {
        ::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_PRINTPREVIEW, NULL);
    }
    else if (iSelection == CUSTOM_MENU_EXPORT)
    {
        ::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_EXPORT, NULL);
    }
    else
    {
        (void) ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
    }
}

关键在于测试TrackMenuPopup的返回值并进行自定义处理.实际上,在编写此答案时,我现在意识到可以将打印预览"菜单项定义为IDM_PRINTPREVIEW的值,然后再次测试,如下所示:

The key was testing the return value of TrackMenuPopup and doing custom handling. In-fact, whilst writing this answer I now realise that my "Print Preview" menu item can be defined as the value of IDM_PRINTPREVIEW and I test again that, like this:

if (iSelection != 0)
{
    if (iSelection == IDM_PRINTPREVIEW)
    {
        ::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_PRINTPREVIEW, NULL);
    }
    else if (iSelection == CUSTOM_MENU_EXPORT)
    {
        ::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_EXPORT, NULL);
    }
    else
    {
        (void) ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
    }
}

因此,我唯一的烦恼是我自己的#define是值正在使用文字数字,如果可能的话,我希望它们基于IDM常量.但是无论哪种方式,一切都很好!

So my only gripe is that my own #define are values are using literal numbers and I would prefer them to be based on the IDM constants if possible. But either way, it all works fine!

这篇关于是否无法在CHtmlView上下文菜单上添加我们自己的菜单项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆