读一个TXT文本,有10000行数据,按行读,用一个CProgressCtrl显示读取进度。
最开始我只用主线程编程,做了一个菜单,点击这个菜单弹出文件对话框,选中要读的TXT文件,然后用
for(i=1;i<=10000,i++)循环一行一行读取这10000行数据,循环体中我用进度条的SetPos函数设置进度条的进度,按我最初
的设想,程序每循环一次会刷新一次进度条的位置,这样进度条就会一点一点往上涨,但最后我看到的结果是这样的:
一打开选中的TXT文档,界面就卡住不动,界面上的进度条当然也没有任何显示,过了20多秒数据都读完了,看到进度条很快的从0涨到100%。后来在论坛上发了个贴,很多人告诉我要再开一个线程去读取文件,于是我做了如下工作:
在主线程进入for循环读取文件的之前新建了一个线程hThread1,命令如下:
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
CloseHandle(hThread1);hThread1线程的函数Fun1Proc申明为MainFrame的友元函数,然后将主线程原来for(i=1;i<=10000,i++)循环读数据的程序都搬Fun1Proc里面,在主线程里加一个while(i<=10000)的循环体,在这个循环体里根据(i/10000)*100的值来刷新进度条的进度。可是我发现进度条的反应与每开新线程是一样的,就是中间0-20秒左右没动静,最后唰的一下从0到100%。各位大哥,数据的读取我的程序都没有问题,但是这个进度条的反应该怎么弄啊?折腾我好几天了。

