搜索

tag 标签: 对话框

相关帖子

版块 作者 回复/查看 最后发表
suoma最后一篇labview帖子 attach_img 【测试/测量】 suoma 2016-12-20 7 2415 soso 2016-12-21 13:52
AltiumDesigner的preference里隐藏的功能——PCB缺省设置 attach_img PCB设计 okhxyyo 2016-5-18 5 3949 金老师 2017-10-18 16:25
【芯航线FPGA学习】Quartus II 15.1软件开启代码自动补全功能 attach_img FPGA/CPLD 小梅哥 2016-4-14 0 1111 小梅哥 2016-4-14 10:56
CCS4.1.2连接目标板的时候总是弹出一个对话框然后就关了 attach_img 【微控制器 MCU】 WANGZHEWANGZHE 2016-2-27 12 1473 michael_llh 2016-2-27 22:37
Altium Desinger怎么走蛇形线 attach_img PCB设计 okhxyyo 2016-1-14 43 34972 蓝天007 2019-9-5 10:03
Altium Designer铺铜那件事儿(一) attach_img PCB设计 okhxyyo 2015-12-30 32 43853 luoke1999 2018-4-21 09:30
PADS Layout(PowerPCB)中设置板框倒角 信息发布 boli505 2015-8-29 0 808 boli505 2015-8-29 16:22
采用CorelDraw向Altium Designer中导入图片 信息发布 boli505 2015-8-27 0 808 boli505 2015-8-27 16:08
Allegro中针对铺铜不能自动更新 信息发布 boli505 2015-8-20 0 1111 boli505 2015-8-20 10:23
DA14580开发学习教程1---开发环境搭建+裸机实验 attach_img 信息发布 ranliu 2015-7-24 2 5155 hekang889988 2015-7-29 17:14
PADS Logic 电源符号添加 信息发布 boli505 2015-8-28 0 909 boli505 2015-8-28 16:05
Powerpcb/Pads输出Gerber文件详解 信息发布 boli505 2015-9-2 0 707 boli505 2015-9-2 15:14
1788外扩了SDRAM,系统总是跑不起来,总是产生HardFault。 attach_img 【NXP LPC MCU】 zsz2008610 2015-12-3 8 3353 zsz2008610 2015-12-6 01:07
AD15弹出的对话框太大,大到没法点确认了,怎么解决? attach_img PCB设计 freeyounger 2016-9-17 26 12040 TANG20051008 2017-3-13 17:09
众一电路提供Protel 99 SE转gerber文件步骤 信息发布 llh2006 2016-10-11 1 1014 llh2006 2016-10-11 09:42
求助:如何实时更新对话框中的数据,如在对话框中进行秒表设计 【uCOS/uCGUI】 ygrong_2008 2016-10-27 0 2828 ygrong_2008 2016-10-27 09:11
使用datalog函数,如何得到实时的波形? attach_img 【微控制器 MCU】 xiangou123 2016-11-24 0 1717 xiangou123 2016-11-24 16:16
PCB设计软件操作之两种常见的差分信号设定方法 attach_img 信息发布 kdyhdl 2017-1-4 0 404 kdyhdl 2017-1-4 10:46
高速PCB设计allegro软件操作导入网表的两种方法 attach_img 信息发布 kdyhdl 2017-2-8 0 606 kdyhdl 2017-2-8 11:11
高速PCB设计软件allegro之DXF文件导入操作步骤 attach_img 信息发布 高速PCB设计 2017-2-15 0 707 高速PCB设计 2017-2-15 15:11

相关日志

