文字输入框开发小进展
在《看似简单的输入控件,工作量巨大》中提到了我正在制作InputControl控件,其中工作量巨大,但没有办法,谁叫我想自己实现这个程序呢?不得不硬着头皮一点点的将每一个细节实现出来。 不过距离上一次代码撰写已经过去14天了(中间插入了其他的工作:要基于electron.js开发另外一个项目),今天又重新开始对纯原生小应用进行开发。 一、今日已经完成工作: 1、完成了光标的跟随:在InputControl获得焦点之后,可以出现光标,之前这个光标是“死”的,今天已经可以根据InputControl里面的内容,自动计算出内容长度,然后令光标跟随在文字的后面。 2、预输入文字也可以出现在InputControl中:涉及到借助IME进行内容输入时(例如中文输入),输入内容是分为2部分的:预输入文字+正式输入文字。现在预输入文字已经可以同时展现出来了。 3、IME弹出位置在正式文字输入完成或删除完成之后,根据InputControl的内容,重新计算,重新指定IME下一次可能出现的位置。 二、InputControl里面欠缺的主要细节: 0、【bug】预输入文字的删除存在多个问题:预输入文字会在某些情况下一次性全部删除、预输入文字的最初一个字符的删除事件得不到; 1、通过键盘的方向按键调整光标的位置; 2、通过鼠标调整光标的位置; 3、通过键盘或鼠标进行内部文字的框选,进而再通过组合按键进行复制、剪贴、黏贴等操作; 4、鼠标右键在InputControl中可以弹出上下文菜单,进而进行复制、剪贴、黏贴等操作; 5、预输入阶段的光标位置控制; 6、内容过长时怎么办? 7、对于可换行InputControl的处理; 8、正式输入文字和预输入文字的渲染形式应该不同; 9、具有了方向键调整光标位置的功能之后,预输入文字可能是插在正式文字中间的,这种情形也要考虑并实现。
std::vector<T>.size()返回的是size_t类型
一、遇到的问题 今天写程序的时候代码运行崩溃,提示format specifier doesn’t match argument type。因为我刚刚接触C++,所以在这个问题上花了不少的时间。 代码如下: 代码非常的简单,但是一旦编译运行,就会出断言错误提示。最终发现原来vector<T>.size()返回的不是int类型,而是size_t类型,所以在wxLogDebug()中因为存在着断言,发现类型不同就报错了。而后面for()循环里面虽然不报错,那是因为for()循环里面相当于是对int < size_t进行判断,没有断言语句所以不报错,并不是因为真的没有错误。 (int < size_t)这个判断语句虽然在多数情况下都可以正确的执行,但安全起见,还是应该重新定义,改成for (size_t i=0; i<test.size(); i++)这样比较稳妥。 再回过头看wxLogDebug()里面正确的写法,就是使用%zu代替%d,这样格式化字符串的时候接受的参数类型就是size_t了。所以最终代码正确写法如下: 二、size_t和int有什么不同? 上面遇到的问题并不复杂,只是因为以前没有碰到过,所以浪费了一些时间。接下来的问题更令我感兴趣:size_t和int有什么不同吗?既然说size_t是无符号、且与当前系统最大可用内存匹配数,为什么不能直接用unsigned int代替呢? 原因是为了令代码在不同的平台上移植时更加的方便。size_t的确就是unsigned int,但具体是int16、int32还是int64并不一定,在不同的处理器、不同的系统上,size_t表示的范围是不同的。 例如在32位系统上,size_t是unsigned int32,而在64位系统上它的范围则是unsigned int64。…
小工具开发备忘
最近用C++语言写一个小的工具程序,进展还算顺利,大的方向和功能开展的比较顺利,但是细节上有很多小问题。为了确保软件开发的进度,我是抓大放小,先力求能将整体功能全部实现出来。 对于细节问题,只能是做些备注、放在一旁,等软件整体完成之后,再回过头来逐一推敲了。这里记录一下遇到的小问题,当是给自己的备忘,等以后有时间了,再慢慢研究。 1、《系统托盘菜单点击之后500毫秒内的残影》 这个问题并不严重,临时解决方案是在程序中触发截屏时,先延迟一段时间再开始进行截屏。 2、《std::vector.size()返回的是size_t类型》 这并不是“放在一旁、暂且不管”的缺陷,而是我在写代码的时候遇到的一个“引起程序崩溃”的bug。实际上并非真的导致了程序的崩溃,而是因为wxWidgets中的调试断言弹出了警告对话框。 只不过因为我对C++不熟悉、又这个弹出警告框的文字实在难于阅读,所以起初一直以为是程序崩溃了。找了好久才找到原因,并且发现只不过是在f(x)函数的调用是,参数x使用了int类型,而真正应该使用的是size_t类型。虽然int和size_t几乎一样,但严格的断言判定最终生成了警告信息。 这个问题虽然已经解决,但是额外的需要再补充一下细节知识的缺失——《C++中的int和size_t有什么不同?》 3、《wxWidgets似乎没有事件广播机制》 我现在对wxWidgets的认知来看,它是没有事件广播机制的,但是对于我现在正在开发的一个“相对复杂”的窗口,如果能够以事件广播,将会令代码更加简单。所以想到了一个也许笨拙的方法——使用全局单例——来临时解决问题。 ================ 以下为尚未这里问题 ================ 一、已解决的问题主要有: 1、为什么在程序退出时会产生一些内存泄漏? 答:之前使用的退出方式不正确,之前的退出方式在“程序退出”时,虽然也调用了析构函数,但是那个调用析构函数的时候,实际上内存已经泄露了。我在那个析构函数中进行资源释放,实际上是对已经泄露了内存、且资源句柄已经无效的时刻,才去释放资源,结果就是无权访问会引发程序崩溃。 按照之前的错误思路,怎么办呢?释放就会崩溃,所以只能选择不释放资源,这样程序就不会崩溃了。但是在debug调试器中,就会看到有内存泄漏产生。虽然这里产生的内存泄漏会再被系统回收处理,但是这相当于是将“烂摊子”交给了操作系统的内存控制器。 现在已经解决了。解决的方法就是改用正确的退出函数,这样正确的退出函数会触发正确的析构过程,在这个新的析构过程中,释放资源,此时的资源还没有泄露,也就可以正常的被释放掉。 2、icontray的弹出菜单文字的动态调整 这里只是一个小技巧而已:将mainFrame的指针传给iconTray,这样iconTray内部就能在弹出菜单之前,判断出mainFrame当前的状态,再根据mainFrame的当前状态实时生成菜单,就能够令弹出菜单的内容“实时”,使用体验会比较好。 二、尚未解决的问题: 1、程序多次被启动,虽然我用互斥锁能判断出来,但是第二次启动只能弹出一个提示“已有实例,不要重复启动”。 但是我想做的更好一些,使用IPC通信,第二次的启动可以通过IPC通知第一个实例,第一个实例如果正处于隐藏状态(icontray状态),就自己重新唤醒起来。 2、paintDC的绘制效率很低:已经使用双缓存和悬浮层两个方案,共同解决了这个问题。 3、wxSashLayoutWindow窗口的拖拽改变尺寸,产生的事件 OnSashDrag(wxSashEvent&) 这个事件折磨了我大约4个小时,后来才想起来打印看一下,结果发现这是在鼠标抬起的时候才唯一的产生一次响应。难怪无法实时改变窗口的大小。还没有解决思路。