【问题标题】:Final toolbar item icon not showing最终工具栏项目图标未显示
【发布时间】:2018-01-27 08:19:23
【问题描述】:

我正在包装 Win32 工具栏。一切正常,除了当包装类的用户添加分隔符时,最后一个工具栏项的图标不显示。

考虑这个客户端代码:

    toolbarBtn tbb[] = { toolbarBtn { ID_FILE_NEW, IDI_NEW },
                            toolbarBtn { ID_FILE_OPEN, IDI_OPEN },
                            sep { },
                            toolbarBtn { ID_FILE_SAVEAS, IDI_SAVE },
                            toolbarBtn { ID_FILE_PRINT, IDI_PRINT },
                            sep { },
                            toolbarBtn { ID_EDIT_UNDO, IDI_UNDO },
                            toolbarBtn { ID_EDIT_REDO, IDI_REDO } };

this->tb = toolbar { *this, tbb, sizeof tbb / sizeof *tbb };

toolbarBtn 对象代表一个工具栏按钮。 sep 对象是一个分隔符,继承自类 toolbarBtn。以下语句调用工具栏类的构造函数,创建它。对于这段代码,这是我得到的图形输出:

您可以通过悬停看到,最后两个按钮存在!但是由于某种原因,图标不显示,并且图标的顺序也发生了变化。它应该是“新建”、“打开”、[分隔符]、“保存”、“打印”、[分隔符]、“撤消”和“重做”。但“另存为”和“重做”不显示。而且我知道图标本身没有问题,因为我可以放置任何toolbarBtns 序列,但只要有sep 对象,那么最后一个图标永远不会显示。

以下是相关功能/方法的实现:

toolbarBtn::toolbarBtn(int id, icon ico, BYTE state, BYTE style)
{
    ZeroMemory(this, sizeof *this);
    this->ico = ico;
    this->tbb.idCommand = id;
    this->tbb.fsState = state;
    this->tbb.fsStyle = style;
    this->tbb.iBitmap = 0;  // field will be changed by toolbar c'tor
}

// count # of buttons; no separators counted
size_t nActualButtons(const toolbarBtn btns[], size_t n)
{
    size_t n1 = n;
    for (size_t i = 0; i < n; ++i)
        if (btns[i].getTBB().fsStyle & TBSTYLE_SEP)
            --n1;
    return n1;
}
toolbar::toolbar(overlappedwindow parent, const toolbarBtn btns[], size_t n, 
                 int id)
{
    this->hwnd = CreateWindow(TOOLBARCLASSNAME, NULL, 
        WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT, 0, 0, 0, 0,
        parent.gethwnd(), (HMENU) id, GetModuleHandle(NULL), NULL);
    if (this->hwnd == NULL)
        message(L"%s: %s", __FUNCTIONW__, geterror());

    // Send the TB_BUTTONSTRUCTSIZE message, which is required for
    // backward compatibility.
    SendMessage(this->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);

    HIMAGELIST imglist = ImageList_Create(16, 16, ILC_COLOR32, n, 0);
    if (!imglist)
        message(L"%s: %s", __FUNCTIONW__, geterror());

    for (size_t i = 0; i < n; ++i) {
        if (btns[i].getTBB().fsStyle & TBSTYLE_SEP)
            continue;     // dont add separators to image list
        if (ImageList_AddIcon(imglist, btns[i].getIcon().gethandle()) == -1)
            message(L"%s: %s", __FUNCTIONW__, geterror());
    }

    SendMessage(this->hwnd, TB_SETIMAGELIST, (WPARAM) 0, (LPARAM) imglist);

    TBBUTTON *tbb = (TBBUTTON *) calloc(n, sizeof (TBBUTTON));
    for (size_t i = 0; i < n; ++i) {
        tbb[i] = btns[i].getTBB();
        tbb[i].iBitmap = (tbb[i].fsStyle & TBSTYLE_SEP) ? 0 : i;
        if (tbb[i].fsStyle & TBSTYLE_SEP)
            tbb[i].idCommand = 0;
    }
    SendMessage(this->hwnd, TB_ADDBUTTONS, n, (LPARAM) tbb);
    free(tbb);
}

【问题讨论】:

  • nActualButtons 不计算分隔符。因此,如果您使用其中的返回值传递给toolbar 构造函数,则构造函数中的循环将在处理最后一项之前终止
  • @JimRhodes 我没有将nActualButtons 的返回值传递给toolbar 构造函数。我正在传递数组的大小 (sizeof tbb / sizeof *tbb)。事实上,我并没有在代码中的任何地方使用nActualButtons,我知道我为什么还要发布它
  • 如果你有两个分隔符,最后两张图片会不会显示?你能添加实际调用上述函数的代码吗?
  • @pingul 调用上述函数的代码是问题的最重要部分。为了回答你关于分隔符的问题,如果我添加两个分隔符,它仍然只是最后一个没有出现的项目。
  • 这就是我们使用std::array 的原因。无论如何,我认为我们无法从代码中推断出导致问题的原因——正常的调试似乎是要走的路。不过,我会在 codereview.stackexchange.com 上发布这个问题以进行一些代码改进。

标签: c++ winapi toolbar


【解决方案1】:

我认为您的问题可能与此有关:

sep { },

您实际上是在这样做:

sep {0, 0, 0, 0}

因此您的分隔符不会设置 TBSTYLE_SEP。您可能应该像这样初始化分隔符:

sep {0, 0, 0, TBSTYLE_SEP}

【讨论】:

  • 我的分隔符类只是继承自toolbarBtn类,它的构造函数调用toolbar的构造函数:sep() : toolbarBtn(0, icon { }, TBSTATE_ENABLED, TBSTYLE_SEP) { }
猜你喜欢
  • 1970-01-01
  • 2016-08-28
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 2014-12-26
  • 2014-03-04
  • 2017-02-27
  • 1970-01-01
相关资源
最近更新 更多