统一 Qt 4 和 Qt 5 程序的界面——简单方法

现在正是 KDE 4 和 KDE 5 家族(原谅我用了这个不严谨的说法,因为解释起来实在有点复杂)世代更替的时候。包括 kate 、Gwenview 等等在内的部分 KDE 应用已经基于 KDE Framework 5 。但是不知是因为功能特性已经冻结,还是开发者没有意识到或者没有精力解决这个问题, KDE 4 的界面设置对 Qt 5 程序是不生效的,再加上最初 Oxygen 主题标题栏的设计在外观上和窗口内容是整合的,一旦界面不统一,标题栏和内容不能融为一体,观感就会很糟糕。这个问题困扰了我很久,今日终于找到了解决办法。

首先,如果是运行着 KDE 4 的话, KDE 4 的界面配置文件是 ~/.kde4/share/config/kdeglobals (有的发行版可能是 .kde 而不是 .kde4),但是对于 Qt 5 程序来说,每次运行的时候读取的文件却是 ~/.config/kdeglobals 。KDE 4 的设置只会修改前者,所以 Qt 5 程序的界面并不会随之变动。到目前为止, Plasma 5 似乎也不会改 KDE 4 的界面配置文件。

于是想统一界面,方法就很简单了。首先需要装好分别针对 Qt 4 程序和 Qt 5 程序的同名主题,然后删掉当前桌面环境不会修改的配置文件,并且创建一个同名的、指向能够改变的配置文件的符号链接就可以了。

例如我现在用的是 KDE 4 ,首先装好 KDE 5 的 oxygen 主题(不同发行版的包名可能不同,在 Arch 上这个包现在就叫 oxygen )。

然后把 KDE 5 的界面配置文件改个名,备份起来:
mv ~/.config/kdeglobals ~/.config/kdeglobals~

最后,再创建指向 KDE 4 配置文件的符号链接:
ln -s ~/.kde4/share/config/kdeglobals ~/.config/kdeglobals

这样就大功告成了。再启动 Qt 5 程序,显示效果非常完美。

一会得把这方法写到 Arch 的 Wiki 上去……

思源黑体——Adobe和Google联合华文、イワタ、Sandoll推出的开源CJK无衬线字体

本来我这个懒汉是不怎么写网志的,不过今天Twitter简直被这个字体刷屏了,可见这个新字体带来的震动之大。确实是一件值得记叙的大事情。

众所周知(好吧,也许不是周知),字体,尤其是计算机字体的设计与调试是一项极为困难而繁琐的工作,需要兼顾美观、辨识度、针对屏幕优化、减少视觉疲劳等多个方面。汉字数量繁多、笔画复杂、形态优美,字体设计尤其困难。一直以来,开源界优秀中文字体相当有限(常用优秀中文开源字体参见这里)。

本次,Adobe和Google联合中日韩三家字体设计公司华文(Sinotype)、イワタ(Iwata)、Sandoll,共同推出开源中日韩字体——思源黑体。AdobeGoogle分别撰文予以报道。

这款字体完整包含简、繁、日、韩四种不同字形及六种不同粗细,总字体数量超过50万,将分别作为Adobe Source Sans字体家族及Google Noto Sans字体家族中的成员。

Adobe公告下载源代码

Google公告Noto Sans CJK主页


使用体验稍后奉上。

Qt编程新手躬行经验记(持续更新?)

Qt是我唯一使用过/使用的编写图形程序的库。虽然我编写的图形程序很少且都很简单,不过由于实在没什么经验,一来二去也碰壁数次。在这里将自己吃过的亏总结一下,既供备忘,又可为后来者提供一些经验。

元件的尺寸与布局管理

布局管理是个好东西,不过有些问题要注意。首先,如果没有人为干预的话,布局管理是在这个窗口真正显示出来的时候才生效的,也就是说如果是用自定义类来继承QWidget/QMainWindow的方法做窗口,在类的初始化阶段它还没有生效,此时取到的元件长宽等属性和窗口真正显示的时候是不一样的。必要时考虑使用QLayout::update()和QLayout::activate()来强制更新布局。

QString与编码

