mfc编程 对话框中的listbox和进度条不能实时刷新,求高手指点!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mfc编程 对话框中的listbox和进度条不能实时刷新,求高手指点!相关的知识,希望对你有一定的参考价值。

在主对话框中 新建了一个对话框:

mymodel = new CmyModel;
mymodel->Create(IDD_MODEL, this);
mymodel->MoveWindow(1425, 0, 180, 230, TRUE);
mymodel->ShowWindow(SW_SHOW);
在创建的对话框中的OnCtlColor函数中,实现了对话框的透明:
switch(pWnd->GetDlgCtrlID())

pDC->SetBkMode(TRANSPARENT);
return (HBRUSH)GetStockObject(NULL_BRUSH);
break;


但是 我在 listbox控件中动态添加的内容删除后,内容还显示,没有实时刷新。我在listbox控件函数中加了Invalidate()和UpdateData()函数不管用,在Onpaint函数 中加了也不起作用。
滑动条滑动后 也没有实时刷新对话框。
这应该怎么解决呢?求支招,谢谢了!

参考技术A

这里不能实时刷新存在多种可能,你的描述太少,不能确定。

常见可能分析几个你先试试:

    透明造成的。测试方法,注销OnCtrlColor中的TRANSPARENT相关代码试试。

    大循环无Idle空闲造成的,通常因为大数据量在循环中加入,在循环中无法实现刷新,判断根据:循环后会一起完成刷新。

    非法界面控制代码造成的,即在无透明、无大数据循环下,正常更新代码无法控制界面。这种情况比较麻烦,如果MFC不是很熟悉,建议新建一个空工程,测试代码有效性。

追问

是透明造成的。但又必须将对话框透明处理。您有什么好办法吗?

追答

控件透明后,Invalidate(TRUE)函数是有效的。一般安全的做法是进行两次。

即在同一个函数中,更新内容前线Invalidate一次,更新之后再次Invalidate。注意,这个函数不能在OnPaint中调用。

追问

我是在button按键中将listbox列表里的内容删除的!

ClistBox m_ListView;

m_ListView.Invalidate(TRUE);
int index = m_ListView.GetSelCount();
m_ListView.DeleteString(index);
m_ListView.Invalidate(TRUE);,

但是不管用,还是没刷新。

追答

你需要调用的,是对话框的Invalidate,而不是列表框的。
如果优化设计,最好是GetWindowRect获取listView的范围,通过InvalidateRect区域更新。

追问

我调用 mymodel 这个指针,而且我看了它在创建对话框 和 需要刷新时的值 是一样的,但还是没有刷新呀!我把我的整个程序界面缩小后,在放大,listbox才会刷新。但是背景就变了。

追答

透明控件,需要父窗口刷新才会产生实际刷新,其实这是因为在MFC中,通过CtrlColor透明刷子做透明,是一种取巧行为,造成刷新机制的不完善。

追问

这么复杂啊,那应该怎么处理呢?

追答

前面说了,调用对话框的Invalidate

追问

mymodel 这个就是创建对话框的指针。不是用这个吗?还是需要在创建一个新指针呢?

追答

你不是在对话框的按钮响应函数里面么?用什么指针啊,既然是对话框的成员函数中,直接使用就可以了。

Invalidate(TRUE);
int index = m_ListView.GetSelCount();
m_ListView.DeleteString(index);
Invalidate(TRUE);,

追问

试过了 还是没有刷新。

追答

那就不应该是刷新的问题了吧,你点击按钮后,最小化对话框(或切换程序)再最大化,看看是否刷新了。如果这样也不刷新,那不是刷新的问题,而应该是你代码是否生效的问题。

追问

这样试过,是可以刷新的。

追答

那我就没办法了。透明控件,无论是list列表框还是编辑框什么的,采用OnCtrlColor方式透明,就是会出现刷新问题,这个时候就是要调用父窗口刷新才会正确显示。一般是用InvalidateRect,如果Invalidate无效可以试试这个。
至于你的为什么不显示,我觉得还是有其它代码问题。建议你新建一个MFC对话框工程,只做透明代码和列表框代码看看,我觉得逻辑上是没有问题的。

本回答被提问者采纳
参考技术B 试试AddString后面加下面这一句:

m_ListBox.RedrawWindow();

《MFC网络编程》学习日记2

VC++的 MFC类库中提供了 CAsyncSocket这样一个套接字类,用他来实现

