VC 如何在delphi 线程调用控件里调用主窗口的控件

如何在别的线程中调用主窗口控件的属性_百度知道
如何在别的线程中调用主窗口控件的属性
我有更好的答案
创建线程时,传主窗口的this,线程中得到主窗口句柄this。然后使用你要调用的属性相关的函数一定有个HWND参数,填上线程得到的主窗口传过来的句柄这个变量。
我要在工作线程里,调用主窗口CheckBox1.Checked的值我直接调用,返回的结果是错误的。像下面的代码,在主窗口中调用是正常,在别的线程中调用就会出错。if (true == CheckBox1.Checked)
MessageBox.Show(&CheckBox1.Checked&);
}好像是有BeginInvoke之类的可以用,但不知道具体什么用,谢谢!
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。09-1008-1909-1209-09
10-1810-1810-1810-17
◇本站云标签在C#中,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程是不同的空间,因此想要在子线程来操作窗体上的控件,是不可能简单的通过控件对象名来操作,但不是说不能进行操作,微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的控件操作。
要实现该功能,有两种方法可以选择:
1、在程序初始化的时候对要操作的控件设置下面的属性:
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls& =&
这样,系统就不会再抛出上面所说的这个错误了。
从实质上说,该方法是通过采用取消线程安全保护模式的方式实现的,所以不建议采用。
2、基本思路如下:
把想对另一线程中的控件实施的操作放到一个函数中,然后使用delegate代理那个函数,并且在那个函数中加入一个判断,用InvokeRequired 来判断调用这个函数的线程是否和控件线程处于同一线程中,如果是则直接执行对控件的操作,否则利用该控件的Invoke或BeginInvoke方法来执行这个代理。示例代码如下:
2 using System.Collections.G
3 using System.Windows.F
5 using System.T
7 namespace 子线程操作主线程窗体上的控件
public partial class frmMain : Form
/***************************************************** 定义该类的私有成员 ****************************************************/
/// &summary&
/// 定义一个队列,用于记录用户创建的线程
/// 以便在窗体关闭的时候关闭所有用于创建的线程
/// &/summary&
private List&Thread& ChaosThreadL
/***************************************************** 该类的初始化相关函数 ****************************************************/
/// &summary&
/// 窗体的初始化函数,初始化线程队列ChaosThreadList
/// &/summary&
public frmMain()
InitializeComponent();
ChaosThreadList = new List&Thread&();
/// &summary&
/// 窗体的关闭事件处理函数,在该事件中将之前创建的线程全部终止
/// &/summary&
/// &param name="sender"&&/param&
/// &param name="e"&&/param&
private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
if (ChaosThreadList.Count & 0)
//编列自定义队列,将所有线程终止
foreach (Thread tWorkingThread in ChaosThreadList)
tWorkingThread.Abort();
/***************************************************** 定义该类的自定义函数 ****************************************************/
/// &summary&
/// 定义一个代理
/// &/summary&
/// &param name="index"&&/param&
/// &param name="MSG"&&/param&
private delegate void DispMSGDelegate(int index,string MSG);
/// &summary&
/// 定义一个函数,用于向窗体上的ListView控件添加内容
/// &/summary&
/// &param name="iIndex"&&/param&
/// &param name="strMsg"&&/param&
private void DispMsg(int iIndex,string strMsg)
if (this.lstMain.InvokeRequired==false)
//如果调用该函数的线程和控件lstMain位于同一个线程内
//直接将内容添加到窗体的控件上
ListViewItem lvi = new ListViewItem();
lvi.SubItems[0].Text = iIndex.ToString();
lvi.SubItems.Add(strMsg);
this.lstMain.Items.Insert(0, lvi);
//如果调用该函数的线程和控件lstMain不在同一个线程
//通过使用Invoke的方法,让子线程告诉窗体线程来完成相应的控件操作
DispMSGDelegate DMSGD = new DispMSGDelegate(DispMsg);
//使用控件lstMain的Invoke方法执行DMSGD代理(其类型是DispMSGDelegate)
this.lstMain.Invoke(DMSGD, iIndex, strMsg);
/// &summary&
/// 定义一个线程函数,用于循环向列表中添加数据
/// &/summary&
private void Thread_DisplayMSG()
for (int i = 0; i & 10000; i++)
DispMsg(i + 1, "Welcome you : " + (i + 1).ToString());
Thread.Sleep(10);
/***************************************************** 定义该类的事件处理函数 ****************************************************/
/// &summary&
/// 【开始】按钮的单击事件处理函数,新建一个线程向窗体上的ListView控件填写内容
/// &/summary&
/// &param name="sender"&&/param&
/// &param name="e"&&/param&
private void btnBegin_Click(object sender, EventArgs e)
//创建一个新的线程
Thread tWorkingThread = new Thread(Thread_DisplayMSG);
//将新建的线程加入到自定义线程队列中,以便在窗体结束时关闭所有的线程
ChaosThreadList.Add(tWorkingThread);
//开启线程
tWorkingThread.Start();
这样子就可以实现用子线程去操作主线程窗体上的控件的内容,同时,又不影响主线程对窗体上其他控件的响应。程序运行截图如下:
&点击[开始]按钮,程序开启一个新的线程,不断向列表中添加新的数据,而同时不会影响主界面对其它控件(例如:文本框)的响应。
INVOKE方法的作用:
它使该控件所在的线程执行Invoke方法参数中指定的代理,也就是使主线程执行我们想对控件进行的操作。
阅读(...) 评论()这里是马甲用于收藏废品的地方,欢迎程序猿入群 4204218
VC在线程中操作界面
版权声明请尊重原创作品。转载请保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正。
多线程是我们在编程中经常遇到的问题,线程执行完后往往要把执行的结果传给主线程,但是MFC的控件不是线程安全的,所以在线程中操作界面是一件很危险的事情。所以就需要安全的方法。这一系列篇文章我将介绍VC在线程操作界面方法。
问题描述:
1.界面上有两个Button m_btn1,m_btn2。m_btn创建一个线程,来操作m_btn2。
void CMyDlg::OnButton1()
_beginthread(ThreadStart,0,(void *)(m_btn2));
2.线程执行的代码如下:
void ThreadStart(void* p)
CButton *btn = (CButton*)(p);
btn-&SetWindowText("aaaaaaa");
这是我们想象的代码,但是如果这样写来,是不正确的。是因为MFC窗体程序的界面控件是由主线程来控制的,由于我在新创建的线程中也操作了界面的控件,这样就同时由两个线程操作一个控件。但是这两个线程又没有进行同步。所以就发生了错误。
下面我们就通过让工作线程和主线程进行同步来解决上面的问题。
1.定义MYMSG
#define MYMSG WM_USER +200
2.线程启动的代码如下:
void CMyDlg::OnButton1()
_beginthread(ThreadStart,0,(void *)(this));
3.线程执行的代码如下:
void ThreadStart(void* p)
CString str = "aaaaaa";
CMyDlg *btn = (CMyDlg*)(p);
PostMessage(btn-&m_hWnd,MYMSG,WPARAM(&str),NULL);
Sleep(1000);
4.添加消息映射
ON_MESSAGE(MYMSG,OnMsgBack)
5.添加消息映射函数的定义和实现
LRESULT OnMsgBack(WPARAM wParam,LPARAM lParam);
LRESULT CMyDlg::OnMsgBack(WPARAM wParam,LPARAM lParam)
CString* str = (CString*)wP
m_btn2.SetWindowText(*str);
这样就完成了在线程中操作界面的工作。
我们也可以使用继承CwinThread的类,然后在消息映射中用
ON_THREAD_MESSAGE来处理往线程中发送的消息。
在线程中往主线程PostMessage发送数据的时候,一定要保证数据在主线程使用之前是存在的。Sleep(1000);是为了保证让主线程先处理到str。否则,执行完ThreadStart函数后,str自动销毁了,然后在外面访问这个已经销毁的指针是非常危险的。
本文来自CSDN博客,转载请标明出处:
版权声明请尊重原创作品。转载请保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正。
VC在线程中操作界面(二)
同样是在VC在线程中操作界面(一)的问题。我们可以通过另外一种方法来解决。
定义消息处理函数和SetWindowLong返回值
static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);
在Button1的处理函数中创建线程
void CMyDlg::OnButton1()
HWND h = m_btn2.m_hW
OldProc = SetWindowLong(h,GWL_WNDPROC,long(PluginWinProc));
_beginthread(ThreadStart1,0,(void *)(&m_btn2));
void CMyDlg::OnDestroy()
CDialog::OnDestroy();
SetWindowLong(m_btn2.m_hWnd,GWL_WNDPROC,OldProc);
static LRESULT CALLBACK PluginWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch (msg)
case MYMSG:
CWnd *wnd = CWnd::FromHandle(hwnd);
wnd-&SetWindowText("aaaaaaa");
CallWindowProc((WNDPROC)OldProc,hwnd,msg,wParam,lParam);
代码都非常简单。关键的是SetWindowLong这个函数,这个函数的作用是设定窗口属性。GWL_WNDPROC 为窗口过程设置新地址。下面是MSDN中关于SetWindowLong和GWL_WNDPROC的说明:
若使用SetWindowLong函数和GWL_WNDPROC索引替换窗口过程,则给定的窗口过程必须遵
循WindowProc回调函数的说明中指定的准则。
使用GWL_WNDPROC索引调用SetWindowLong函数可创建该窗口类的子类(窗口类用来创建窗
口)。应用程序不得用另一个过程的窗口产生子类。
当然要在使用完后在用SetWindowLong原来的窗口过程设置回去。使用这种方法可用于修改你无法更改代码的类,可以重写他的消息处理函数。
本文来自CSDN博客,转载请标明出处:
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!vc如何自定义消息与在线程中向主窗体控件发送数据
如何定义消息:
1.定义消息:
在对话框类的头文件中定义一个自定义消息
#define WM_MY_MESSAGE WM_USER+100
2.在类中声明该消息的处理函数:
在该类声明的内部的protected:下声明如:
afx_msg LRESULT MyMessage(WPARAM wParam, LPARAM lParam);
3.在类的消息映射表中加入映射项
在该类的源文件的消息映射表中添加一条消息处理记录
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_MESSAGE(WM_MY_MESSAGE ,MyMessage)
END_MESSAGE_MAP()
4.在类的实现文件中添加该消息的处理函数
添加一个消息处理函数,如:
LRESULT CMyDialog::MyMessage(WPARAM wParam,LPARAM lParam)
........//数据的处理
5.调用SendMessage函数或是PostMesage函数给主窗体发消息,
首先获取主窗体的句柄
HWND hHwnd = GetSafeHwnd();
然后再线程函数里面
DWORD _stdcall ListenProc(LPVOID Param)
............
char *sendstr="需要发送的数据";
PostMessage(hWnd,WM_MY_MESSAGE,(WPARAM)sendstr,0);
............
return 0L;
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 delphi 线程调用控件 的文章

 

随机推荐