解决方案 »

  1.   

    不是,我是在线程函数里读取文件数据,然后在主线程的while循环体里用
    ::PostMessage(Splitter3.GetPane(0,0)->m_hWnd,0x407,0L,0L)这个函数不断发送代码为0x407的消息。
    因为我这个进度条是一个叫Dlg3的类的一个成员,因此我在Dlg3类的DefWindowProc函数里响应0x407消息刷新进度条。
    Dlg3这个类是我在资源管理器里编辑的一个Dialog,其基类选择的CFormView,我用Dlg3作为我一个拆分子窗口的View类,也就是说我的进度条放置在这个拆分子窗口中显示。
      

  2.   

    把你的PostMessage改成SendMessage试试,调试一下,看看进入消息响应函数中去了吗???
      

  3.   

    试过了啊,效果好像是一样的,消息是肯定发出去了的,要没发出去根本进度条都不会有显示增长(我其它任何地方都没有操作进度条进度),消息确实是在Dlg3的DefWindowProc被接收到了的,只是奇怪为什么读数据的时候整个界面会卡在那里,感觉好像死机了一样,不光是进度条,界面上的所有东西都没有被刷新,非得等10000行数据都读完了才有反应。
      

  4.   

    不会的,主线程运行到这一步就是发送消息这一点程序,倒是读数据的线程函数比较复杂。
    我还是把进入多线程后的程序贴出来吧:
    主线程:
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    hMutex=CreateMutex(NULL,FALSE,NULL);
    while (line<=line_num_rut)

    WaitForSingleObject(hMutex,INFINITE);
    if ((ceil(10*line/line_num_rut))==(10*line/line_num_rut))
    {
                            progress=ceil(100*line/line_num_rut);//算出进度条位置
    ::PostMessage(Splitter3.GetPane(0,0)->m_hWnd,0x407,0L,0L);//发送更新进度条消息
    }
    ReleaseMutex(hMutex);
    }
    hThread1线程函数(这个读数据的函数有些复杂,但是这不主线程啊):
    DWORD WINAPI Fun1Proc(LPVOID lpParameter)
    {
    for (line=1;line<=line_num_rut;line++)
    {
    WaitForSingleObject(hMutex,INFINITE);
    int dot_position[10];
    float c=0;

                for (i=0;i<LineWidth_rut;i++)
    {
    fseek(fp,CurrentPosition_1+i+LineWidth_rut*(line-1),0);
    fread(&a[i],1,1,fp);
    d[i]=a[i]-48;
    }

    j=0;
    for (i=0;i<LineWidth_rut;i++)
    {

    if (d[i]==-2)
    {
    dot_position[j]=i;
    j=j+1;
    }

    }   


    bool label_valid=false;
    int data_num=0;
    int num_temp=0;
    for (i=1;i<LineWidth_rut;i++)
    {
    if (d[i]==-16&&d[i-1]!=-16)
    {
    num_temp=num_temp+1;
    if (num_temp==9)
    {
    dot_position[j]=i;
    }
    }
    }
    for (i=1;i<LineWidth_rut;i++)
    {

    if (d[i-1]==-16&&d[i]!=-16)
    {

    label_valid=true;

    }
    if (d[i]==-16&&d[i-1]!=-16)
    {

    b[data_num]=c;
    label_valid=false;
    data_num=data_num+1;
    c=0;
    }


    if (label_valid==true&&d[i]!=-2)

    {


    if ((dot_position[data_num-1]-i)>0)
    {
    c=c+d[i]*pow(10,dot_position[data_num-1]-i-1);
    }
    if ((dot_position[data_num-1]-i)<0)
    {
    c=c+d[i]/pow(10,i-dot_position[data_num-1]);
    }
    }


    bool label_firststr=false;
    CString temp_str;
    stake_num_rut[line]="";
    for (i=0;i<LineWidth_rut;i++)
    {

    if (a[i]==32)
    {
    label_firststr=true;
    }
    if (label_firststr==false)
    {
    temp_str=a[i];
    stake_num_rut[line]=stake_num_rut[line]+temp_str;
    }

    if (a[i]<128&&a[i]!=32&&i<LineWidth_rut-2)
    {
                        data_valid_rut[line]=a[i];
    }
    }





    leftdepth_rut[line]=b[1];
    rightdepth_rut[line]=b[2];
    leftdepth_rdi_rut[line]=b[3];
    rightdepth_rdi_rut[line]=b[4];
    wholedepth_rut[line]=b[5];
    maxdepth_rut[line]=b[6];
    speed_rut[line]=b[7];
    distance_rut[line]=b[8];

    ReleaseMutex(hMutex);


    }

    return 0;
    }
    有问题的程序就这么多
      

  5.   

    你在主线程的while循环里WaitForSingleObject(hMutex,INFINITE);做等待,你的主线程不就卡在这里,当hMutex没有single时。那么你的子线程里发送给主线程的消息就不会得到及时的处理主线程里最好不会做WaitForSingleObject()或者Sleep()这之类的操作。
      

  6.   

    互斥对象其实对我的程序作用不大,去掉也可以,我把所有的WaitForSingleObject和ReleaseMutex都注释掉,结果还是一样的。
    另外我又发现一个问题:
    我在主线程里把::PostMessage(Splitter3.GetPane(0,0)->m_hWnd,0x407,0L,0L)这句去掉,直接用
    p->m_progress.SetPos(progress)这个函数设置进度条进度,其中p是指向进度条所在类的指针,m_progress就是我的进度条,这样我就不需要在主线程里发消息去告诉Dlg3更新进度条了。
    做了上述改动后,程序编译都没有问题,运行打开也没有问题,但是一读取数据的时候就报错,说afxcmn2.inl这个文件出问题了。快崩溃了,这么个小问题都不知道该怎么解决。‘组织部长’同志,实在不行你就贴一个类似的源程序给我参考下吧,就是读取TXT文件并用多线程方式显示进度的就可以。
      

  7.   

    为了查找原因,我把线程函数里的程序都删掉了,就用几个for循环来加大运算量,这样程序看起来非常简单,但是结果还是一样的。
    改动后的主程序如下(进入多线程部分):
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    CloseHandle(hThread1); 
    while (line<=line_num_rut)
    {  
    progress=ceil(100*line/line_num_rut);//算出进度条位置
    ::PostMessage(Splitter3.GetPane(0,0)->m_hWnd,0x407,0L,0L);//发送更新进度条消息
    }改动后的子线程函数如下:DWORD WINAPI Fun1Proc(LPVOID lpParameter)
    {
    for (line=1;line<=line_num_rut;line++)
    {
    for (i=1;i<10000;i++)
    {
    progress=ceil(100*line/line_num_rut);
    }
            }
    return 0;
    }
    就是这么两段程序,我连互斥对象也去掉了,结果还是一点击读文件时界面就卡住,然后进度条等到所有程序运行完了以后才唰的一下从0涨到100%;
      

  8.   

    帮你写了个小demo程序,就是从一个文件F:\11.txt文本文件中每次读一个字符的数据,然后设置进度条。// .H头文件中
    CProgressCtrl m_pb; // 进度条控件对象
    afx_msg LRESULT OnSetRange(WPARAM wParam, LPARAM lParam); // 设置进度条的范围
    afx_msg LRESULT OnSetPos(WPARAM wParam, LPARAM lParam); // 设置进度条的当前位置// .CPP源文件中
    #define UM_SETRANGE WM_USER+1110 // 自定义的消息,设置进度条的范围
    #define UM_SETPOS   WM_USER+1111 // 自定义的消息,设置进度条的位置BEGIN_MESSAGE_MAP(CXXXDlg, CDialog)

    ON_MESSAGE(UM_SETRANGE, &CAGEADlg::OnSetRange)
    ON_MESSAGE(UM_SETPOS, &CAGEADlg::OnSetPos)
    ON_MESSAGE(UM_SETFIN, &CAGEADlg::OnSetFin)
    END_MESSAGE_MAP()// 设置进度条的范围消息UM_SETRANGE的响应函数
    LRESULT CXXXDlg::OnSetRange(WPARAM wParam, LPARAM lParam)
    {
    if(m_pb.GetSafeHwnd())
    {
    m_pb.SetRange32(0, (int)lParam);
    }
    return 0;
    }// 设置进度条的当前消息UM_SETRANGE的响应函数
    LRESULT CXXXDlg::OnSetPos(WPARAM wParam, LPARAM lParam)
    {
    if(m_pb.GetSafeHwnd())
    {
    m_pb.SetPos((int)lParam);
    }
    return 0;
    }// 线程函数,读取文件数据,并显示文件读取进度信息
    UINT __cdecl ThreadProc(LPVOID lParam)
    {
    HWND hWnd = (HWND)lParam;
    try
    {
    CFile file;
    file.Open(_T("F:\\11.txt"), CFile::modeRead);
    int nLen = (int)file.GetLength();
    ::SendMessage(hWnd, UM_SETRANGE, 0, (LPARAM)nLen);
    char buf[1] = {0};
    int nIndex = 0;
    while(TRUE)
    {
    int nRet = file.Read(buf, 1);
    if(!nRet)
    break;
    if(nIndex++ == nLen)
    break;
    ::SendMessage(hWnd, UM_SETPOS, 0, (LPARAM)nIndex);
    }
    file.Close();
    }
    catch (CFileException* e)
    {
    e->ReportError();
    e->Delete();
    }
    return 0;
    }// 启动线程函数,从文件中读取数据,并显示当前读取的进度
    void CXXXDlg::OnBnClickedOk()
    {
    // TODO: Add your control notification handler code here
    //OnOK();
    AfxBeginThread(ThreadProc, (LPVOID)GetSafeHwnd());
    }
      

  9.   

    用默认的进度条范围,开个线程,把i值传进来
    让每读100行进度条走一个格,
    while(bool condition)
    {
      setpos(i/100);
    }
    读完文件condition = false;
    循环就退了
    ok了