请问ComboBox1出现的位置怎样设置?

Chartered 2003-10-15 10:23:27

在COMBOBOX的某一项长度大于COMBOBOX的长度,不能完全显示时, 可以用以下语句
设定ComboBox的长度

ComboBox1->Perform(CB_SETDROPPEDWIDTH,400,0);

但是这样做的时,下拉列表的左端和ComboBox的左端一样,那当ComboBox在屏幕右边时,如果某一项长度太长的话就会有一部分看不到了,而且连ScrollBar 也看不到,不能拖了,

请问有没有哪个参数可以设定下拉列表的左端的呢?
我不知道怎样查
int __fastcall Perform(unsigned Msg, int WParam, int LParam);

的Msg参数
...全文
158 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
Kabin 2003-10-15
  • 打赏
  • 举报
回复
这样都行?恭喜恭喜
Chartered 2003-10-15
  • 打赏
  • 举报
回复
哈哈,我自己想到解决的办法啦,
在OnDropDown和OnCloseUP里面分别加入
ComboBox1->Left-=200;

ComboBox1->Left+=200;
让下拉列表在出现时,让ComboBox也左移了,呵呵
ccrun.com 2003-10-15
  • 打赏
  • 举报
回复
这是winuser.h中CB_开头的一些定义:

#define CB_OKAY 0
#define CB_ERR (-1)
#define CB_ERRSPACE (-2)
#define CB_GETEDITSEL 0x0140
#define CB_LIMITTEXT 0x0141
#define CB_SETEDITSEL 0x0142
#define CB_ADDSTRING 0x0143
#define CB_DELETESTRING 0x0144
#define CB_DIR 0x0145
#define CB_GETCOUNT 0x0146
#define CB_GETCURSEL 0x0147
#define CB_GETLBTEXT 0x0148
#define CB_GETLBTEXTLEN 0x0149
#define CB_INSERTSTRING 0x014A
#define CB_RESETCONTENT 0x014B
#define CB_FINDSTRING 0x014C
#define CB_SELECTSTRING 0x014D
#define CB_SETCURSEL 0x014E
#define CB_SHOWDROPDOWN 0x014F
#define CB_GETITEMDATA 0x0150
#define CB_SETITEMDATA 0x0151
#define CB_GETDROPPEDCONTROLRECT 0x0152
#define CB_SETITEMHEIGHT 0x0153
#define CB_GETITEMHEIGHT 0x0154
#define CB_SETEXTENDEDUI 0x0155
#define CB_GETEXTENDEDUI 0x0156
#define CB_GETDROPPEDSTATE 0x0157
#define CB_FINDSTRINGEXACT 0x0158
#define CB_SETLOCALE 0x0159
#define CB_GETLOCALE 0x015A
#define CB_GETTOPINDEX 0x015b
#define CB_SETTOPINDEX 0x015c
#define CB_GETHORIZONTALEXTENT 0x015d
#define CB_SETHORIZONTALEXTENT 0x015e
#define CB_GETDROPPEDWIDTH 0x015f
#define CB_SETDROPPEDWIDTH 0x0160
#define CB_INITSTORAGE 0x0161
#define CB_MULTIPLEADDSTRING 0x0163
#define CB_GETCOMBOBOXINFO 0x0164
#define CB_MSGMAX 0x0165
#define CB_MSGMAX 0x0163
#define CB_MSGMAX 0x0162
#define CB_MSGMAX 0x015B
Chartered 2003-10-15
  • 打赏
  • 举报