编码是个讨厌的问题……然而作为中国人,在UTF统一世界之前是没有可能回避得过去的。

QString内部采用UTF-8编码,那么源码一律使用UTF-8就没问题了吧?很遗憾,如果在源代码用C风格字符串来初始化的话,不论源码本身的编码是什么,Qt默认都会调用QString::fromAscii(),把字符串当成ASCII来处理。所以无论使用GBK、BIG5还是UTF-8,最后中文存进去全都是错的。正确的办法是手动调用fromUtf8()、fromLocal8Bit()等等,在建立之初就转换好。也可以在全局使用
QTextCodec::setCodecForCStrings(QTextCodec::codecForName(“GB2312”));
或者
QTextCodec::setCodecForCStrings(QTextCodec::codecForName(“UTF-8”));

来为整个程序一劳永逸地设计编码。

拿什么显示图片?

如果我有一张图片需要显示在窗口中,应该拿什么元件来装?直观地想应该是QWidget,然而实际使用的时候却发现QWidget居然没有setPixmap(),虽说用setPalette或者setStyleSheet之类的方法也能实现,不过太不优雅。其实正确的做法是使用QLabel。QLabel的方法是明确写在文档里的,不过为啥会是用QLabel我一直搞不太懂……而且,似乎同一个QLabel不能同时既显示图片又显示字。

QPixmap的使用

首先,QPixmap必须在QApplication的实例创建之后才能使用。这个问题会有明确的错误提示,不过最好还是早发现造解决,不要到后来数据结构都设计好了最后还要重构……

还有一个问题需要注意……QPixmap在主线程以外使用是不安全的。这一点我一直没想明白,不过既然Qt这么说了,若非不得已,就这么用吧……

VPS购买与配置记

买VPS是我琢磨了很久的事情了,以前一直没有付诸实践,一是有点舍不得这个钱,二是自知水平与精力都实在有限,即便买了,也不能发挥其真正的能力。最近在现实生活中混得很不得意,于是乎某种愚蠢的勇气占了上风,心一横,决定当做玩具买了。

服务器是从Arch Linux中文社区的管理员之一——凤凰君(@phoenixlzx)手中买的最低端方案(网站在此),就我未来一段时间可能玩的东西来说应当是足够了。

我目前的网志在wordpress.com上,所以服务器启动之后我做的第一件事是先搭个wordpress出来然后迁移网志。最开始我为了用较新的软件包,选的系统是OpenSUSE 12.1,后来发现用OpenSUSE做服务器的相关资料非常少,而且折腾配置麻烦,于是乎作为一个彻头彻尾的小白,我最后采纳了凤凰君的建议,换了Debian 7.0 Wheezy,发现软件也还蛮新的。

得益于强大的apt包管理系统,Debian上面Apache、phpMyAdmin、mySQL的配置都相当方便(而且有文档)。源里也可以直接装wordpress(不过为了日后升级时不混乱,还是直接从官网拉下来装的)。在此有一个经验——千万不要相信宣传中所谓的5分钟安装一类的措词,那都是在对LAMP/LNMP有充分了解的情况下才能做到的。而对小白来说,会面临这样那样的许多问题,需要逐一地查找资料解决,能在5个小时之内彻底地配置好就很不容易了。

虽然我以前完全没了解过Apache和php,不过东拼西凑查找了下资料,再加上一些人的帮忙,目前网志已经正常运转了(ukyoi.info)。至于以后的计划……科学上网自不必提,这个十一我准备学学基本的html、Javascript知识,写的小东西也可以放在上面。鉴于我的网志根本没什么人来,200G的流量再搭个OwnCloud什么的应该也不错。另外据说Apache负载会比较大?改天研究研究换成Nginx吧。

最后要感谢一下凤凰君。他的“售后服务”做得相当的尽心到位,耐心解答了我的很多问题。

自制快速调节鼠标灵敏度的小玩意——SimpMouse

simpmouse_pic

介绍:

这是我最近弄的小玩意,可以识别连接的鼠标,并分别调节每个鼠标的“减速系数”(Constant Deceleration)。

代码托管在Github上:
https://github.com/ukyoi/simpmouse (点此进入项目页面)
欢迎fork和贡献(虽然我觉得应该没什么人fork)。

