首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

[IE编程]怎么消除Webbrowser控件切换时的闪烁

2012-12-14 
[IE编程]如何消除Webbrowser控件切换时的闪烁?环境:VS2005 C# XP小弟以webbrowser控件为基础做一个多页面

[IE编程]如何消除Webbrowser控件切换时的闪烁?
环境:VS2005 C# XP

小弟以webbrowser控件为基础做一个多页面网页流览器,页面切换时会有相对明显的闪烁。经goole,网上找到这么一篇资料:

Web Browser控件和CHtmlView有什么具体应用我也不废话了,咱们开门见山吧。

通常使用上述两个东西的时候会发现切换的时候有很严重的闪烁。

仔细观察你会发现,比方在ChtmlView中,窗口的绘画过程是:先画View的背景,然后在上层画控件(即网页)

解决办法很简单,禁止View进行那无用的导致闪烁的绘制背景过程。

具体做法 :

在派生类里处理WM_ERASEBKGND消息

BOOL CMyHtmlView::OnEraseBkgnd(CDC* pDC) 
{
 return TRUE; 
// return CHtmlView::OnEraseBkgnd(pDC);
}

通过上面的改动以后,你会发现VIEW会跟腾讯的QQ浏览器一样无闪烁:)

Web Browser控件的相应做法类似,不再详述

于是在Webbrowser控件里重写WndProc方法,截获该消息,但没有效果。重写OnPaintBackground,让它啥也不干,照样没效果。忽然想到Webbrowser不过是对底层axwebbrowser控件的封装,于是改用底层的axwebbrowser,还是重写WndProc和OnPaintBackground,结果令人大失所望,页面切换时闪烁依旧。

请问有什么好的办法吗?
[最优解释]
C C++ VC MFC 群1
[其他解释]
关注,接分
[其他解释]
支持这篇文章
[其他解释]
没看懂哦,我做的时候没这个问题
[其他解释]
路过过不去
[其他解释]
自己顶一下
[其他解释]
再up
[其他解释]
该问题可以这样概括:

双缓冲有效解决了自定义控件闪烁问题,但对于一些系统控件而且不能设置双缓冲的控件比如Webbrowser,如何防止其闪烁呢?

难道我得回归VC了?
[其他解释]
用webbrowser控件做多标签式的浏览器,当点击标签切换不同页面时会有闪烁---当页面以黑色为背景时尤其明显
[其他解释]
解决方法如下:

从WebBrowser派生一个新类


构造函数中添加DocumentCompleted事件响应

相关代码:



        [DllImport("user32.dll")]
        protected static extern int GetWindowLong(int hwindow, int unindex);
        [DllImport("user32.dll")]
        protected static extern int CallWindowProc(int lpPrevWndFunc, int hWnd, int Msg, int wParam, int lParam);
        [DllImport("user32.dll")]
        protected static extern int SetWindowLong(int hwindow, int unindex, CallWindowProcDelegate lnewvalue);


        public static int oldWindow = 0; 
        public const int GWL_WNDPROC = -4;
        public delegate int CallWindowProcDelegate(int Wnd, int Msg, int WParam, int LParam);
        public  CallWindowProcDelegate MyCallWindowProc; 

    bool add = false;

        void ExtendWebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            if(add)


            {  return; }

            add = true;
            FindWindow fw = new FindWindow(this.Handle, "Internet Explorer_Server");
            IntPtr hIE = fw.FoundHandle;

            if (hIE.ToInt32() != 0)
            {
                oldWindow = (int)GetWindowLong(hIE.ToInt32(), GWL_WNDPROC);
                MyCallWindowProc = new CallWindowProcDelegate(WndProc);
                SetWindowLong(hIE.ToInt32(), GWL_WNDPROC, MyCallWindowProc);
            }
        }

        private int WndProc(int Wnd, int Msg, int WParam, int LParam)
        {
            const int WM_ERASEBKGND = 0x14;

            if (Msg == WM_ERASEBKGND)
            {
                return 1;
            }

            return CallWindowProc(oldWindow, Wnd, Msg, WParam, LParam);
        }  

    /**/
    /// <summary>
    /// This class is to find the given window's child window accroding to the given child window's name.
    /// The useage: FindWindow fw = new FindWindow(wndHandle, "ChildwndClassName"); IntPtr ip = fw.FoundHandle;
    /// I adapt the code from Paul DiLascia,who is the MSDN Magazine's writer.
    /// The original class is named CFindWnd which is written in C++, and you could get it on Internet.
    /// www.pinvoke.net is a great website.It includes almost all the API fuctoin to be used in C#.
    /// </summary>
    class FindWindow
    {
        [DllImport("user32")]
        [return: MarshalAs(UnmanagedType.Bool)]
        //IMPORTANT : LPARAM  must be a pointer (InterPtr) in VS2005, otherwise an exception will be thrown
        private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);


        //the callback function for the EnumChildWindows
        private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

        //if found  return the handle , otherwise return IntPtr.Zero
        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        private string m_classname; // class name to look for

        private IntPtr m_hWnd; // HWND if found
        public IntPtr FoundHandle
        {
            get { return m_hWnd; }
        }
        // ctor does the work--just instantiate and go
        public FindWindow(IntPtr hwndParent, string classname)
        {
            m_hWnd = IntPtr.Zero;
            m_classname = classname;
            FindChildClassHwnd(hwndParent, IntPtr.Zero);
        }

        //EnumChildWindows是API函数,能够遍历主窗口下所有子窗口。不过它的遍历过程是通过
        //第二个参数即回调函数与程序员交互的。EnumChildWindows每找到一个窗口。就调用回调
        //函数。回调函数如果返回false。遍历就会结束。

        /**/
        /// <summary>
        /// Find the child window, if found m_classname will be assigned 
        /// </summary>
        /// <param name="hwndParent">parent's handle</param>
        /// <param name="lParam">the application value, nonuse</param>
        /// <returns>found or not found</returns>
        //The C++ code is that  lParam is the instance of FindWindow class , if found assign the instance's m_hWnd
        private bool FindChildClassHwnd(IntPtr hwndParent, IntPtr lParam)
        {
            EnumWindowProc childProc = new EnumWindowProc(FindChildClassHwnd);
            IntPtr hwnd = FindWindowEx(hwndParent, IntPtr.Zero, this.m_classname, string.Empty);
            if (hwnd != IntPtr.Zero)


            {
                this.m_hWnd = hwnd; // found: save it
                return false; // stop enumerating
            }
            EnumChildWindows(hwndParent, childProc, IntPtr.Zero); // recurse  redo FindChildClassHwnd
            return true;// keep looking
        }
    }






[其他解释]
我也遇到了,加了你的代码,还是很闪啊
[其他解释]
好了,忘了在构造函数里调用,不好意识。
[其他解释]
好东西,谢谢分享!解决了闪烁问题!

热点排行