分享 打开proe出现“当前页面脚本发生错误”对话框解决方法
夏至将至 2017-5-26 20:46
很多朋友们可能在打开proe时,有的会出现“当前页面脚本发生错误”的对话框(如图),这样每次打开都很麻烦,但如何解决这一问题呢,下面给大家分享下解决的方法。 出现这一问题的原因是什么呢? 是因为默认打开 pro e时浏览器会打开PTC公司的网页,由于PTC网站升级,导致此网页中的代码有问题,所以才会出现此错误提示,并导致PROE停止响应,无法正常使用。 解决方法: 1、关闭网络连接,如果是ADSL关掉即可,如果是公司网络可能受权限控制只能拔掉网线。否则只要PROE启动就会出错,无法进行下面步骤的 设置 。 2、如图,点“工具”、“屏幕定制”、“浏览器”,取消勾选“缺省情况下,加载PRO/E时展开浏览器”,注意将 config .win保存到启动目录下! 3、然后点“工具”、“选项”、 配置 config.pro增加以下选项:(永久取消PROE启动时载入网页) web_browser_homepageabout:blank (上面这句配置的意思是让PROE启动时打开空白页面)然后保存到proe启动目录下或者text目录下, 文件 名字是config.pro 然后连接网络重新启动PROE,应该不会再出现错误了;如果还出现错误那就是上面说的config.pro和config.win没设置好。
0 个评论
分享 DialogFragment详解
huanghai381 2014-9-21 23:46
详解一: Android提供alert、prompt、pick-list,单选、多选,progress、time-picker和date-picker对话框,并提供自定义的dialog。在Android 3.0后,dialog基于fragment,并对之前版本提供兼容支持库,也就是说对于开发者而言,dialog是基于DialogFragment的,但此时需要在应用中加入相关的兼容库。 和Windows或者网页JS的Dialog不同,Android的dialog是异步的,而不是同步的。对于同步的dialog,显示dialog后,下一行代码会等到dialog结束,即下一行代码可以知道dialog的输入以及用户点击的button。而对于异步的dialog,dialog显示后,下一行代码继续执行,而不是等dialog消失,通过callback来处理dialog的事件。异步的dialog也意味着应用的代码也可以关闭dialog。 我们的小例子通过菜单触发分别触发告警框和自定义布局提示框,提示框中有三个button,其中一个Help按钮可以再触发一个帮助内容的对话框。 创建dialog fragment 对话框基于DialogFrame,告警框AlterDialogFrament类如下,如何通过newInstance()创建实例在Fragment的学习中已经学过,不再详述。newInstance()有两个参数,一是告警框的标题,一是告警框的内容。 public class AlterDialogFragment extends DialogFragment { /*【步骤1】:通过newInstance()创建实例,并返回,这里的处理和系统从save状态中re-create相同。 * 1、通过缺省构造函数创建对象 * 2、将传递的信息设置为fragment的参数 * 3、返回对象 * */ public static AlterDialogFragment newInstance(String title,String message){ AlterDialogFragment adf = new AlterDialogFragment(); Bundle bundle = new Bundle(); bundle.putString("alert-title", title); bundle.putString("alert-message", message); adf.setArguments(bundle); return adf; } ...... 略,见后文...... } 自定义布局提示框PromptDialogFragment同样是DialogFragment的继承。类似的,代码如下: public class PromptDialogFragment extends DialogFragment { public static PromptDialogFragment newInstance(String prompt){ PromptDialogFragment pdf = new PromptDialogFragment(); Bundle b = new Bundle(); b.putString("prompt-message", prompt); pdf.setArguments(b); return pdf; } ......略,见后文...... } Activity显示对话框 在MyActivity中,通过optionsMenu来分别触发告警框和提示框的显示,代码如下: public class MainActivity extends Activity{ //设置告警框、提示框和帮助框的dialog fragment的tag。 public final static String ALERT_DIALOG_TAG = "ALERT_DIALOG_TAG"; public final static String PROMPT_DIALOG_TAG = "PROMPT_DIALOG_TAG"; public final static String HELP_DIALOG_TAG = "HELP_DIALOG_TAG"; …... 略 : 设置UI和创建OptionsMenu ...... @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()){ case R.id.alter_dialog: alterDialogTestCase(); break; case R.id.prompt_dialog: promptDialogTestCase(); default: break; } return false; } /* 触发告警框:通过dialogFragment.show()触发 * 我们注意对于FragmentTransaction ft,代码中没有执行ft.commit()。查看DialogFragment的show方法的源代码,如下 public void show(FragmentManager manager, String tag) { mDismissed = false; mShownByMe = true; FragmentTransaction ft = manager.beginTransaction(); ft.add(this, tag); ft.commit(); } public int show(FragmentTransaction transaction, String tag) { mDismissed = false; mShownByMe = true; transaction.add(this, tag); mViewDestroyed = false; mBackStackId = transaction.commit(); return mBackStackId; } * 这里面的操作含有ft.add()和ft.commit(),故不需要在代码中重复commit,否则会异常。 add表示加入到activity,这里没有填容器的ID,即contianerViewID为0,表示不加载在具体容器内,对于dialog,container为null。 * 这本例中也可以通过adf.show(getFragmentManager(), ALERT_DIALOG_TAG)来实现。对于将fragment transaction作为参数的方式,在调用show()之前,可通过fragment transaction进行控制,如加入到back stack中,这将在按提示框的Help按钮弹帮助框中进行演示。在show()中,同时设置了fragment的tag,可用于索引,可在fragment中可以通过getTag()获取。 */ private void alterDialogTestCase(){ AlterDialogFragment adf = AlterDialogFragment.newInstance("Alert", "This is the Alter Message for test!"); FragmentTransaction ft = getFragmentManager().beginTransaction(); adf.show(ft, ALERT_DIALOG_TAG); } /* 弹出提示框 */ private void promptDialogTestCase(){ PromptDialogFragment pdf = PromptDialogFragment.newInstance("This is a Prompt Dialog!"); FragmentTransaction ft = getFragmentManager().beginTransaction(); pdf.show(ft, PROMPT_DIALOG_TAG); } /* 此为用户按对话框按键时被调用的方法,通过Toast显示相关信息。*/ public void onDialogDone(String tag, boolean cancelled, CharSequence message) { String s = tag + " responds with: " + message; if(cancelled) s = tag + " was cancelled by the user"; //Toast是没有button的信息框,在一定时间后消失,很适合用于debug。 Toast.makeText(this, s, Toast.LENGTH_LONG).show(); } } 通过fragment实现dialog的好处是:activity配置改变(例如转向)进行重构的情况下,fragment管理器能够自动重够,恢复原来的状态,无需人工干预。 详解二: DialogFragment的实例newInstance()已经在上一次学习笔记中实现。我们创建dialog的UI,可以通过重写DialogFragment的两个函数当中的一个来实现,这两个函数是onCreateView()和onCreateDialog(),前者返回view,后者返回dialog,如同通过AlertDialog.Builder构造一样。 重写onCreateView() 重写onCreateView()是fragment的传统方式,适合自定义的对话框,本例适合用于提示框,如下图所示。通过按菜单弹出提示框,提示框由一个TextView,一个EditText和三个Button组成UI。按不同的按钮触发不同的处理。小例子自作范例,按Save和Dismiss按钮,都会调用Activity的onDialogDone()函数,根据用户的实际操作,显示不同的信息。按Help按钮,则弹出一个帮助框。再弹框在稍后学习笔记中实现。 通过onCreateView()设置UI和按键反馈 利用Fragment的onCreateView()来实现对话框的UI和Fragment学习中没有差别,在本例中,我们增加了按钮点击的触发,代码如下: public class PromptDialogFragment extends DialogFragment implements OnClickListener { public static PromptDialogFragment newInstance(String prompt){ ...略... } @Override //通过重写Fragment的onCreateView()实现dialog的UI public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //1、通过inflate,根据layout XML定义,创建view View v = inflater.inflate(R.layout.prompt_dialog, container,false); TextView tv = (TextView)v.findViewById(R.id.prompt_message); tv.setText(getPrompt()); //2、注册三个button的按键监听listener Button dismissBtn = (Button)v.findViewById(R.id.button_dismiss); dismissBtn.setOnClickListener(this); Button saveBtn = (Button)v.findViewById(R.id.button_save); saveBtn.setOnClickListener(this); Button helpBtn = (Button)v.findViewById(R.id.button_help); helpBtn.setOnClickListener(this); return v; } private String getPrompt(){ Bundle b = getArguments(); return b.getString("prompt-message"); } @Override //在onCreate中设置对话框的风格、属性等 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //如果setCancelable()中参数为true,若点击dialog覆盖不到的activity的空白或者按返回键,则进行cancel,状态检测依次onCancel()和onDismiss()。如参数为false,则按空白处或返回键无反应。缺省为true setCancelable(true); //可以设置dialog的显示风格,如style为STYLE_NO_TITLE,将被显示title。遗憾的是,我没有在DialogFragment中找到设置title内容的方法。theme为0,表示由系统选择合适的theme。 int style = DialogFragment.STYLE_NO_NORMAL, theme = 0; setStyle(style,theme); } @Override //仅用于状态跟踪 public void onCancel(DialogInterface dialog) { showInfo("onCancel() is called"); super.onCancel(dialog); } @Override //仅用户状态跟踪 public void onDismiss(DialogInterface dialog) { showInfo("onDismiss() is called"); super.onDismiss(dialog); } @Override //Button按键触发的回调函数 public void onClick(View v) { MainActivity act = (MainActivity)getActivity(); switch(v.getId()){ case R.id.button_dismiss: act.onDialogDone(getTag(), true, null); //调用activity的onDialogDone(),通过Toast显示相关信息 dismiss(); //关闭对话框,并触发onDismiss()回调函数。 break; case R.id.button_help: … 略:以后实现 … break; case R.id.button_save: TextView tv = (TextView)getView().findViewById(R.id.input_text); act.onDialogDone(getTag(), false, " " + tv.getText()); //调用activity的onDialogDone(),通过Toast显示相关信息 dismiss(); //关闭对话框,并触发onDismiss()回调函数 break; default: break; } } private void showInfo(String s){ Log.d("PromptDialogFragment",s); } } 信息保存 如果用户在输入框中填入text,然后进行屏幕的横屏和竖屏切换,这涉及到填入内容的保存,可以通过onSaveInstanceState(),将之保存到fragment的Bundle savedInstanceState中,并在onCreateView()中将之恢复。但是在Android 4.2版本的测试中,系统已经能够自动保存和恢复,无需加入代码。当然,安全地我们仍建议进行以下处理。 public class PromptDialogFragment extends DialogFragment implements OnClickListener{ private EditText et = null; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ...... et = (EditText)v.findViewById(R.id.input_text); if(savedInstanceState != null){ CharSequence text = savedInstanceState.getCharSequence("input"); et.setText(text == null ? "" : text); } ...... } @Override public void onSaveInstanceState(Bundle outState) { outState.putCharSequence("input", et.getText()); super.onSaveInstanceState(outState); } } 重写onCreateDialog() 对于简单的对话框,可以通过AlterDialog.Builder直接创建对话框的UI,本例用于告警框,如下图。AlertDialog.Builder在Android 3.0版本之前的创建对话框方式,在之后的版本中,可用在DialogFragment中,适用于创建简单对话框。 代码如下。虽然都是OnClickListener接口,但提示框的是View.OnClickListener,这里是DialogInterface.OnClickListener。 public class AlterDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { /*【步骤1】:通过newInstance()创建实例并返回* */ public static AlterDialogFragment newInstance(String title,String message){ … 略 … } private String getTitle(){ return getArguments().getString("alert-title"); } private String getMessage(){ return getArguments().getString("alert-message"); } /* 【步骤2】创建view可以通过两个途径,一是fragment中的onCreateView(),二是DialogFragment中的onCreateDialog()。 * 前者适合对自定义的layout进行设置,具有更大的灵活性 * 而后者适合对简单dialog进行处理,可以利用Dialog.Builder直接返回Dialog对象 * 从生命周期的顺序而言,先执行onCreateDialog(),后执行oonCreateView(),我们不应同时使用两者。 * */ @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder b = new AlertDialog.Builder(getActivity()) .setTitle(getTitle()) .setMessage(getMessage()) .setPositiveButton("OK", this) //设置回调函数 .setNegativeButton("Cancel",this); //设置回调函数 return b.create(); } @Override //按键触发的回调函数 public void onClick(DialogInterface dialog, int which) { boolean isCancel = false; if(which == AlertDialog.BUTTON_NEGATIVE) { //判断用户所按何键 isCancel = true; } MyActivity act = (MyActivity) getActivity(); act.onDialogDone(getTag(), isCancel, "CLick OK, Alert dismissed"); } } 详解三: 提示框的按钮Help,将触发弹出新的帮助提示框。 帮助提示框的实现 帮助提示框的实现很简单,利用重写onCreateView( )的方式,点击按钮是执行dismiss(),关闭对话框即可。 代码不在此重复。dialog fragment的关闭有两种方式,一种是在dialog fragment中直接执行dismiss(),我们来看看DialogFragment的源代码片段: view plain copy /** * Dismiss the fragment and its dialog. If the fragment was added to the * back stack, all back stack state up to and including this entry will * be popped. Otherwise, a new transaction will be committed to remove * the fragment. */ public void dismiss() { dismissInternal( false ); } void dismissInternal( boolean allowStateLoss) { if (mDismissed) { return ; } mDismissed = true ; mShownByMe = false ; if (mDialog != null ) { mDialog.dismiss(); mDialog = null ; } mViewDestroyed = true ; if (mBackStackId = 0 ) { getFragmentManager().popBackStack(mBackStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE); mBackStackId = - 1 ; } else { FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.remove( this ); if (allowStateLoss) { ft.commitAllowingStateLoss(); } else { ft.commit(); } } } 如果back stack堆栈有该dialog,将其pop出来,否则ft.remove(this); ft.commit();。估计pop的操作也包含ft.remove()和ft.commit()。调用dismiss()会触发onDismiss()回调函数。跟踪状态,如下。 实现再弹框 在PromptDialogFragment中实现弹框的相关代码如下。这里采用另一种关闭dialog的方法,通过fragment transaction进行控制。 public void onClick(View v) { ... ... switch(v.getId()){ case R.id.button_help: FragmentTransaction ft = getFragmentManager().beginTransaction(); /* 如果不执行remove(),prompt dailog在下层,跟踪状态,系统即不会进入onDismiss()状态。主要考虑美观的问题,如果下面prompt对话框大于帮助框,视觉效果不好。下面左图为执行了remove()的效果,右图为不执行remove()的效果。 对于Dialog,container为0或者null。 */ ft.remove(this); /* 将当前的PromptDialogFragment加入到回退堆栈,当用户按返回键,或者通过按帮助框的Close按钮dismiss帮助框是,重新显示提示框。 对于back stack的处理,系统具有一定的智能。例如:执行两次addToStackStack(),实际不会重复压栈。 有例如:注释掉remove()语句,即提示框不消失,而是在帮助框的下面,如右图,由于提示框存在,我们并不需要将提示框键入到back stack,但是在实验中发现是否有addToBackStack()都不会结果有影响,系统能够分析到对象存在,不需要压栈。没有去查源代码,猜测通过mBackStackId比对来进行智能处理。 */ ft.addToBackStack(null); HelpDialogFragment hdf = HelpDialogFragment.newInstance(R.string.help_message); /* 对fragment的处理是通过fragment transaction,与在activity弹框一样,通过show()方式实现。 在此之前,我们已经通过transaction将当前的fragment加入到back stack中。*/ hdf.show(ft,MainActivity.HELP_DIALOG_TAG); break; ... ... } } 通过remove()和addToBackStack()使得fragment从UI中消失,当仍可以通过fragment管理器和回退堆栈获取。 再谈fragment管理器 通过fragment管理器或者fragment transaction,我们可以对dialog fragment进行具体地控制。show()就是在管理器中加入fragment,dismiss()就是从管理器中去掉fragment。我们不能先进行add(),然后在进行show(),因此一个fragment对象只能加入管理器一次。如果fragment被dismiss(),将从管理器中删除,我们不能再通过管理器获取该fragment的信息。因此,如果我们想保留被dismiss的dialog的一些状态或信息,需要在dialog外进行保存,例如利用activity。 总结: 编程思想:封装接口 在小例子中,fragment会调用activity的onDialogDone()来显示Toast等信息。在真正项目中,fragment的编写并不需要了解activity的各类方法,好的编程风格是将fragment所涉及的方法以接口的方式封装起来,如下: public interface OnMyDialogClickListener { public void onDialogDone(String tag, boolean cancelled, CharSequence message); } 在activity中,增加接口的实现,如下: public class MainActivity extends Activity implements OnMyDialogClickListener { ...... public void onDialogDone(String tag, boolean cancelled, CharSequence message) { String s = tag + " responds with: " + message; if(cancelled) s = tag + " was cancelled by the user"; Toast.makeText(this, s, Toast.LENGTH_LONG).show(); showInfo(s); } } 相应地,在fragment中,对该方法的调用,可以写为: OnMyDialogClickListener act = (OnMyDialogClickListener)getActivity(); act.onDialogDone(……); 对于一些大型项目,如果我们无法确定activity是否真的实现了接口,可以在fragment的早期,即刚关联activity的阶段进行检测,如下: @Override public void onAttach(Activity activity) { //onAttach()是合适的早期阶段进行检查MyActivity是否真的实现了接口。 //采用接口的方式,dialog无需详细了解MyActivity,只需了解其所需的接口函数,这是真正项目中应采用的方式。 try{ OnMyDialogClickListener act = (OnMyDialogClickListener)activity; }catch(ClassCastException e){ …... activity并不真正支持接口的异常处理...... } super.onAttach(activity); } fragment和activity以其他fragment之间的通信 小例子演示了通过getActivity()获取接口对象或者直接获取activity的对象,实现两者之间的通信。此外fragment也可以通过fragment管理器,通过tag,获取其他fragment实例,从而进行fragment之间的通信。当然从编程思想的角度看,fragment之间的过多进行交叉调用,不利于程序的管控。
个人分类: 安卓开发|12135 次阅读|0 个评论
分享 关于uc/gui基于FRAMEWIN创建对话框的消息处理 (转载)
liufan 2014-2-12 17:15
对话框窗体的创建有两种方式,一种是基于 FRAMEWIN 的对话框窗体的创建,另一种是基于 WINDOW 的对话框窗体的创建。这两种方式创建的对话框返回的对话框句柄当然也是不同的,即:基于 FRAMEWIN 的对话框返回的句柄为 FRAMEWIN 控件的句柄;而基于 WINDOW 的对话框返回的是 WINDOW 控件的句柄。 具体的创建过程我们来看一下对话框的创建函数 GUI_CreateDialogbox() 。 /******************************************************************** * * GUI_CreateDialogbox ********************************************************************/ WM_HWIN GUI_CreateDialogBox(const GUI_WIDGET_CREATE_INFO* paWidget, int NumWidgets, WM_CALLBACK* cb, WM_HWIN hParent, int x0, int y0) { /* 首先创建对话框的窗体, paWidget 此时指向对话框创建资源列表中的第一个控件,即:作为对话框的中子控件载体的 WINDOW 或者是 FRAMEWIN 。根据你所创建的对话框资源列表的第一个元素来确定。返回值 hDialog =WINDOW 或者 FRAMEWIN 的句柄 */ WM_HWIN hDialog = paWidget-pfCreateIndirect(paWidget, hParent, x0, y0, cb); /* 下面这条语句比较关键。通过 WM_GetClientWindow ( hDialog )来获得对话框窗体的客户区控件的句柄。 1 基于 FRAMEWIN 的对话框: FRAMEWIN 控件创建时会同时创建一个他的子窗口,即客户区控件。对话框所有其他的空间以这个客户区窗口为父窗口,将所有控件显示在他的上面。所以,此处 hDialogClient =FRAMEWIN 客户区的句柄。 2 基于 WINDOW 的对话框: WINDOW 控件创建时没有创建一个所谓的客户区的窗口,所有其他的对话框控件的载体也就还是 WINDOW 本身。所以 hDialogClient = hDialog */ WM_HWIN hDialogClient = WM_GetClientWindow(hDialog); WIDGET_OrState(hDialog, paWidget-Flags); WM_ShowWindow(hDialog); WM_ShowWindow(hDialogClient); /* 接下来创建对话框其他的控件 */ while (--NumWidgets 0) { WM_HWIN hChild; /* paWidget++ ,指向下一个控件资源 */ paWidget++; /* 看清了,对话框其他控件资源都是客户区 hDialogClient 的子窗口 */ hChild = paWidget-pfCreateIndirect(paWidget, hDialogClient, 0, 0, 0); /* Create child window */ WM_ShowWindow(hChild); } /* 焦点设置在对话框资源列表中窗体控件的下一个控件 */ WM_SetFocusOnNextChild(hDialog); WM_SendMessageNoPara(hDialogClient, WM_INIT_DIALOG); /* 返回对话框句柄,说白了就是 WINDOW 或者 FRAMEWIN 的句柄 */ return hDialog; } 解释到这,你只要明白一件事:对话框创建完成后返回的对话框的句柄是 WINDOW 或者 FRAMEWIN 的句柄,而不是客户区的句柄( FRAMEWIN 才有客户区这一说)。 再来说明一个事情,对于所有控件如: BUTTON 、 CHECKBOX 、 FRAMEWIN 等等,都有一个原始的回调函数,这个回调函数位于 uc/GUI 内核中。但是为了扩展控件本身的消息处理能力, uc/GUI 允许我们在创建某个控件实体时再给这个对象实体增加一个回调函数。那么这两个回调函数之间存在什么关系呢?笼统的来说,当某个对象实体上发生事件后,事件以消息的形式首先到达控件的原始回调函数。在原始的回调函数中进行一般的消息处理,再通过某种机制来调用对象实体的回调函数进行特殊的消息功能处理。这种机制这里不再细说。接下来进入正题。 1 消息发送 我们在应用 uc/GUI 做一些具体应用时, uc/GUI 中的一般性的消息不会考虑用户的特殊应用。所以,有时候我们需要向对话框发送一些自定义的消息。而向对某个窗体发送我们自定义的消息,可以用以下两个通用的函数来完成: 1 void WM_SendMessage(WM_HWIN hWin, WM_MESSAGE* pMsg) ; 2 int WM_BroadcastMessage( WM_MESSAGE* pMsg) ; 应用第一个函数函数我们可以向一个特定的窗体发送一条消息,让这个窗体的回调函数来处理我们自定义的消息。 第二个函数是一个以广播的形式向当前所存在的所有窗体句柄发送我们自定义的消息。哈哈,注意了啊!!不是对话框才叫窗体。 TEXT 、 BUTTON 、 DIALOG 、 EDIT 等等 …… 所创建的、具有实体句柄的窗体都会被发送这样一条消息。个人感觉可能会引起资源的小小浪费。 2 基于 FRAMEWIN 对话框的消息处理 为了详细的了解基于 FRAMEWIN 对话框的消息处理,首先就必须看一下 FRAMEWIN 的原始回调函数。 下面就是 uc/GUI3.91 的 FRAMEWIN 原始回调函数的完整版。 /******************************************************************** * * Framewin Callback ********************************************************************/ static void _FRAMEWIN_Callback (WM_MESSAGE *pMsg) { FRAMEWIN_Handle hWin = (FRAMEWIN_Handle)(pMsg-hWin); FRAMEWIN_Obj* pObj = FRAMEWIN_H2P(hWin); GUI_RECT* pRect = (GUI_RECT*)(pMsg-Data.p); POSITIONS Pos; GUI_HOOK* pHook; /* Call hook functions */ for (pHook = pObj-pFirstHook; pHook; pHook = pHook-pNext) { int r; r = (*pHook-pHookFunc)(pMsg); if (r) { return; /* Message handled */ } } switch (pMsg-MsgId) { case WM_HANDLE_DIALOG_STATUS: if (pMsg-Data.p) { /* set pointer to Dialog status */ pObj-pDialogStatus = (WM_DIALOG_STATUS*)pMsg-Data.p; } else { /* return pointer to Dialog status */ pMsg-Data.p = pObj-pDialogStatus; } return; case WM_PAINT: _Paint(pObj); break; case WM_TOUCH: _OnTouch(hWin, pObj, pMsg); return; /* Return here ... Message handled */ case WM_GET_INSIDE_RECT: FRAMEWIN__CalcPositions(pObj, Pos); *pRect = Pos.rClient; return; /* Return here ... Message handled */ case WM_GET_CLIENT_WINDOW: /* return handle to client window. For most windows, there is no seperate client window, so it is the same handle */ pMsg-Data.v = (int)pObj-hClient; return; /* Return here ... Message handled */ case WM_NOTIFY_PARENT: if (pMsg-Data.v == WM_NOTIFICATION_RELEASED) { WM_MESSAGE Msg; Msg.hWinSrc = hWin; Msg.Data = pMsg-Data; Msg.MsgId = WM_NOTIFY_PARENT_REFLECTION; WM_SendMessage(pMsg-hWinSrc, Msg); } return; case WM_SET_FOCUS: /* We have received or lost focus */ if (pMsg-Data.v == 1) { if (WM_IsWindow(pObj-hFocussedChild)) { WM_SetFocus(pObj-hFocussedChild); } else { pObj-hFocussedChild = WM_SetFocusOnNextChild(pObj-hClient); } FRAMEWIN_SetActive(hWin, 1); pMsg-Data.v = 0; /* Focus could be accepted */ } else { FRAMEWIN_SetActive(hWin, 0); } return; case WM_TOUCH_CHILD: /* If a child of this framewindow has been touched and the frame window was not active, the framewindow will receive the focus. */ if (!(pObj-Flags FRAMEWIN_SF_ACTIVE)) { const WM_MESSAGE * pMsgOrg; const GUI_PID_STATE * pState; pMsgOrg = (const WM_MESSAGE*)pMsg-Data.p; /* The original touch message */ pState = (const GUI_PID_STATE*)pMsgOrg-Data.p; if (pState) { /* Message may not have a valid pointer (moved out) ! */ if (pState-Pressed) { WM_SetFocus(hWin); } } } break; case WM_NOTIFY_CHILD_HAS_FOCUS: _OnChildHasFocus(hWin, pObj, pMsg); break; case WM_DELETE: GUI_DEBUG_LOG("FRAMEWIN: _FRAMEWIN_Callback(WM_DELETE)\n"); GUI_ALLOC_FreePtr(pObj-hText); break; } /* Let widget handle the standard messages */ if (WIDGET_HandleActive(hWin, pMsg) == 0) { return; } WM_DefaultProc(pMsg); } 好了,我们主要来看一下其中的关于消息处理部分,即 switch (pMsg-MsgId) {} 部分。其中, case 的结尾有的是直接的函数返回,有的却是跳出 swtch 。二者有什么区别呢?本人理解的是以 return 结尾的消息,对话框接收到这类消息后,经 FRAMEWIN 的原始回调函数 _FRAMEWIN_Callback 处理后,这个消息就已经划上了句号,这个消息不再产生任何其他行为。而以 break 结尾的消息,经过 swtch 中的处理过程后,这个消息还没有完,接下来看函数末尾绿色部分语句。这里 WIDGET_HandleActive(hWin, pMsg) ,又将这个消息进行了一般消息的处理,如果一个消息在 WIDGET_HandleActive 中得到处理则这个函数返回 0 。返回 0 后, _FRAMEWIN_Callback 关于消息的处理也就告一段落,也就是说这个消息的处理过程划上了句号。如果一个消息没有在 WIDGET_HandleActive 中得到处理,则程序往下执行,这就到了 WM_DefaultProc(pMsg) 。 WM_DefaultProc(pMsg) 函数也是对于一些 GUI 中的特定消息进行了一般处理。但是有一个特殊的消息,那就是按键消息的处理比较特别,按键消息会通过这个函数将按键消息通知给他的父窗口来处理。处理过程如下: case WM_KEY: WM_SendToParent(hWin, pMsg); return; /* Message handled */ 其它的消息到此为止,湮灭在整个 GUI 中了。 说到这里,你会发现一个问题。这个函数好像跟我们对话框实体对象的回调函数没有任何关系。也就是说,如果一个我们自定义的消息发送个我们的对话框的实体对象后,实际上首先是由 _FRAMEWIN_Callback 来处理的。经过 _FRAMEWIN_Callback 处理后,我们的实体对象回调函数不会得到任何机会去处理它。最后的结果就是我们自定义的消息会湮灭在整个 GUI 中。 得到这样一个结论后,我们再来看一个回调函数,也就是 FRAMEWIN 的客户区句柄的回调函数。 /********************************************************************* * * Client Callback ********************************************************************/ static void FRAMEWIN__cbClient(WM_MESSAGE* pMsg) { WM_HWIN hWin = pMsg-hWin; WM_HWIN hParent = WM_GetParent(pMsg-hWin); FRAMEWIN_Obj* pObj = FRAMEWIN_H2P(hParent); WM_CALLBACK* cb = pObj-cb; switch (pMsg-MsgId) { case WM_PAINT: if (pObj-Props.ClientColor != GUI_INVALID_COLOR) { LCD_SetBkColor(pObj-Props.ClientColor); GUI_Clear(); } /* Give the user callback a chance to draw. * Note that we can not run into the bottom part, as this passes the parents handle */ if (cb) { WM_MESSAGE Msg; Msg = *pMsg; Msg.hWin = hWin; (*cb)(Msg); } return; case WM_SET_FOCUS: if (pMsg-Data.v) { /* Focus received */ if (pObj-hFocussedChild (pObj-hFocussedChild != hWin)) { WM_SetFocus(pObj-hFocussedChild); } else { pObj-hFocussedChild = WM_SetFocusOnNextChild(hWin); } pMsg-Data.v = 0; /* Focus change accepted */ } return; case WM_GET_ACCEPT_FOCUS: WIDGET_HandleActive(hParent, pMsg); return; case WM_KEY: if (((const WM_KEY_INFO*)(pMsg-Data.p))-PressedCnt 0) { int Key = ((const WM_KEY_INFO*)(pMsg-Data.p))-Key; switch (Key) { case GUI_KEY_TAB: pObj-hFocussedChild = WM_SetFocusOnNextChild(hWin); return; } } break; /* Send to parent by not doing anything */ case WM_GET_BKCOLOR: pMsg-Data.Color = pObj-Props.ClientColor; return; /* Message handled */ case WM_GET_INSIDE_RECT: /* This should not be passed to parent ... (We do not want parents coordinates)*/ case WM_GET_ID: /* This should not be passed to parent ... (Possible recursion problem)*/ case WM_GET_CLIENT_WINDOW: /* return handle to client window. For most windows, there is no seperate client window, so it is the same handle */ WM_DefaultProc(pMsg); return; /* We are done ! */ } /* Call user callback. Note that the user callback gets the handle of the Framewindow itself, NOT the Client. */ if (cb) { pMsg-hWin = hParent; (*cb)(pMsg); } else { WM_DefaultProc(pMsg); } } 看一下上面的程序,我来问一个问题。如果一个消息在 switch 中没有得到匹配,直截了当的说,如果客户区句柄收到了一个我们自定义的消息后,这个 Framewin 的客户区句柄会做什么?看函数最后部分的绿色语句,你会不会恍然大悟啊。呵呵,我们终于找到答案了。最后的答案就是,自定义消息不会在 switch 中得到任何处理。 if (cb) 会判断 Framewin 的回调函数是否存在,如果存在则会调用这个回调函数来处理这则消息。哈哈!!我们的消息终于有人管了。 是不是觉得结果来的太突然,那好,我再来对其中的细节进行一下解释。 cb------ 看程序开头部分的绿色语句 WM_CALLBACK* cb ,我们可以知道: Cb 是个回调函数的指针。指向哪个回调函数呢?看下面这条语句,这条语句是得到当前收到消息的客户区句柄的父窗口的句柄,客户区的父窗口是什么啊?很简单,就是他所对应的 FRAMEWIN 的实体对象的句柄,进一步说,就是对话框的句柄。 WM_HWIN hParent = WM_GetParent(pMsg-hWin); 再来看 cb 的赋值过程:这个指针最后指向了我们所创建的对话框实体对象的回调函数,(不是 FRAMEWIN 的原始回调函数,看清了。) WM_CALLBACK* cb = pObj-cb; hParent------ 将这个消息发送个句柄为 hParent 的回调函数,而不是客户区的句柄。这点很关键。 就这样,我们自定义的消息回到了我们在创建对话框时所赋予的那个回调函数中去了。在定义的回调函数中,对于自定义的消息就可以任你处置了。 你是不是还有疑问,那我们该怎么样向一个实体对话框发送自定义的消息呢?往下看。 回过头来看一下这两个发送消息的函数: 1 void WM_SendMessage(WM_HWIN hWin, WM_MESSAGE* pMsg) ; 2 int WM_BroadcastMessage( WM_MESSAGE* pMsg) ; 如果我们用第一个函数向一个对话框实体发送自定一消息,参数 WM_HWIN hWin 我们应该传递对话框的句柄;而参数 WM_MESSAGE* pMsg 应该传递我们自定义消息的地址。但是,我们前面说过,对话框的句柄其实就是 FRAMEWIN 的句柄,如果这样发送一个自定义消息给对话框,我们自定义的实体对话框回调函数是收不到的啊。怎么办,在发送个特定对话框句柄一个消息之前要简单处理一下程序如下: /* hWin 就是要想这个特定的对话框实体发送一个消息,通过它我们首先得到他的客户区句柄。但是如果我们的对话时基于 WINDOW 创建的话,这样也没关系,因为他返回的依然是 WINDOW 的句柄,也就是依然是对话框的句柄 */ WM_HWIN hDialogClient = WM_GetClientWindow(hWin); /* 将这个消息发送个给对话框客户区的句柄,最终会在我们自定义的实体对话框的回调函数中收到它。 */ WM_SendMessage(hDialogClient, pMsg) ; 如果我们用第二个函数向一个对话框实体句柄发送一条自定义的消息时,这个函数会向所有当前存在的有效句柄发送自定义的消息,当然也会包括对话框客户区的原始回调函数。所以我们同样也可以收到我们的自定义消息。 好了,关于基于 FRAMEWIN 创建对话框的消息处理就讲到这里了,希望能对大家在 uc/GUI 的应用开发中有所帮助。
个人分类: UCGUI|1571 次阅读|0 个评论

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-10-17 10:52 , Processed in 0.049860 second(s), 9 queries , Gzip On, MemCache On.

Powered by EEWORLD电子工程世界

© 2019 http://bbs.eeworld.com.cn/

返回顶部