回复
哈哈,因为我不知道要怎样做啊,如果谁有更好的办法,请共享一下,: )
尹成Python27天从入门到实战项目!全课665节讲解详细易操作,助力实战项目能力成长,轻松、简单、易懂!day1  python入门与学习方法精确思维与用到才能记忆深刻课程简介课前介绍计算机简介与硬盘概念内存作用计算机小结编程语言简介操作系统简介python版本简介切换python版本修改环境变量交互式编程两种风格python3代码保存必须是utf-8使用IDE了解注释段落打印三引号注释多行三个单引号python代码要严格对齐中文输入字符错误简单数学表达式代码风格三种错误风格系统执行指令运行结果乱码交互式编程绘图绘制线段与圆形改变颜色绘制奥运五环小结习题day1plus python  常量变量数据类型 常量与变量区别标识符关键字输入输出id求地址type求类型python变量是地址赋值可以改变类型python主要数据类型复数数据类型自适应变长整数intdel作用连续赋值交互对称赋值字符串转化与输入输出编程wmv多行拆分多行归并成一行规范用的常量算术运算符科学计数法与数字越界优先级结合性赋值运算符数据类型转换四舍五入数据提取时间处理作业day2   python字符串与绘图复习变量None变量参与运算没有赋值的情况不会改变绘制立方体绘制五角星时间计算强化实现贷款计算连续输入多个字符串加法与绘图实现显示线段长度数据函数使用快速查阅函数帮助字符串三种风格字符与编号中文字符编号问题字符编号用途统一码转义字符意义转义字符用于字符串print高级用法字符串加法与转换字符串小结python中所有的数据都是对象字符串格式化了解进制图形绘制重点作业以及学习认知方法day3   python运算符与ifelse逻辑语句第一天上午回顾第二天下午回顾1第二天回顾2.7习题解答2.11习题解答2.26作业KaliLinux简介3.4实现五边形面积计算3.7随机字符生成3.8实数误差与四舍五入3.18解答与特殊字符if简介与空格的作用if处理的是逻辑表达式关系运算符针对数值字符串的关系运算符if自动转化Bool类型随机数if缺点且运算符或运算符取反运算符短路效应身份运算符运算符优先级结合性概览pass语句潜台词翻译系统None用途指令翻译系统嵌套嵌套与elif对比以及注意细节习题解答绘图作业与重点day4  语音合成与逻辑循环回顾语音合成简单理解while控制次数WhileElseWhileElse实战whileFloat回顾与ifelse表达式赌博概率分类设计方法-一元二次方程嵌套求有序3个数闰年计算矩形区域随机数ifelse回文数判断10进制转化16进制16进制转十进制暴力穷举无限循环指令循环同步异步黑科技读写内存读写内存无限循环监测重点与作业day5  复杂逻辑循环while与whileelse编程风格循环控制图形绘制while猜数字输入输出重定向while习题分析可以退出的命令系统for初步简介跑分流程结合for循环小结forfor嵌套forfor分析break中断循环contiune结束本次循环双层循环的break与continue分析break与contiue小结一闪一闪亮晶晶循环控制大小与位置对角线绘制圆形口顺时针运动循环等价作业与小结day6  函数实战回顾.算学费输入数据求最大精确划分思维解决最大次大交换数据实现按行显示围棋棋盘绘制国际象棋绘制为什么要用函数函数的四种类型函数的一般形式必须用函数的理由-哥德巴赫函数的本质就是地址函数变量意义函数变量用途装饰器设计模式包含模式函数概念None函数默认参数与返回值作为参数名称参数与位置参数参数副本机制副本练习多个返回值全局变量与局部变量函数内部引用全局变量函数可以嵌套nolocal处理函数嵌套变量函数nonlocalnonlocal总结开房数据查询day7      函数实战与常用数据结构函数的两种类型函数的本质再分析函数地址切换切换功能ifelse配合地址筛选函数收费函数调用过程函数基本小结return小结位置参数与默认参数混合参数填充混合填充错误情况lambda匿名函数可变长函数字符串常识普及字符串特点字符串不可以修改内部字符list列表list用途tuple简介集合运算字典概念in与notin运算符构造表达式转换数据类型系统小结拓展查询作业day8   字符串实战简单回顾eval与exec简介字符串的简单规范字符串的截取字符串赋值规范字符串转义字符字符串常见运算符字符串格式化字符串格式化强化字符串编码简介dir与help查看str字符串函数第一个大写以及字符串居中显示打印金字塔count统计字符串出现个数字符串编码注意事项解码失败判断字符串以什么为结束tab键转换find函数与rfind函数day9   字符串高级简单回顾..eval与exec简介字符串的简单规范字符串的截取字符串赋值规范字符串转义字符字符串常见运算符字符串格式化字符串格式化强化字符串编码简介dir与help查看str字符串函数第一个大写以及字符串居中显示打印金字塔count统计字符串出现个数字符串编码注意事项解码失败判断字符串以什么为结束tab键转换find函数与rfind函数index函数与rindex函数字符串判断字符串间隔求长度以及左右填充字符串大小写取出最大最小字符替换去除空格简单切割换行切割判断开头大小写切换以及填充0翻译表.字符串模板小结day10  字符串集合与语音识别实战回顾lset初始化风格set增加与去重set删除元素遍历set类型转化set无法操作单个元素的赋值set常见方法set常见运算符set关系运算符判断包含set集合判断frozenset字典的基本定义循环字典判断在不在实现插入与更新字典删除字典详解字典与set无法嵌套迭代器列表生成式生成器生成器节省内存用于循环生成器yield作用生成器简介测试游戏简介游戏初级修改键盘模拟语音控制游戏实现鼠标模拟代码规范函数简化重用列表与元组小结作业day11  阶段综合练习昨日回顾.堆栈函数模块引用系统模块引用与错误列表生成式的若干方法生成矩阵str与reprpython把输入输出设备当作文件处理写入中文写入英文读取中文读取英文读取错误写入错误处理文件缓存区文件读取若干种方式for循环按行读取数据文件指针seektell数据结构与文件的交互数据查询并保存结果数据查询小结与数据day12downwithoutdata  数据处理开发大数据指令数据清洗的概念初级数据清洗密码排序次数统计QQ密码概率分布QQ号码分类器.开房数据清洗..区域划分省份划分年龄月份划分日划分day12up  数据实战简单回顾12系统默认编码中文编码常见错误字符串切割抓取邮箱抓取用户名与密码排序密码文件统计次数排序.统计文件密码次数密码次数排序day13withoutdata  数据分类与list深入地区分类详解字典分类器数据简单归并数据如何切割数据加密数据解密指令执行判断文件夹编程小结列表归并-删除列表归并-下标小结与作业day14down   面向对象编程与深浅拷贝面向对象与过程的差异self用途动态绑定增加属性方法重载运算符的概念有名对象与匿名对象重载运算符的返回值重载运算符多个类型类的拷贝是浅复制深浅拷贝函数调用参数副本原理函数调用可以改变list的元素不可以改变list指向对象当作参数的细节私有变量私有变量用于设计权限私有方法用于设计权限私有变量本质用类的方式读取文件行数密码次数归并数据处理方法简介今日小结作业wmvday14up  暴力穷举与类回顾....排列组合暴力生成穷举密码密码破解必破生成器密码破解小结为啥使用类-代码重用类的一般形式详解self构造函数与析构函数构造函数初始化类的属性最简洁的UI设定窗体的位置以及大小类的实际用途day15down  面向对象数据搜索实战输入处理文本编辑器表格数据树状显示数据搜索可视化第一步实现查询窗体数据搜索可视化第二步实现搜索数据数据搜索可视化第三步实现显示窗体数据可视化第四步显示与搜索串联数据可视化终结作业小结day15up  面向对象设计与图像界面上设计一个类发短信类的方法设计一下短信发送邮件类的设计-设计发邮件类的多文件引用腾讯营销类的设计消息循环消息回掉函数机制lambda按下按钮标签显示文本文本输入框listcombobox选择列表day16up  面向对象与图形界面开发下设计一个类发短信类的方法设计一下短信发送邮件类的设计-设计发邮件类的多文件引用腾讯营销类的设计消息循环消息回掉函数机制lambda按下按钮标签显示文本文本输入框listcombobox选择列表day17  面向对象继承实战昨日小结.,.继承的概念多继承的概念多继承的覆盖私有变量不可以被继承Object类类的常见属性super解决父类重复初始化isinstance多态静态方法类方法数据工具1类的继承数据工具实现小结day18down  正则表达式正则表达式bB贪婪与非贪婪标签.标签解决提取标签名称提取QQ生成邮箱列表工具简单正则表达式编写常见的正则表达式复杂正则表达式编写复杂表达式代码验证作业与小结day18up 正则表达式实践为什么使用正则表达式正则表达式匹配.预编译的概念搜索技能搜索用在找出第一个邮箱手机提取findall字符串切割筛选正则表达式正则表达式替换单个字符判断中括号选择一个字符正则表达式次数正则开头结尾括号与选择正则表达式特殊符号day19down 递归与爬虫实战函数递归模拟文件树文件树事件读取网页抓取邮箱抓取QQ提取http抓取邮箱简单程序框架实现抓取邮箱的框架核心两个函数完成广度遍历深度遍历作.业day19up 深度遍历与广度遍历正则表达式小结最简单递归递归顺序递归求和递归腾讯台阶面试题文件夹的函数遍历文件夹遍历文件夹有层次感栈模拟递归栈模拟递归遍历文件夹栈模拟递归遍历文件夹层次感普及网站提取概念栈修改的逻辑错误广度遍历 day20 正则 爬虫实战行情简介提取页面信息提取股票代码提取股票代码下载功能下载股票批量下载股票抓取1页的股票数据抓取多个页面的股票抓取基金信息作业day21  网络编程与信息安全网络概念UDP协议UDP通信UDP远程控制TCP通信TCP控制测试网站后台网站密码破解作业 day22down  线程通信线程通信线程通信强化线程condition高级线程调度生产者消费者线程池延时线程with作用前台进程后台进程TLS线程独立存储作业day22up  多线程实战多线程核心目标并发主线程与小弟线程多线程解决加速多线程的加速线程冲突基于类实现多线程基于类实现多线程的顺序与乱序互斥锁解决线程冲突死锁-使用锁要注意Rlock解决一个线程反复加锁单线程死锁创建线程的三种风格信号量限制线程数量限定线程数量day23  多进程实战多线程回顾多进程拷贝代码多进程拷贝全局变量获取进程编号subprocess执行LinuxShell信号Linux进程小结__name__进程mutiprocessing创建过程join作用进程不可以用全局变量共享数据进程同步进程pipe发送接收数据进程队列进程队列传输数据进程共享数据进程之间共享数组进程共享字典与list简单小结day23down  多进程多线程综合实战读取CSV写入csv单线程统计行数多线程统计行数多进程统计行数多线程检索数据第一步多线程检索赵琳多线程检索找到通知其他人退出多线程检索开放数据并保存同一个文件作业day24up  多进程多线程综合实战多进程检索第一步多进程检索开房数据求平均市值多线程解决平均市值多进程统计平均市值单线程BFS抓取邮箱多线程并行抓取邮箱多线程采集邮箱并保存csv归并多线程归并文件day25down 文件格式处理doc处理系统处理doc与docx文件处理的小结读取并写入xls与xlsx读取网络pdf中文pdftelnet简介登陆Linux登陆Windows小结day25up  时间编程与单元测试时间的简单风格时间格式化抓取年月日计算时间差时间函数计算时间差date小结python2与3的差异内置函数筛选内置函数map内置的函数sorted新浪数据抓取实时文档测试单元测试函数单元测试一个类day26  综合实战播放音乐设置背景鬼程序协程简介协程传递数据wmv协程编号协程生产者消费者模式office自动化操作wordoffice办公自动化操作exceloffice办公自动化操作outlookoffice办公自动化access开发环境配置访问mdb格式访问accdb格式实现CGI程序显示页面环境变量cgi处理前后端day26down  破解wifi实战扫描wifi扫描网卡区分链接成功或者失败wifi密码爆破工具设计Linux破解简介day27down  飞机大战实战命令行下脱裤创建一个pygame窗体窗体加载背景图片处理消息飞机移动实现基本框架飞机框架飞机销毁双机对战双机对战加载子弹双机与敌机出现发射子弹day27up  数据库实战jython的安装MySQL简介数据库的一般操作MySQL数据类型数据表的创建于删除数据的查询数据的插入数据的删除数据的更新联合查询字段一致数据查询排序排序与分组join与nullmysql用python编程查询数据python数据库增删查改项目简介other  异常与错误综合练习异常与错误的概念作业tryexcept解决异常不出错继续执行密码破解工具进攻数据库爆破mysql异常else异常处理的标准公式弹出异常withas类中使用异常继承自定义异常断言密码工具设计三个独立的类密码工具2类链接3类密码工具1类链接3类密码工具分析作业speech   语音识别问题解决语音识别解决None
VC之美化界面篇 作者:白乔 链接:http://vcer.net/1046595482643.html 本文专题讨论VC中的界面美化,适用于具有中等VC水平的读者。读者最好具有以下VC基础: 1. 大致了解MFC框架的基本运作原理; 2. 熟悉Windows消息机制,熟悉MFC的消息映射和反射机制; 3. 熟悉OOP理论和技术; 本文根据笔者多年的开发经验,并结合简单的例子一一展开,希望对读者有所帮助。 1 美化界面之开题篇 相信使用过《金山毒霸》、《瑞星杀毒》软件的读者应该还记得它们的精美界面: 图1 瑞星杀毒软件的精美界面 程序的功能如何如何强大是一回事,它的用户界面则是另一回事。千万不要忽视程序的用户界面,因为它是给用户最初最直接的印象,丑陋的界面、不友好的风格肯定会影响用户对软件程序的使用。 “受之以鱼,不若授之以渔”,本教程并不会向你推荐《瑞星杀毒软件》精美界面的具体实现,而只是向你推荐一些常用的美化方法。 2 美化界面之基础篇 美化界面需要先熟悉Windows下的绘图操作,并明白Windows的幕后绘图操作,才能有的放矢,知道哪些可以使用,知道哪些可以避免…… 2.1 Windows下的绘图操作 熟悉DOS的读者可能就知道:DOS下面的图形操作很方便,进入图形模式,整个屏幕就是你的了,你希望在哪画个点,那个地方就会出现一个点,红的、或者黄的,随你的便。你也可以花点时间画个按钮,画个你自己的菜单,等等…… Windows本身就是图形界面,所以Windows下面的绘图操作功能更丰富、简单。要了解Windows下的绘图操作,要实现Windows界面的美化,就必须了解MFC封装的设备环境类和图形对象类。 2.1.1 设备环境类 Windows下的绘图操作说到底就是DC操作。DC(Device Context设备环境)对象是一个抽象的作图环境,可能是对应屏幕,也可能是对应打印机或其它。这个环境是设备无关的,所以你在对不同的设备输出时只需要使用不同的设备环境就行了,而作图方式可以完全不变。这也就是Windows的设备无关性。 MFC的CDC类封装了Windows API 中大部分的画图函数。CDC的常见操作函数包括: Drawing-Attribute Functions:绘图属性操作,如:设置透明模式 Mapping Functions:映射操作 Coordinate Functions:坐标操作 Clipping Functions:剪切操作 Line-Output Functions:画线操作 Simple Drawing Functions:简单绘图操作,如:绘制矩形框 Ellipse and Polygon Functions:椭圆/多边形操作 Text Functions:文字输出操作 Printer Escape Functions:打印操作 Scrolling Functions:滚动操作 *Bitmap Functions:位图操作 *Region Functions:区域操作 *Font Functions:字体操作 *Color and Color Palette Functions:颜色/调色板操作 其中,标注*项会用到相应的图形对象类,参见2.1.2内容。 2.1.2 图形对象类 设备环境不足以包含绘图功能所需的所有绘图特征,除了设备环境外, Windows还有其他一些图形对象用来储存绘图特征。这些附加的功能包括从画线的宽度和颜色到画文本时所用的字体。图形对象类封装了所有六个图形对象。 下面的表格列出了MFC的图形对象类: MFC类 图形对象句柄 图形对象目的 CBitmap HBITMAP 内存中的位图 CBrush HBRUSH 画刷特性—填充某个图形时所使用的颜色和模式 CFont HFONT 字体特性—写文本时所使用的字体 CPalette HPALETTE 调色板颜色 CPen HPEN 画笔特性—画轮廓时所使用的线的粗细 CRgn HRGN 区域特性—包括定义它的点 表1 图形对象类和它们封装的句柄 使用CDC和图形对象类,在Windows里绘图还算是很简单的。观察以下的画面: 图2 使用CDC绘制出的按钮 该画面通过以下代码自行绘制的假按钮: BOOL CUi1View::PreCreateWindow(CREATESTRUCT& cs) { //设置背景色 //CBrush CUi1View::m_Back m_Back.CreateSolidBrush(::GetSysColor(COLOR_3DFACE)); cs.lpszClass = AfxRegisterWndClass(0, 0, m_Back, NULL); return CView::PreCreateWindow(cs); } int CUi1View::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; //创建字体 //CFont CUi1View::m_Font m_Font.CreatePointFont(120, "Impact"); return 0; } void CUi1View::OnDraw(CDC* pDC) { //绘制按钮框架 pDC->DrawFrameControl(CRect(100, 100, 220, 160), DFC_BUTTON, DFCS_BUTTONPUSH); //输出文字 pDC->SetBkMode(TRANSPARENT); pDC->TextOut(120, 120, "Hello, CFan!"); } 呵呵,不好意思,这并不是真的Windows按钮,它只是一个假的空框子,当用户在按钮上点击鼠标时,放心,什么事情都不会发生。 2.2 Windows的幕后绘图操作 在Window中,如果所有的界面操作都由用户代码来实现,那将是一个很浩大的工程。笔者曾经在DOS设计过窗口图形界面,代码上千行,但实现的界面还是很古板、难看,除了我那个对编程一窍不通的女友,没有一个人欣赏它L;而且,更要命的是,操作系统,包括别的应用程序并不认识你的界面元素,这才是真正悲哀的。认识这些界面的只有你的程序,图2中的按钮永远只是一个无用的框子。 有了Windows,一切都好办了,Windows将诸如按钮、菜单、工具栏等等这些通用界面的绘制及动作都交给了系统,程序员就不用花心思再画那些按钮了,可以将更多的精力放在程序的功能实现方面。 所有的标准界面元素都被Windows封装好了。Windows知道怎么画你的菜单以及你的标注着“Hello, Cfan!”的按钮。当CFan某个快乐的小编(譬如:小飞)点击这个按钮的时候,Windows也明白按钮按下去的时候该有的模样,甚至,当这个友好的按钮获取焦点时,Windows也会不失时机地为它准备一个虚框…… 有利必有弊。你的不满这时候产生了:你既想使用Windows的True Button,可也嫌它的界面不够好看,譬如,你喜欢用蓝色的粗体表达你对CFan的无限情怀(正如图2那样)——人心不足,有办法吗?有的。 3 美化界面之实现篇 Windows还是给程序员留下了很多后门,通过一些途径还是可以美化界面的。本章节我们系统学习一下Windows界面美化的实现。 3.1 美化界面的途径 如何以合法的手段来达到美化界面的效果?一般美化界面的方法包括: 1. 使用MFC类的既有函数,设定界面属性; 2. 利用Windows的消息机制,截获有用的Windows的消息。通过MFC的消息映射(Message Mapping)和反射(Message Reflecting)机制,在Windows准备或者正在绘制该元素时,偷偷修改它的状态和行为,譬如:让按钮的边框为红色; 3. 利用MFC类的虚函数机制,重载有用的虚函数。在MFC框架调用该函数的时候,重新定义它的状态和行为; 一般来说,应用程序可以通过以下两种途径来实现以上的方法: 1. 在父窗口里,截获自身的或者由子元素(包括控件和菜单等元素)传递的关于界面绘制的消息; 2. 子类化子元素,或者为子元素准备一个新的类(一般来说该类必须继承于MFC封装的某个标准类,如:CButton)。在该子元素里,截获自身的或者从父窗口反射过来的关于界面绘制的消息。譬如:用户可以创建一个CXPButton类来实现具有XP风格的按钮,CXPButton继承于CButton。 对于应用程序,使用CXPButton类的途径相对于对话框窗口和普通窗口分成两种: ① 对话框窗口中,直接将原先绑定按钮的CButton类替换成CXPButton类,或者在绑定变量时直接指定Control类型为CXPButton,如图3所示: 图3 为按钮指定CXPButton类型 ②在普通窗口中,直接创建一个CXPButton类对象,然后在OnCreate()中调用CXPButton的Create方法; 以下的章节将综合地使用以上的方法,请读者朋友留心观察。 3.2 使用MFC类的既有函数 在界面美化的专题中,MFC也并非一无是处。MFC类对于界面美化也做了部分的努力,以下是一些可以使用的,参数说明略去。 CWinApp::SetDialogBkColor void SetDialogBkColor( COLORREF clrCtlBk = RGB(192, 192, 192), COLORREF clrCtlText = RGB(0, 0, 0) ); 指定对话框的背景色和文本颜色。 CListCtrl::SetBkColor CReBarCtrl::SetBkColor CStatusBarCtrl::SetBkColor CTreeCtrl::SetBkColor COLORREF SetBkColor( COLORREF clr ); 设定背景色。 CListCtrl::SetTextColor CReBarCtrl::SetTextColor CTreeCtrl::SetTextColor COLORREF SetTextColor( COLORREF clr ); 设定文本颜色。 CListCtrl::SetBkImage BOOL SetBkImage( LVBKIMAGE* plvbkImage ); BOOL SetBkImage( HBITMAP hbm, BOOL fTile = TRUE, int xOffsetPercent = 0, int yOffsetPercent = 0); BOOL SetBkImage( LPTSTR pszUrl, BOOL fTile = TRUE, int xOffsetPercent = 0, int yOffsetPercent = 0 ); 设定列表控件的背景图片。 CComboBoxEx::SetExtendedStyle CListCtrl::SetExtendedStyle CTabCtrl::SetExtendedStyle CToolBarCtrl::SetExtendedStyle DWORD SetExtendedStyle( DWORD dwExMask, DWORD dwExStyles ); 设置控件的扩展属性,例如:设置列表控件属性带有表格线。 图4是个简单应用MFC类的既有函数来改善Windows界面的例子: 图4 使用MFC类的既有函数美化界面 相关实现代码如下: BOOL CUi2App::InitInstance() { //… //设置对话框背景色和字体颜色 SetDialogBkColor(RGB(128, 192, 255), RGB(0, 0, 255)); //… } BOOL CUi2Dlg::OnInitDialog() { //… //设置列表控件属性带有表格线 DWORD NewStyle = m_List.GetExtendedStyle(); NewStyle |= LVS_EX_GRIDLINES; m_List.SetExtendedStyle(NewStyle); //设置列表控件字体颜色为红色 m_List.SetTextColor(RGB(255, 0, 0)); //填充数据 m_List.InsertColumn(0, "QQ", LVCFMT_LEFT, 100); m_List.InsertColumn(1, "昵称", LVCFMT_LEFT, 100); m_List.InsertItem(0, "5854165"); m_List.SetItemText(0, 1, "白乔"); m_List.InsertItem(1, "6823864"); m_List.SetItemText(1, 1, "Satan"); //… } 嗯,这样的界面还算不错吧? 3.3 使用Windows的消息机制 使用MFC类的既有函数来美化界面,其功能是有限的。既然Windows是通过消息机制进行通讯的,那么我们就可以通过截获一些有用的消息来美化我们的界面,以下是一些有用的Windows消息: WM_PAINT WM_ERASEBKGND WM_CTLCOLOR* WM_DRAWITEM* WM_MEASUREITEM* NM_CUSTOMDRAW* 注意,标注*的消息是子元素发送给父窗口的通知消息,其它的为窗口或者子元素自身的消息。 3.3.1 WM_PAINT WM_PAINT消息相信大家都很熟悉,一个窗口要重绘了,就会有一个WM_PAINT消息发送给窗口。 可以响应窗口的WM_PAINT,以更改它们的模样。WM_PAINT的映射函数原型如下: afx_msg void OnPaint(); 控件也是窗口,所以控件也有WM_PAINT消息,通过消息映射我们完全可以定义控件的界面。如图5所示: 图5 利用WM_ PAINT消息美化界面 实现代码也很简单: void CLazyStatic::OnPaint() { CPaintDC dc(this); // device context for painting //什么都不输出,仅仅画一个矩形框 CRect rc; GetClientRect(&rc); dc.Rectangle(rc); } 哈哈,简单吧?不过WM_PAINT确实绝了点,它要求应用程序完成元素界面的所有绘制过程,想象一下如何画出一个完整的列表控件?太烦了吧。一般来说,很少有人喜欢使用WM_PAINT,还有其它更细致的消息。 3.3.2 WM_ERASEBKGND Windows在向窗口发送WM_PAINT消息之前,总会发送一个WM_ERASEBKGND消息通知该窗口擦除背景,默认情况下,Windows将以窗口的背景色清除该窗口。 可以响应窗口(包括子元素)的WM_ERASEBKGND,以更改它们的背景。WM_ERASEBKGND的映射函数原型如下: afx_msg BOOL OnEraseBkgnd( CDC* pDC ); 返回值: 指定背景是否已清除,如果为FALSE,系统将自动清除 参数: pDC指定了绘制操作所使用的设备环境。 图6是个简单的例子,通过OnEraseBkgnd为对话框加载了一副位图背景: 图6 利用WM_ ERASEBKGND消息美化界面 实现代码也很简单: BOOL CUi4Dlg::OnInitDialog() { //… //加载位图 //CBitmap m_Back; m_Back.LoadBitmap(IDB_BACK); //… } BOOL CUi4Dlg::OnEraseBkgnd(CDC* pDC) { CDC dc; dc.CreateCompatibleDC(pDC); dc.SelectObject(&m_Back); //获取BITMAP对象 BITMAP hb; m_Back.GetBitmap(&hb); //获取窗口大小 CRect rt; GetClientRect(&rt); //显示位图 pDC->StretchBlt(0, 0, rt.Width(), rt.Height(), &dc, 0, 0, hb.bmWidth, hb.bmHeight, SRCCOPY); return TRUE; } HBRUSH CUi4Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { //设置透明背景模式 pDC->SetBkMode(TRANSPARENT); //设置背景刷子为空 return (HBRUSH)::GetStockObject(HOLLOW_BRUSH); } 同时别忘了响应OnCtlColor,否则窗口里面的控件就不透明了。OnCtlColor的内容。 3.3.3 WM_CTLCOLOR 在控件显示之前,每一个控件都会向父对话框发送一个WM_CTLCOLOR消息要求获取绘制所需要的颜色。WM_CTLCOLOR消息缺省处理函数CWnd::OnCtlColor返回一个HBRUSH类型的句柄,这样,就可以设置前景和背景文本颜色,并为控件或者对话框的非文本区域选定一个刷子。 WM_CTLCOLOR的映射函数原型如下: afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ); 返回值: 用以指定背景的刷子 参数: pDC指定了绘制操作所使用的设备环境。 pWnd 控件指针 nCtlColor 指定控件类型,其取值如表2所示: 类型值 含义 CTLCOLOR_BTN 按钮控件 CTLCOLOR_DLG 对话框 CTLCOLOR_EDIT 编辑控件 CTLCOLOR_LISTBOX 列表框 CTLCOLOR_MSGBOX 消息框 CTLCOLOR_SCROLLBAR 滚动条 CTLCOLOR_STATIC 静态控件 表2 nCtlColor的类型值与含义 作为一个简单的例子,观察以下的代码: BOOL CUi5Dlg::OnInitDialog() { //… //创建字体 //CFont CUi1View::m_Font1, CUi1View::m_Font2 m_Font1.CreatePointFont(120, "Impact"); m_Font3.CreatePointFont(120, "Arial"); return TRUE; // return TRUE unless you set the focus to a control } HBRUSH CUi5Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if(nCtlColor == CTLCOLOR_STATIC) { //区分静态控件 switch(pWnd->GetDlgCtrlID()) { case IDC_STATIC1: { pDC->SelectObject(&m_Font1); pDC->SetTextColor(RGB(0, 0, 255)); break; } case IDC_STATIC2: { pDC->SelectObject(&m_Font2); pDC->SetTextColor(RGB(255, 0, 0)); break; } } } return hbr; } 生成的界面如下: 图7 利用WM_CTLCOLOR消息美化界面 3.3.4 WM_DRAWITEM OnCtlColor只能修改元素的颜色,但不能修改元素的界面框架,WM_DRAWITEM则可以。 当一个具有Owner draw风格的元素(包括按钮、组合框、列表框和菜单等)需要显示外观时,该元素会发送一条WM_DRAWITEM消息至它的隶属窗口(Owner)。 WM_DRAWITEM的映射函数原型如下: afx_msg void OnDrawItem( int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct ); 参数: nIDCtl 该控件的ID,如果该元素为菜单,则nIDCtl为0 lpDrawItemStruct 指向DRAWITEMSTRUCT结构对象的指针,DRAWITEMSTRUCT的结构定义如下: typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; }DRAWITEMSTRUCT; CtlType指定了控件的类型,其取值如表3所示: 类型值 含义 ODT_BUTTON 按钮控件 ODT_COMBOBOX 组合框控件 ODT_LISTBOX 列表框控件 ODT_LISTVIEW 列表视图 ODT_MENU 菜单项 ODT_STATIC 静态文本控件 ODT_TAB Tab控件 表3 CtlType的类型值与含义 CtlID 指定自绘控件的ID值,该成员不适用于菜单项 itemID表示菜单项ID,也可以表示列表框或者组合框中某项的索引值。对于一个空的列表框或组合框,该成员的值为?C1。这时应用程序只绘制焦点矩形(该矩形的坐标由rcItem 成员给出)虽然此时控件中没有需要显示的项,但是绘制焦点矩形还是很有必要的,因为这样做能够提示用户该控件是否具有输入焦点。当然也可以设置itemAction 成员为合适值,使得无需绘制焦点。 itemAction 指定绘制行为,其取值为表4中所示值的一个或者多个的联合: 类型值 含义 ODA_DRAWENTIRE 当整个控件都需要被绘制时,设置该值。 ODA_FOCUS 如果控件需要在获得或失去焦点时被绘制,则设置该值。此时应该检查itemState成员,以确定控件是否具有输入焦点。 ODA_SELECT 如果控件需要在选中状态改变时被绘制,则设置该值。此时应该检查itemState 成员,以确定控件是否处于选中状态。 表4 itemAction的类型值与含义 itemState 指定了当前绘制项的状态。例如,如果菜单项应该被灰色显示,则可以指定ODS_GRAYED状态标志。其取值为表5中所示值的一个或者多个的联合: 类型值 含义 ODS_CHECKED 标记状态,仅适用于菜单项。 ODS_DEFAULT 默认状态。 ODS_DISABLED 禁止状态。 ODS_FOCUS 焦点状态。 ODS_GRAYED 灰化状态,仅适用于菜单项。 ODS_SELECTED 选中状态。 ODS_HOTLIGHT 仅适用于Windows 98/Me/Windows 2000/XP,热点状态:如果鼠标指针位于控件之上,则设置该值,这时控件会显示高亮颜色。 ODS_INACTIVE 仅适用于Windows 98/Me/Windows 2000/XP,非激活状态。 ODS_NOACCEL 仅适用于Windows 2000/XP,控件是否有快速键。 ODS_COMBOBOXEDIT 在自绘组合框控件中只绘制选择区域。 ODS_NOFOCUSRECT 仅适用于Windows 2000/XP,不绘制捕获焦点的效果。 表5 itemState的类型值与含义 hwndItem 指定了组合框、列表框和按钮等自绘控件的窗口句柄;如果自绘的对象为菜单项,则表示包含该菜单项的菜单句柄。 hDC 指定了绘制操作所使用的设备环境。 rcItem 指定了将被绘制的矩形区域。这个矩形区域就是上面hDC的作用范围。系统会自动裁剪组合框、列表框或按钮等控件的自绘制区域以外的部分。也就是说rcItem中的坐标点(0,0)指的就是控件的左上角。但是系统不裁剪菜单项,所以在绘制菜单项的时候,必须先通过一定的换算得到该菜单项的位置,以保证绘制操作在我们希望的区域中进行。 itemData 对于菜单项,该成员的取值为由CMenu::AppendMenu、CMenu::InsertMenu、CMenu::ModifyMenu等函数传递给菜单的值。 对于列表框或这组合框,该成员的取值为由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等函数传递给控件的值。 如果ctlType 的取值是ODT_BUTTON或者ODT_STATIC,itemData的取值为0。 图5是个相应的例子,它修改了按钮的界面: 图8 利用WM_DRAWITEM消息美化界面 实现代码如下: BOOL CUi6Dlg::OnInitDialog() { //… //创建字体 //CFont CUi1View::m_Font m_Font.CreatePointFont(120, "Impact"); //… } void CUi6Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) { if(nIDCtl == IDC_HELLO_CFAN) { //绘制按钮框架 UINT uStyle = DFCS_BUTTONPUSH; //是否按下去了? if (lpDrawItemStruct->itemState & ODS_SELECTED) uStyle |= DFCS_PUSHED; CDC dc; dc.Attach(lpDrawItemStruct->hDC); dc.DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle); //输出文字 dc.SelectObject(&m_Font); dc.SetTextColor(RGB(0, 0, 255)); dc.SetBkMode(TRANSPARENT); CString sText; m_HelloCFan.GetWindowText(sText); dc.TextOut(lpDrawItemStruct->rcItem.left + 20, lpDrawItemStruct->rcItem.top + 20, sText); //是否得到焦点 if(lpDrawItemStruct->itemState & ODS_FOCUS) { //画虚框 CRect rtFocus = lpDrawItemStruct->rcItem; rtFocus.DeflateRect(3, 3); dc.DrawFocusRect(&rtFocus); } return; } CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct); } 别忘了标记Owner draw属性: 图9 指定按钮的Owner draw属性 值得一提的是,CWnd内部截获了WM_DRAWITEM、WM_MEASUREITEM等消息,并映射成子元素的相应虚函数的调用,如CButton::DrawItem()。所以,以上例子也可以通过派生出一个CButton的派生类,并重载该类的DrawItem()函数来实现。使用虚函数机制实现界面美化参见3.4章节。 3.3.5 WM_MEASUREITEM 仅仅WM_DRAWITEM还是不够的,对于一些特殊的控件,如ListBox,系统在发送WM_DRAWITEM消息前,还发送WM_MEASUREITEM消息,需要你设置ListBox中每个项目的高度。 WM_DRAWITEM的映射函数原型如下: afx_msg void OnMeasureItem( int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct ); nIDCtl 该控件的ID,如果该元素为菜单,则nIDCtl为0 lpMeasureItemStruct指向MEASUREITEMSTRUCT结构对象的指针,MEASUREITEMSTRUCT的结构定义如下: typedef struct tagMEASUREITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemWidth; UINT itemHeight; DWORD itemData } MEASUREITEMSTRUCT; CtlType指定了控件的类型,其取值如表6所示: 类型值 含义 ODT_COMBOBOX 组合框控件 ODT_LISTBOX 列表框控件 ODT_MENU 菜单项 表6 CtlType的类型值与含义 CtlID 指定自绘控件的ID值,该成员不适用于菜单项 itemID表示菜单项ID,也可以表示可变高度的列表框或组合框中某项的索引值。该成员不适用于固定高度的列表框或组合框。 itemWidth 指定菜单项的宽度 itemHeight指定菜单项或者列表框中某项的的高度,最大值为255 itemData 对于菜单项,该成员的取值为由CMenu::AppendMenu、CMenu::InsertMenu、CMenu::ModifyMenu等函数传递给菜单的值。 对于列表框或这组合框,该成员的取值为由ComboBox::AddString、CComboBox::InsertString、CListBox::AddString或者CListBox::InsertString等函数传递给控件的值。 图示出了OnMeasureItem的效果: 图10 利用WM_MEASUREITEM消息美化界面 相应的OnMeasureItem()实现如下: void CUi7Dlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if(nIDCtl == IDC_COLOR_PICKER) { //设定高度为 lpMeasureItemStruct->itemHeight = 30; return; } CDialog::OnMeasureItem(nIDCtl, lpMeasureItemStruct); } 同样别忘了指定列表框的Owner draw属性: 图11 指定下拉框的Owner draw属性 3.3.6 NM_CUSTOMDRAW 大家也许熟悉WM_NOTIFY,控件通过WM_NOTIFY向父窗口发送消息。在WM_NOTIFY消息体中,部分控件会发送NM_CUSTOMDRAW告诉父窗口自己需要绘图。 可以反射NM_CUSTOMDRAW消息,如: ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw) afx_msg void OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult); 参数: pNMHDR 说到底只是一个指针,大多数情况下它指向一个NMHDR结构对象,NMHDR结构如下: typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR; 其中: hwndFrom 发送方控件的窗口句柄 idFrom 发送方控件的ID code 通知代码 对于某些控件来说,pNMHDR则会解释成其它内容更丰富的结构对象的指针,如:对于列表控件来说,pNMHDR常常指向一个NMCUSTOMDRAW对象,NMCUSTOMDRAW结构如下: typedef struct tagNMCUSTOMDRAWINFO { NMHDR hdr; DWORD dwDrawStage; HDC hdc; RECT rc; DWORD dwItemSpec; UINT uItemState; LPARAM lItemlParam; } NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW; hdr NMHDR对象 dwDrawStage 当前绘制状态,其取值如表7所示: 类型值 含义 CDDS_POSTERASE 擦除循环结束 CDDS_POSTPAINT 绘制循环结束 CDDS_PREERASE 准备开始擦除循环 CDDS_PREPAINT 准备开始绘制循环 CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam参数有效 CDDS_ITEMPOSTERASE 列表项擦除结束 CDDS_ITEMPOSTPAINT 列表项绘制结束 CDDS_ITEMPREERASE 准备开始列表项擦除 CDDS_ITEMPREPAINT 准备开始列表项绘制 CDDS_SUBITEM 指定列表子项 表7 dwDrawStage的类型值与含义 hdc指定了绘制操作所使用的设备环境。 rc指定了将被绘制的矩形区域。 dwItemSpec 列表项的索引 uItemState 当前列表项的状态,其取值如表8所示: 类型值 含义 CDIS_CHECKED 标记状态。 CDIS_DEFAULT 默认状态。 CDIS_DISABLED 禁止状态。 CDIS_FOCUS 焦点状态。 CDIS_GRAYED 灰化状态。 CDIS_SELECTED 选中状态。 CDIS_HOTLIGHT 热点状态。 CDIS_INDETERMINATE 不定状态。 CDIS_MARKED 标注状态。 表8 uItemState的类型值与含义 lItemlParam 当前列表项的绑定数据 pResult 指向状态值的指针,指定系统后续操作,依赖于dwDrawStage: 当dwDrawStage为CDDS_PREPAINT,pResult含义如表9所示: 类型值 含义 CDRF_DODEFAULT 默认操作,即系统在列表项绘制循环过程不再发送NM_CUSTOMDRAW。 CDRF_NOTIFYITEMDRAW 指定列表项绘制前后发送消息。 CDRF_NOTIFYPOSTERASE 列表项擦除结束时发送消息。 CDRF_NOTIFYPOSTPAINT 列表项绘制结束时发送消息。 表9 pResult的类型值与含义(一) 当dwDrawStage为CDDS_ITEMPREPAINT,pResult含义如表10所示: 类型值 含义 CDRF_NEWFONT 指定后续操作采用应用中指定的新字体。 CDRF_NOTIFYSUBITEMDRAW 列表子项绘制时发送消息。 CDRF_SKIPDEFAULT 系统不必再绘制该子项。 表10 pResult的类型值与含义(二) 以下是一个利用NM_CUSTOMDRAW消息绘制出的多色列表框的例子: 图12 利用NM_CUSTOMDRAW消息美化界面 对应代码如下: void CCoolList::OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult) { //类型安全转换 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); *pResult = 0; //指定列表项绘制前后发送消息 if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { *pResult = CDRF_NOTIFYITEMDRAW; } else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { //奇数行 if(pLVCD->nmcd.dwItemSpec % 2) pLVCD->clrTextBk = RGB(255, 255, 128); //偶数行 else pLVCD->clrTextBk = RGB(128, 255, 255); //继续 *pResult = CDRF_DODEFAULT; } } 注意到上例采取了3.1所推荐的第2种实现方法,派生了一个新类CCoolList。 3.4 使用MFC类的虚函数机制 修改Windows界面,除了从Windows消息机制下功夫,也可以从MFC类下功夫,这应该得益于类的虚函数机制。为了防止诸如“面向对象技术”等术语在此泛滥,以下仅举一段代码作为例子: void CView::OnPaint() { // standard paint routine CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); } 这是MFC中viewcore.cpp中的源代码,很多读者总不明白OnDraw()和OnPaint()之间的关系,从以上的代码中很容易看出,CView的WM_PAINT消息响应函数OnPaint()会自动调用CView::OnDraw()。而作为开发者的用户,可以通过简单的OnDraw()的重载实现对WM_PAINT的处理。所以说,对MFC类的虚函数的重载是对消息机制的扩展。 以下列出了与界面美化相关的虚函数,参数说明略去: CButton::DrawItem CCheckListBox::DrawItem CComboBox::DrawItem CHeaderCtrl::DrawItem CListBox::DrawItem CMenu::DrawItem CStatusBar::DrawItem CStatusBarCtrl::DrawItem CTabCtrl::DrawItem virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ); Owner draw元素自绘函数 很显然,位图菜单都是通过这个DrawItem画出来的。限于篇幅,在此不再附以例程。

552

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 茶馆
社区管理员
  • 茶馆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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