功能上,选中要调节的鼠标,然后拖动滑杆或输入数值,就可以改变鼠标灵敏度。由于减速系数取值是1到正无穷(应该是正无穷吧……),所以滑杆那里我取了个倒数,左端对应数值为16。直接输入的话则可以接受任何有效的数值。

另外,虽然有Refresh、Apply和Cancel三个按钮,不过这些都是半年前构想中的功能,现在统统用不了,当然更无什么记忆功能。总之只是个很简陋的半成品。

主要用到的东西:Qt做界面、C++、Qt做基本功能(使用qmake进行构建)。
通过运行 xinput list 和 xinput list-props 获取鼠标信息,并用 xinput set-prop 写入Constant Deceleration数值。

关于这个程序的一些废话:

最初想法源于半年前跟人联网用wine玩星际。KDE的鼠标调节功能比较残,指针加速那里即使调到最低,我的鼠标也还是太灵敏(xfce的鼠标调节就很好,可以每个鼠标独立调整,项目也多)。网上查到用xinput可以对鼠标行为进行精细调节,我就打算写个方便的图形工具来用。结果一下拖到现在,星际自然是早就不打了,程序也变成了练手(自娱自乐)之作。至于程序名……由于这个程序对多数人来说实在是没啥大用,请原谅我没在上面花什么心思。

我本以为如此小程序,不会有什么代码量,然而最终代码量却出乎我的意料。当然回报也是有的,我的最大收获大概在于对如何组织程序的结构有了一些经验。我之前只是看过一些编程语言的教材和简单的算法,而对哪怕一个很小的程序应该如何设计和组织则全无经验。通过边写这个程序边进行重构,我对代码该怎么划分、怎么组织都有了一些粗浅的了解。虽然程序本身很小,但我自认为带来的收获还是可观的吧。

C/C++ 包含顺序引发的错误一例

这个错误是我最近在写一个Qt小程序的时候出现的,觉得有一定价值,打算写出来。由于我水平实在太弱,故若高手们看了之后觉得浪费了自己的生命,还请轻拍。

假如我的程序除了main.cpp之外还有3个.h/.cpp组,这里用A.h、B.h、C.h代替:

[code language=”cpp”]
// main.c
#include "A.h";
// Do something…
return 0;
[/code]

[code language=”cpp”]
// A.h
#ifndef A_H
#define A_H

#include "B.h";
#include "C.h";

#endif
[/code]

[code language=”cpp”]
// B.h
#ifndef B_H
#define B_H

class A_Class;

#endif
[/code]

[code language=”cpp”]
// C.h
#ifndef C_H
#define C_H

#include "A.h";
void a_function(A_Class an_arg);

#endif
[/code]

可以看出,C.h的一个函数中要用到B.h中声明的一个叫做A_Class的类。由于A.h包含了C.h和B.h,而C.h又包含了A.h,因此看上去C.h可以通过A.h包含B.h,从而用上B.h中声明的类。

之后通过qmake等等自动写makefile的工具生成makefile,进行编译。然而在编译的时候,编译器却会给出错误,说A_Class没有被声明。而如果把A.h中包含的顺序调换一下,先包含B.h,再包含C.h,编译就能够通过。

问题主要就出在A.h和C.h的相互包含上。A.h先包含了C.h,根据生成的makefile,编译器会先开始处理C.h,而在C.h被处理完毕之前,B.h是不会被处理的,因此编译器会说找不到B.h中声明过的类。而如果把A.h中包含的顺序调换,在处理C.h之前,B.h已经被处理好了,就不会出现找不到声明的情况。

因此为了避免这类问题,最好把头文件间的关系理清,不要出现这种“互相包含”的情况。如果非要用到彼此的东西,可以使用前向声明(但这种方法实际操作起来是很麻烦的)。另外,既然有了#ifndef的保护,凡是要用到的东西统统在头文件里包含一遍,这样也可以确保所有需要用到的东西在用到之前都是准备好的。

[转] 我是一个硬盘……我是一条内存……

在Google Plus上看到的,从里面涉及到的硬件来看应该是个老文了。原作者已不可考,特此感谢。

 

