关于界面上控件发现奇怪问题

Nosoft12345 2015-09-07 03:26:08
最近在做界面相关的东西,还是直接进入主题:

一个对话框,属性是child(不解释为什么是这个类型,但是程序所需),上面有个进度条子。还有一个按钮。

功能是:上传文件。

这个小界面的功能是,点击按钮后,选择要上传的文件,然后开启一个小线程去专门处理上传文件的部分。

在这里面,为了对对话框上的进度条子进行setpos,调用了诸如:hProgress=GetDlgItem、CProgressCtrl * cProgress = (CProgressCtrl *)CWnd::FromHandle(hProgress);等相关的代码

在开始的时候,这个代码没有问题。然后当进度条走到一段距离后,程序突然报错。显示afxcmn2.inl 363行。异常

去这里看了下,说 assert( iswindow(hwnd) 大致的意思就是说 这个hwnd为null。

然后为了验证这个问题,在代码增加了判断 if( cProgress == NULL || hProgress== NULL )等类似的判断

然后又debug程序,跑了会,就在这里弹出提示

说这个hwnd为null

=========================================================================================



如果这个有问题,为什么在开始到报错之间的一段时间内,这样调用上面的代码,却没有问题呢。

而是用着用着就报错了。

而且中途没有其他的操作 ,就是看着它走动进度条子。

用spy++ 也看了下,没看出什么问题来

...全文
159 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Nosoft12345 2015-09-10
  • 打赏
  • 举报
回复
引用 16 楼 worldy 的回复:
[quote=引用 14 楼 Nosoft12345 的回复:] [quote=引用 11 楼 worldy 的回复:] lz不知道你自己在哪出了问题,试了一下,是完全没有问题的: [/code]
我之前的版本,跟你这个完全一样,也没问题。 我现在界面上都改了,对窗口进行了分割,左边是树形的窗口,每次点树形节点时,左边会出现一个对话框界面,此对话框界面 child类型,然后用完全一样的方法,代码一样,就报错。 我很纳闷、换成child类型就不行了吗? ============== 另外很感谢qyl_qiyalu,的确,换成定时器后,就没问题了。 [/quote] 会报错,你肯定是哪个地方不对[/quote] 是的,也确实没找到问题真的出的地方。
worldy 2015-09-10
  • 打赏
  • 举报
回复
引用 14 楼 Nosoft12345 的回复:
[quote=引用 11 楼 worldy 的回复:] lz不知道你自己在哪出了问题,试了一下,是完全没有问题的: [/code]
我之前的版本,跟你这个完全一样,也没问题。 我现在界面上都改了,对窗口进行了分割,左边是树形的窗口,每次点树形节点时,左边会出现一个对话框界面,此对话框界面 child类型,然后用完全一样的方法,代码一样,就报错。 我很纳闷、换成child类型就不行了吗? ============== 另外很感谢qyl_qiyalu,的确,换成定时器后,就没问题了。 [/quote] 会报错,你肯定是哪个地方不对
Nosoft12345 2015-09-10
  • 打赏
  • 举报
回复
我还是先给分吧。
Nosoft12345 2015-09-10
  • 打赏
  • 举报
回复
引用 11 楼 worldy 的回复:
lz不知道你自己在哪出了问题,试了一下,是完全没有问题的: [/code]
我之前的版本,跟你这个完全一样,也没问题。 我现在界面上都改了,对窗口进行了分割,左边是树形的窗口,每次点树形节点时,左边会出现一个对话框界面,此对话框界面 child类型,然后用完全一样的方法,代码一样,就报错。 我很纳闷、换成child类型就不行了吗? ============== 另外很感谢qyl_qiyalu,的确,换成定时器后,就没问题了。
redui 2015-09-07
  • 打赏
  • 举报
回复
确定窗口线程没有被阻塞或者在进行耗时调用?表现形式就是窗口无响应,消息队列被阻塞,然后队列......满了
worldy 2015-09-07
  • 打赏
  • 举报
回复
上面的 “// 工作者线程,处理所有的IOCP的完成通知”注释请无视
worldy 2015-09-07
  • 打赏
  • 举报
回复
lz不知道你自己在哪出了问题,试了一下,是完全没有问题的:
// WorkThreadXDlg.h : 头文件
//

#pragma once
#include "afxcmn.h"


#define WM_PROGRESS WM_USER+100

// CWorkThreadXDlg 对话框
class CWorkThreadXDlg : public CDialog
{
// 构造
public:
	CWorkThreadXDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_WORKTHREADX_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()

	//////////////////////////////////////////////////////////////////////////
	// 工作者线程,处理所有的IOCP的完成通知
	static BOOL bContinue;
	static DWORD WINAPI _TxThread(LPVOID lpParm)
	{
		CWorkThreadXDlg* pDlg=(CWorkThreadXDlg*)lpParm;
		while (bContinue)
		{
			::PostMessage(pDlg->m_hWnd, WM_PROGRESS,0,0);
			Sleep(200);
		}
		TRACE("Exit Threat!");
		return 0;
	}

public:
	CProgressCtrl TxProgress;
	afx_msg LRESULT ProgressChanged(WPARAM, LPARAM)
	{
		int nVal=TxProgress.GetPos();
		nVal++;
		TxProgress.SetPos(nVal);
		if(nVal==100) bContinue=FALSE;
		return 0;
	}
};
// WorkThreadXDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "WorkThreadX.h"
#include "WorkThreadXDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CWorkThreadXDlg 对话框




CWorkThreadXDlg::CWorkThreadXDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CWorkThreadXDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CWorkThreadXDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_PROGRESS1, TxProgress);
}