Socket编程,是非常方便的。
本文将用一个 Echo例程来介绍CAsyncSocket类的用法。
一. 客户端
1. 创建一个 Dialog Based项目: CSockClient。
2. 设计对话框
去掉Ok和 Cancle两个按钮,增加 ID_Connect(连接) 、 ID_Send(发送) 、
ID_Exit ( 关闭)按钮, 增加ListBox控件IDC_LISTMSG和Edit控件IDC_EDITMSG,
并按下表在ClassWizard中为CCSockClientDlg类添加变量。
3. CAsyncSocket类用DoCallBack函数处理MFC消息,当一个网络事件发生时,
DoCallBack函数按网络事件类型: FD_READ、 FD_WRITE、 FD_ACCEPT、 FD_CONNEC

ControlID Type Member
IDC_EDITMSG CEdit m_MSG
IDC_LISTMS ClistBox m_MSGS

分别调用OnReceive、 OnSend、 OnAccept、 OnConnect函数。 由于MFC把这些事件
处理函数定义为虚函数, 所以要生成一个新的C++类, 以重载这些函数, 做法如下:
以Public方式继承CAsyncSocket类,生成新类 MySock;
为MySock类添加虚函数 OnReceive、 OnConnect、 OnSend
4. 在 MySock.ccp中添加以下代码
#include "CSockClient.h"
#include "CSockClientDlg.h"
5. 在 MySock.h中添加以下代码
public:
BOOL m_bConnected; //是否连接
UINT m_nLength; //消息长度
char m_szBuffer[4096]; //消息缓冲区
6. 在 MySock.ccp中重载各函数
MySock::MySock()
{
m_nLength=0;
memset(m_szBuffer,0,sizeof(m_szBuffer));
m_bConnected=FALSE;
}
MySock::~MySock()
{
//关闭套接字
if(m_hSocket!=INVALID_SOCKET)
Close();
}
void MySock::OnReceive(int nErrorCode)
{
m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);
//下面两行代码用来获取对话框指针
CCSockClientApp pApp=(CCSockClientApp)AfxGetApp();
CCSockClientDlg pDlg=(CCSockClientDlg)pApp- >m_pMainWnd;
pDlg- >m_MSGS.InsertString(0,m_szBuffer);
memset(m_szBuffer,0,sizeof(m_szBuffer));
CAsyncSocket::OnReceive(nErrorCode);
}
void MySock::OnSend(int nErrorCode)
{
Send(m_szBuffer,m_nLength,0);
m_nLength=0;
memset(m_szBuffer,0,sizeof(m_szBuffer));
//继续提请一个“ 读” 的网络事件,接收Server消息
AsyncSelect(FD_READ);
CAsyncSocket::OnSend(nErrorCode);
}
void MySock::OnConnect(int nErrorCode)
{
if (nErrorCode==0)
{
m_bConnected=TRUE;
CCSockClientApp pApp=(CCSockClientApp)AfxGetApp();
CCSockClientDlg pDlg=(CCSockClientDlg)pApp- >m_pMainWnd;
memcpy(m_szBuffer,"Connected to ",13);
strncat(m_szBuffer,pDlg- >m_szServerAdr,
sizeof(pDlg- >m_szServerAdr));
pDlg- >m_MSGS.InsertString(0,m_szBuffer);
AsyncSelect(FD_READ); ////提请一个“ 读” 的网络事件,准备接收
}
CAsyncSocket::OnConnect(nErrorCode);
}
7. 新建对话框IDD_Addr,用来输入IP地址和 Port;生成新类CAddrDlg。增加
两个Edit控件: IDC_Addr、 IDC_Port按下表在ClassWizard中为CAddrDlg类添
加变量。

Control ID Type Member
IDC_Addr CString m_Addr
IDC_Port int m_Port