我是一个硬盘

我是一个硬盘,st380021a,在一个普普通通的台式机里工作。别人总认为我们是高科技白领,工作又干净又体面,似乎风光得很。也许他们是因为看到洁白漂亮的机箱才有这样的错觉吧。其实象我们这样的小台式机,工作环境狭迫,里面的灰尘吓得死人。每天生活死水一潭,工作机械重复。跑跑文字处理看看电影还凑活,真要遇到什么大软件和游戏,上上下下就要忙的团团转,最后还常常要死机。我们这一行技术变化快,差不多每过两三年就要升级换代,所以人人都很有压力而且没有安全感。每个新板卡来的时候都神采飞扬踌躇满志,几年光阴一过,就变得灰头土脸意志消沉。机箱里的人都很羡慕能去别的机器工作。特别是去那些笔记本,经常可以出差飞来飞去,住五星级的酒店,还不用干重活,运行运行word,上网聊聊天就行了。而我更喜欢去那些大服务器,在特别干净明亮的机房里工作。虽然工作时间长点,但是福利好,24小时不间断电ups,而且还有阵列,热插拔,几个人做一个人的事情,多轻松啊。而且也很有面子,只运行关键应用,不像我们这里,什么乱七八糟的事情都要做。不过我知道,那些硬盘都很厉害,不是scsi,就是scsi II, fibrechannel,象我这样ide的,能混到工作站就算很不错了。

我常常想,当年在工厂里,如果我努力一下会不会也成了一个scsi,或者至少做一个笔记本硬盘。但我又会想,也许这些都是命运。不过我从不抱怨。内存就常常抱怨,抱怨他们主板部门的复杂,抱怨他如何跟新来的杂牌内存不兼容,网卡和电视卡又是如何的冲突。

我的朋友不多,内存算一个。他很瘦的而我很胖,他动作很快,而我总是很慢。我们是一起来这台机器的,他总是不停地说,而我只是听,我从来不说。

内存的头脑很简单,虽然英文名字叫memory,可是他什么memory都不会有,天大的事睡一觉就能忘个精光。我不说,但我会记得所有的细节。他说我这样忧郁的人不适合作技术活,迟早要精神分裂。我笑笑,因为我相信自己的容量。

有时候我也很喜欢这份工作,简单,既不用象显示器那样一天到晚被老板盯着,也不用象光驱那样对付外面的光碟。只要和文件打交道就行了,无非是读读写写,很单纯安静的生活。直到有一天。

我至今还记得那渐渐掀起的机箱的盖子,从缺口伸进来的光柱越来越宽,也越来越亮。空气里弥漫着跳动的颗粒。那个时候,我看到了她。她是那么的纤细瘦弱,银白的外壳一闪一闪的。浑身上下的做工都很精致光洁,让我不禁惭愧自己的粗笨。等到数据线把我们连在一起,我才缓过神来。开机的那一刹那,我感到了电流和平时的不同。后来内存曾经笑话我,说我们这里只要有新人来,电流都会不同的,上次新内存来也是这样。我觉得他是胡扯。我尽量的保持镇定,显出一副很专业的样子,只是淡淡的向她问好并介绍工作环境。慢慢的,我知道了,她,ibm-djsa220,是一个笔记本硬盘,在老板的朋友的笔记本里做事。这次来是为了复制一些文件。我们聊得很开心。她告诉我很多旅行的趣闻,告诉我坐飞机是怎么样的,坐汽车的颠簸又是如何的不同,给我看很多漂亮的照片、游记,还有一次她从桌子上掉下来的的历险故事。而我则卖弄各种网上下载来的故事和笑话。

她笑得很开心。

而我很惊讶自己可以说个不停。

一个早晨,开机后我看到数据线上空荡荡的插口。

她一共呆了7天。后来,我再也没有见过她。

我有点后悔没有交换电子邮件,也没能和她道别。不忙的时候,我会一个人怀念射进机箱的那股阳光。

我不知道记忆这个词是什么意思,我有的只是她留下的许多文件。我把它们排的整整齐齐,放在我最常经过的地方。每次磁头从它们身上掠过,我都会感到一丝淡淡的惬意。