BEGIN_MESSAGE_MAP(CWorkThreadXDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_MESSAGE(WM_PROGRESS,&ProgressChanged)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CWorkThreadXDlg 消息处理程序

BOOL CWorkThreadXDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	TxProgress.SetRange(0,100);
	TxProgress.SetPos(0);
	HANDLE hThread= CreateThread(0,0,&_TxThread,(LPVOID)this,0,0);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CWorkThreadXDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CWorkThreadXDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CWorkThreadXDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

BOOL CWorkThreadXDlg::bContinue=TRUE;

qyl_qiyalu 2015-09-07
  • 打赏
  • 举报
回复
以前做过显示进度条的功能,希望对你有用,做法如下: 新开线程进行数据上传,同时设置一个共享变量Var,对上传次数进行计数。界面线程中把SetPos(Var)放在timer中,可以实现对进度条的更新。
Nosoft12345 2015-09-07
  • 打赏
  • 举报
回复
::PostMessageW(hUpgradedlg,WM_MY_PROGRESS_MSG,0,0); CUpgradeDlg::OnDelMsg(....) { m_ctl_grosess.setpos(..);//去掉,程序就不不错,至是界面上进度条没有变化。 }
zgl7903 2015-09-07
  • 打赏
  • 举报
回复
是不是有越界操作, 导致指针被修改? 添加一个数据断点看看
worldy 2015-09-07
  • 打赏
  • 举报
回复
你工作线程是怎么传消息的?
Nosoft12345 2015-09-07
  • 打赏
  • 举报
回复
刚才用postmessage 试了下,也不行,提示 资源不用。 这个对话框上 的进度条,关联的一个控件变量,如:m_ctl_progress。 在工作线程发送消息后,在对话框消息处理函数里, m_ctl_progress。setpos...也报错,也提示资源不可用
Nosoft12345 2015-09-07
  • 打赏
  • 举报
回复
而且提示 :所需资源不可用
Nosoft12345 2015-09-07
  • 打赏
  • 举报
回复
引用 3 楼 worldy 的回复:
setpos操作应该在上传线程里调用的吧, 建议lz工作线程里不要执行界面相关的操作,工作线程处理界面非常容易发生冲突,工作线程只是简单的PostMessage发送消息给界面线程,然后所有的操作由界面线程去处理
是的,是在上传线程里调用的。 我用过sendmessage,给对话框发消息,但也会出现这个情况。
worldy 2015-09-07
  • 打赏
  • 举报
回复
setpos操作应该在上传线程里调用的吧, 建议lz工作线程里不要执行界面相关的操作,工作线程处理界面非常容易发生冲突,工作线程只是简单的PostMessage发送消息给界面线程,然后所有的操作由界面线程去处理
Nosoft12345 2015-09-07
  • 打赏
  • 举报
回复
GetDlgItem(hdlg, IDC_PROGRESS1) 主要是这里返回的hwnd 为null
Nosoft12345 2015-09-07
  • 打赏
  • 举报
回复
_AFXCMN_INLINE int CProgressCtrl::SetPos(int nPos) 363// { ASSERT(::IsWindow(m_hWnd)); return (int) ::SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L); } 如果一开始调用这个,就报错,也好找问题,但是他用着用着 就在这里报错了

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