【问题标题】:MFC List Control scrolling shows extra grid linesMFC 列表控件滚动显示额外的网格线
【发布时间】:2008-10-08 14:40:13
【问题描述】:

我在带有网格线的报表视图中使用 MFC 列表控件以模糊的电子表格方式显示数据。

有时当用户在控件中垂直滚动时,会绘制额外的网格线,这看起来很糟糕。

当使用滑块或鼠标滚轮滚动时不会发生这种情况,只有在使用滚动控件底部的小向下箭头按钮时才会发生这种情况。

当列表控件窗口的大小不是精确的偶数行时,似乎会发生这种情况,因此在底部可以看到部分行。

如果我调整列表控件的大小,使部分行不可见,问题就解决了。但是,当程序在另一台计算机上运行时,它会出现,大概是因为一行所占用的像素数发生了变化。

我假设这是屏幕分辨率、字体大小和“对话框单位”之间的交互。

我想我需要在创建控件时以编程方式强制它的大小。但是什么尺寸?

我已尝试使用 ApproximateViewRect() 方法,但无法使其正常工作。也许这个方法不知道报表视图?

我想,另一种方法是创建我自己的 CListCtrl 特化并覆盖任何进行滚动的方法。这似乎需要做很多工作。

此屏幕截图显示了一个密切相关的问题,即网格线丢失

这里有一个额外的网格线

这两者之间以及它们与完美滚动的唯一区别是控件的垂直大小有几个像素不同。

【问题讨论】:

    标签: mfc


    【解决方案1】:

    这确实是一个与“平滑滚动”相关的错误,这里有一个解决方法:

    void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
        __super::OnVScroll(nSBCode, nPos, pScrollBar);
        Invalidate();
        UpdateWindow();
    }
    

    【讨论】:

    • 要让框架调用overide,需要将其添加到消息映射中。
    • 我的答案中消息映射编码的详细信息
    • 消息映射是每个在 MFC 工作的人都应该理解的,与这个答案没有特别相关。
    • 你不会接受这个答案,因为他没有输入消息映射条目??天哪!消息映射的东西可能只是作为评论附加在这里(或用它编辑你的问题)。
    【解决方案2】:

    我记得这是 ListView 本身的一个错误(不仅仅是通过 MFC,而是通过通用控件)。一个快速的谷歌搜索似乎让很多人得出了同样的结论。我猜因为 Windows 资源管理器没有网格线,他们觉得不需要解决这个问题?我记得在 90 年代后期。

    我想诀窍是在滚动后使窗口无效 - 也许是为了响应 VSCROLL 消息?只是猜测。

    【讨论】:

    • 您在 google 中使用了哪些搜索词?我什么也找不到。 “ListView”和“List Control”一样吗,我用的就是>
    【解决方案3】:

    股票列表视图会发生这种情况,还是自定义绘制?我从未见过标准 Windows 控件的重绘问题。

    也许您可以发布一个屏幕截图来说明问题?我想您更愿意修复重绘问题而不是精确调整控件的大小?

    【讨论】:

    • 完全有货。这个问题很难重现,我也不清楚这里怎么发图。
    • 好的,我明白了。这个控件是用资源编辑器创建的,还是你动态创建的(例如在 OnInitDialog() 中使用 m_ListCtrl.Create(...)这在过去为我解决了类似的重绘问题。
    • 在资源编辑器中创建。我在 OnInitDialog 中创建它没有问题(我这样做是为了其他事情)。我对使用 WS_CLIPCHILDREN 一无所知 - 将看看。
    • myZoneList.ModifyStyle(0, WS_CLIPSIBLINGS, 0);在 OnInitDialog 中添加此代码无效,如果使用 WS_CLIPCHILDREN 也无效。我的快速阅读表明只有当行是窗口时才会这样做,我对此表示怀疑。
    【解决方案4】:

    要修复 MFC 列表控件中的这个错误,您需要专门化控件,覆盖响应滚动的方法,并强制它在完成滚动后完全重绘列表。

    接口头

    class cSmoothListControl : public CListCtrl
    {
    public:
        DECLARE_MESSAGE_MAP()
        afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
    };
    

    实现:

    BEGIN_MESSAGE_MAP(cSmoothListControl, CListCtrl)
    ON_WM_VSCROLL()
    END_MESSAGE_MAP()
    
    void cSmoothListControl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
        // call base class method to do scroll
        CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
    
        // force redraw to cover any mess that may be created
        Invalidate();
        UpdateWindow();
    }
    

    【讨论】:

    • 这个答案只是将外围消息映射添加到我已经足够的答案中。
    • Ajryan,我发现您的回答不够。当我实施它时,它失败了。花了大约一个小时找到您遗漏的必要代码。我想拯救别人这个悲伤。
    • 完全荒谬。这就像问如何将两个数字相加并说答案不充分,因为它没有说明如何打印结果。
    • 对不起,我同意 ravenpoint 的观点。如果在消息映射中未声明 ON_WM_VSCROLL(),则永远不会调用 OnVScroll,并且在 msdn 文档中根本没有提到它。检查msdn.microsoft.com/en-us/library/fhfk142k%28VS.80%29.aspx,您可以找到此页面:msdn.microsoft.com/en-us/library/hfk31946%28VS.80%29.aspx,前提是您已经知道需要一个消息映射条目。
    • 好吧,我也觉得这很荒谬。任何称职的 MFC 程序员都应该知道添加一个血腥的消息映射条目来调用被覆盖的函数。还 -1 用于糟糕的标记。
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 2011-04-14
    相关资源
    最近更新 更多