但我没有想到老板会要我删除这些文件。我想争辩还有足够的空间,但毫无用处。于是,平生第一次违背命令,我偷偷修改了文件分配表。然后把他们都藏到了一个秘密的地 方,再把那里标志成坏扇区。不会有人来过问坏扇区。而那里,就成了我唯一的秘密,我常常去看他们,虽然从不作停留。

日子一天一天的重复,读取写入,读取写入…我以为永远都会这样继续下去,直到一天,老板要装xp却发现没有足够的空间。

他发现了问题,想去修复那些坏扇区。我拒绝了。很快,我接到了新命令:格式化。

我犹豫了很久

。。。
。。。
。。。
。。。
。。。

track 0 bad, disk unusable

我是一条内存

我是一条内存,我在一台台式电脑里工作,但是我记不得我是从哪里来的,是什么牌子,因为我健忘。我的上司是cpu大哥,他是我们的老大。都说他是电脑的脑子,可是我看他的脑子实在是太小了,比我还要健忘。每天他总是不停的问我,某某页某某地址存的是什么?我总是不厌其烦的告诉他,可是不出一秒钟他又忘记了,又要问一遍,一次我说大哥你烦不烦,你就不能记住点有用的东西?他说“内存兄弟,我有苦衷啊,每天都在不停地做题,头晕眼花的,我也难啊。”

其实我不愿意跟他计较,因为他脑子小,思维也很简单。虽然说他是我的上司,可是每次睡觉醒来,他连要干什么都不记得了,总是急急忙忙地找bios兄弟,“嘿,哥们,今天干什么来着”。bios总是很不耐烦地把每天必做的工作说一遍,然后就去睡觉了。接下来就轮到我和c哥瞎忙了。

在机箱里的兄弟中,我最喜欢硬盘。他脑子大,记得东西多,而且记得牢。他说话的速度很慢,而且很少说错,这说明他很有深度,我这么感觉。cpu也这么想,不过他很笨,每次都忘了硬盘是谁。开机自检的时候总要问:嘿,那家伙是谁?

“st380021a!”我总要重复一遍。

硬盘很喜欢忧郁,我觉得像他这样忧郁的人不适合做技术活,迟早会精神分裂的,但是他不信。

其实睡着的时候我总是把几乎所有的东西都忘记掉,但是我从来都不会忘记朋友。有一块地方叫做cmos,那是我记忆的最深处,保存着硬盘、光驱的名字。有些东西应该很快忘掉,而有些东西应该永远记得。我在梦中总是这么想着。

bios是一个很奇怪的家伙,他老是睡觉,但是却总是第一个醒过来。让我们自检,启动,然后接着睡觉。我知道如果我在cmos里头把bios shadow选项去掉,他就睡不成了,但是看着他晕晕乎乎的样子,也就不忍心这么做了。他对人总是爱搭不理,没有什么人了解他。但是这次硬盘恋爱的事,却使我重新认识了他。

那是很久以前的事了,机箱里似乎来过一块笔记本硬盘,很可爱,说实话我也喜欢她。不过现在除了记得他可爱,别的都忘记了。这就是我比硬盘幸运的地方,我把所有应该忘记的都忘记了,但是他却什么都记得。

自从笔记本硬盘走了之后,硬盘就变得很不正常。每次他的磁头经过一些地方的时候,我们都能感觉到电流很不正常。

“硬盘这是怎么了?”我问cpu。

“谁是硬盘?”

我就知道和cpu没有办法交流,倒是bios没好气地说:“那个傻瓜恋爱了”。我不知道什么是恋爱,因为我记不住东西,似乎有一些人或者事在我生命中留下过痕迹,但是我都轻率地把他们忘记了。

bios对我说:“对你来说记忆太容易了,所以你遗忘得更快,生命中能够永刻的记忆都带着痛楚。”我不懂,但是我知道bios曾经被刷写过,那时他很痛,像要死了一样。我的记忆是轻浮的,不像他们……我很羡慕他们,因为他们拥有回忆,而我没有,从此我也学会了忧郁,因为我在cmos里面写下了“忧郁”两个字。

硬盘一天比一天不对劲,终于有一天,cpu对我说:下条指令是什么来着?