8. 在 CSockClientDlg.ccp中添加代码
#include "AddrDlg.h"
protected:
int TryCount;
MySock m_clientSocket;
UINT m_szPort;
public:
char m_szServerAdr[256];
9. 双击IDD_CSOCKCLIENT_DIALOG对话框中的“ 连接” 按钮,添加以下代码
void CCSockClientDlg::OnConnect()
{
m_clientSocket.ShutDown(2);
m_clientSocket.m_hSocket=INVALID_SOCKET;
m_clientSocket.m_bConnected=FALSE;
CAddrDlg m_Dlg;
//默认端口1088
m_Dlg.m_Port=1088;
if (m_Dlg.DoModal()==IDOK && !m_Dlg.m_Addr.IsEmpty())
{
memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr));
m_szPort=m_Dlg.m_Port;
//建立计时器,每1秒尝试连接一次,直到连上或 TryCount>10
SetTimer(1,1000,NULL);
TryCount=0;
}
}
10. 添加Windows消息WM_TIMER响应函数OnTimer
void CCSockClientDlg::OnTimer(UINT nIDEvent)
{
if (m_clientSocket.m_hSocket==INVALID_SOCKET)
{
BOOL bFlag=m_clientSocket.Create(0,SOCK_STREAM,FD_CONNECT);
if(!bFlag)
{
AfxMessageBox("Socket Error!");
m_clientSocket.Close();
PostQuitMessage(0);
return;
}
}
m_clientSocket.Connect(m_szServerAdr,m_szPort);
TryCount++;
if (TryCount >=10 || m_clientSocket.m_bConnected)
{
KillTimer(1);
if (TryCount >=10)
AfxMessageBox("Connect Failed!");
return;
}
CDialog::OnTimer(nIDEvent);
}
11. 双击IDD_CSOCKCLIENT_DIALOG对话框中的“ 发送” 按钮,添加以下代码
void CCSockClientDlg::OnSend()
{
if (m_clientSocket.m_bConnected)
{
m_clientSocket.m_nLength=m_MSG.GetWindowText
(m_clientSocket.m_szBuffer, sizeof(m_clientSocket.m_szBuffer));
m_clientSocket.AsyncSelect(FD_WRITE);
m_MSG.SetWindowText("");
}
}
12. 双击IDD_CSOCKCLIENT_DIALOG对话框中的“ 关闭” 按钮,添加以下代码
void CCSockClientDlg::OnExit()
{
//关闭Socket
m_clientSocket.ShutDown(2);
//关闭对话框
EndDialog(0);
}
12.运行此项目,连接时输入主机名或IP均可, CAsyncSocket类会自动处理。
二. 服务端
Server端的编程与Client端的类似,下面主要介绍他的 Listen及 Accept函数
1. 建立一个 CNewSocket类, 重载CAsyncSocket类的OnReceive、 OnSend函数,
如何进行信息的显示和发送可以参考Client程序。 本例中采用将收到信息原封不
动发回的方法来实现 Echo功能,代码如下
CNewSocket:: OnReceive( int nErrorCOde)
{
m_nLength=Receive( m_szBuffer, sizeof( m_szBuffer) , 0) ;
// 直接转发消息
AsyncSelect( FD_WRITE) ;
}
CNewSocket:: OnSend( int nErrorCode)
{
Send( m_szBuffer, m_nLength, 0) ;
}
2. 建立一个 CMyServerSocket类,重载 CAsyncSocket类的 OnAccept函数代码
如下
在MyServerSocket.h中声明变量
public::
CNewSocket m_pSocket;
void CMyServerSocket:: OnAccept( int nErrorCode)
{
//侦听到连接请求,调用Accept函数
CNewSocket
pSocket = new CNewSocket( ) ;
if ( Accept( pSocket) )
{
pSocket- >AsyncSelect( FD_READ) ;
m_pSocket=pSocket;
}
else
delete pSocket;
}
3. 为对话框添加一个“ 侦听” 按钮,添加如下代码
在CsockServerDlg.h中声明变量
public:
CMyServerSocket m_srvrSocket;
void CCSockServerDlg:: OnListen()
{
if ( m_srvrSocket.m_hSocket==INVALID_SOCKET)
{
BOOL bFlag=m_srvrSocket.Create
(UserPort, SOCK_STREAM, FD_ACCEPT);
if (! bFlag)
{
AfxMessageBox( “ Socket Error!”) ;
M_srvrSocket.Close( ) ;
PostQuitMessage( 0) ;
Return;
}
}
//“ 侦听” 成功,等待连接请求
if (! m_srvrSocket。 Listen( 1) )
{
int nErrorCode = m_srvrSocket.GetLastError( ) ;
if ( nError! =WSAEWOULDBLOCK)
{
AfxMessageBox( “ Socket Error!”) ;
M_srvrSocket.Close( ) ;
PostQuitMessage( 0) ;
Return;
}
}
}
4. 目前程序只能实现Echo功能,将信息原封不动的转发,若能将Accept中由
CNewSocket
pSocket = new CNewSocket( ) ;得到的 Socket指针存入一个
CList或一个数组中,便像 Client端那样,对所有的连接进行读写控制。
三. 总结
CAsyncSocket类为我们使用Socket提供了极大方便。 建立Socket的 WSAStartup
过程和 bind过程被简化成为Create过程, IP地址类型转换、 主机名和 IP地址转
换的过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是
CAsyncSocket类的异步特点,完全可以替代繁琐的线程操作。 MFC提供了大量的
类库,我们若能灵活的使用他们,便会大大提高编程的效率

以上是关于mfc编程 对话框中的listbox和进度条不能实时刷新,求高手指点!的主要内容,如果未能解决你的问题,请参考以下文章

从 .NET C# DLL 更新 MFC 对话框中的进度条

MFC进度条的美化

猎豹MFC--进度条CProgressCtrl 定时器SetTimer

NX二次开发-BlockUI对话框嵌套MFC对话框制作进度条

VS2010/MFC编程入门之二十(常用控件:静态文本框)

《MFC网络编程》学习日记2