我一看,吓了一跳:“format”。

“是什么?”cpu很兴奋,这个没脑子的家伙。

我还是告诉了他。我不知为什么这么做。

硬盘犹豫了很久,终于说了一句 track 0 bad, disk unusable。

电停了,很久很久,我在黑暗中数着时钟。

一个月后硬盘回来了,也许最后的挣扎也没有使他摆脱残酷的命运,他被低格了。他什么也不记得了,如同一个婴儿,我们很难过,但是这未必不是一件好事,他以后不用痛苦了。

为了恢复数据,笔记本硬盘回来了。”hi,st”,她说,”你不认识我了?”

硬盘没有说话,似乎低格对他的伤害很大。

过了一会,他说:“对不起,好像我们没有见过吧……”。

笔记本硬盘显得很伤心,我能感觉到她带泪的电流。“想不到连你也这么健忘”。

“哦……”。硬盘没有回答。

我很难过,笔记本硬盘的心里依然记着他,而他把一切都忘了,而那正是他最不希望忘却的。究竟是幸运,还是痛苦,我说不上来,只是觉得造化弄人,有一种淡淡的悲凉。

这时从bios传来一阵奇怪的电流,我感觉到硬盘的表情在变化,由漠然到兴奋,由兴奋到哀伤,由哀伤到狂喜……

“ibm,你回来了……”。

………………
………………
………………
………………
………………

后来bios对我说,其实他并没有睡觉,自从硬盘把那些文件藏起来以后,他就料到会有这样的结局,于是偷偷地把其中一些文件放到了备份里。

“幸好我是dual bios,虽然藏得不多,还足够让他想起来……”。

我想bios保存这些东西的时候一定很疼,“为什么这么做呢?”

“呵呵,我们是朋友嘛”。

Linux下,android手机/平板使用USB反向共享(reverse tethering)PC的有线网络

以前的手机共享问题我都是用hack过、支持ad-hoc的wpa_supplicant解决,不过最近升级了android4.2,找了很久也找不到适用的wpa_supplicant。踏破铁鞋之后,在XDA上看到了这样一个用USB反向共享的方法(点击进入原文),总结如下:

首先建议要有adb,没有的话就得在手机的终端模拟器里码字,太累。

主机(PC)方面,以root执行:

[sourcecode language=”bash”]
iptables -A POSTROUTING -t nat -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward
[/sourcecode]

这两句是打开网络地址转换(NAT)和IP转发。

[sourcecode language=”bash”]
ifconfig [您的网络接口地址] 12.12.10.1
[/sourcecode]

这句是为接口设置IP。网络接口地址不同的机器有所不同,可以用ifconfig命令看。有的发行版是usb0(如果使用usb共享的话),我所用的Arch为了避免插了新网卡出现地址名不固定的问题,用的是另一种命名,比如我的接口名是enp0s26f7u1。

IP地址并不一定非要是12.12.10.1,192.168.0.1之类的也是可以的,但要和下面手机设置的域保持一致。

手机方面,首先要打开移动网络,因为有些软件似乎必需在“形式上有网络连接”的状况下才能使用。
在adb shell或终端模拟器里,root环境下:

[sourcecode language=”bash”]
ifconfig rmnet0 0.0.0.0
[/sourcecode]

此为关闭手机信号连接。

[sourcecode language=”bash”]
ifconfig usb0 12.12.10.2
route add default gw 12.12.10.1 dev usb0
[/sourcecode]

为手机的usb0接口配置IP地址(12.12.10.2),并设置路由为主机(12.12.10.1)。注意IP这里的域要和主机的匹配。

[sourcecode language=”bash”]
setprop net.dns1 8.8.8.8
[/sourcecode]

设置DNS服务器。8.8.8.8是一个著名的DNS服务器,归Google所有。

至此,手机就应该能够正常联网了。android4.0后官方加入了wifi-tether,我没有测试,但理论上应该也能如法炮制(甚至不需要分配IP这一步,因为PC连接上之后IP会被设置为192.168.x.x),只需把主机的接口地址换成无线网卡的,再把手机端的usb0换成wlan0即可。欢迎大家尝试。