分类 日常 下的文章

Qt 中的窗口大小

本文中所说的窗口都是指 decorated top-level widget,对于简单程序来说通常就是 QMainWindow 的子类对象。

之前玩 Qt 的时候一直以为 QMainWindow 的大小就是 .geometry() 报告的大小(也就是 .width().height()),结果今天发现其实不对的。

起因是我想将一个窗口放在整个桌面的右下角。那么这里有几个问题。

首先 Windows 平台默认下面是任务栏,那么我们肯定不希望窗口的内容被任务栏挡住(或者挡住任务栏),所以这里需要使用 QDesktopWidget.availableGeometry() 来获取可用的屏幕。在 Windows 平台上,这个方法计算除了任务栏之外的屏幕区域;在 Mac 上会计算除了 Dock 栏和菜单栏的屏幕区域。(什么?Linux?抱歉我已经不在桌面上使用 Linux)

那么可能我们就会写出这样的代码

class MyWindow(QtGui.QMainWindow):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        desktop_geopmetry = QtGui.qApp.desktop().availableGeometry()
        self.move(
            desktop_geometry.width() - self.width(),
            desktop_geometry.height() - self.height()
        )

那么显然我们就是 too young。因为根据 Qt 文档.geometry() 这一类的方法返回窗口 widget 区域(相对应地,.width().height() 都是返回窗口 widget 的宽高),而真实的窗口还带有操作系统窗口管理器附加的装饰,例如标题栏和额外的边框。看下图就懂了(图片来自 Qt 文档,链接在本段头部)。

geometry.png

好吧,那么我们现在改成这样就可以了吧?

class MyWindow(QtGui.QMainWindow):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        desktop_geopmetry = QtGui.qApp.desktop().availableGeometry()
        self_geometry = self.frameGeometry()
        self.move(
            desktop_geometry.width() - self_geometry.width(),
            desktop_geometry.height() - self_geometry.height()
        )

那么显然我们又是 too simple。因为我测试了发现,如果这个窗口还没显示(__init__ 里显然还没显示),那么 .frameGeometry() 这类方法的返回结果其实跟 .geometry() 这一类是一样的。换句话说,只有窗口被至少显示过一次,窗口管理器才有机会去装饰它,这样 Qt 才能知道最终窗口的实际占用区域大小。

那么我们只要在首次 showEvent 信号被触发的时候来获取窗口大小,然后据此移动窗口就可以了(当然如果你想每次显示都移动一下我也没话说 =,=)。

class MyWindow(QtGui.QMainWindow):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.__first_show = True

    def showEvent(self, evt):
        evt.accept()
        if self.__first_show:
            desktop_geopmetry = QtGui.qApp.desktop().availableGeometry()
            self_geometry = self.frameGeometry()
            self.move(
                desktop_geometry.width() - self_geometry.width(),
                desktop_geometry.height() - self_geometry.height()
            )
            self.__first_show = False

写了一个键盘计数器

起因是有个朋友说想写一个小工具看看自己每天敲了多少次键盘,当时因为很忙就直接回复用 pyHook。后来没忍住,自己业余时间写了个图形界面的工具,用了几天感觉还可以了,放出一个 exe 下载。

项目在 Microcore/KeyCounter,下载在项目的 release 里,目前只支持 Windows。主要原理就是

  • 用 pyHook 监听键盘按键被按下的事件
  • 创建一个屏幕大小的窗口,背景设置为透明,在上面绘制数字
  • 每次按键事件,更新数字并且重绘窗口上的文字
  • 创建一个托盘图标,通过菜单来重置计数、调整文字透明度和退出

代码写得很简单,基本就是去调用各种 Windows API,不过设置透明度的窗口是用 MFC 做的。

中间还发现三个问题。第一是如果你监听 KeyDown 事件,那么按住一个键一段时间后,这个事件就会不停触发(后来想了一下这是合理的);二是如果你监听 KeyUp 事件,那么基本上可以断定你会遇到 pyHook 的头号 bug,目前还没有修复,而我也不想直接修改它的源码;最后一个就是,我尝试监听鼠标键按下的事件,发现会对鼠标指针的移动速度造成很大影响(我是速度调得比较高并且去掉指针加速的,如果你是老年人速度那么可以尝试搞一搞),就是鼠标移动快一点的话,比如跨屏快速定位,指针酒会变得一卡一卡的。最终我放弃了鼠标键计数,专心做键盘计数。

想要验证签名的话请使用这个公钥 0A662175C3997E84A6FA879499321BCE08B738B8,关于如何验证签名请参考 Making and verifying signatures

最后提一下一个 Simon Brunning 写的一个很有用的 Windows 系统托盘图标类,以及一个实用的量化生活工具(其中包含了记录键盘活动,并能进行历史搜索和统计等操作)selfspy

12月近况

11月和12月似乎并没有什么重要的事情发生的样子。那么以下是并不重要的流水账。

  • 黑五 Steam 打折,趁机入手了几个之前玩过盗版的游戏.
  • 从 12月13日 起,本站开始使用 HTTP2 了(托管在别处的子域名除外)。
  • 之前因为网站迁移到了国内,所以 Telegram 机器人一直没去弄了(网络原因)。最近清理了一下之前的代码,没什么卯月的功能都去掉了,增加了一个消息推送功能,也是目前唯一的功能。
  • 买了一个诺基亚 5110 的 LCD 屏幕用在树莓派上,然而对比度太低,加上屏幕接触不良、液晶显示速度慢等等问题,现在已经不在使用中。
  • 买了一个 SSD1306 驱动的 OLED 单色屏幕,对比度高,SPI 接口速度还不错,使用中。
  • 买了本 Flask 的书(好久不买实体书了),希望能一边看一边做点实用的东西出来。
  • Mac 上有些应用突然打不开(可能是上次 MAS 证书过期问题导致的),这其中包括 Dash 2;然而 Dash 2 的 MAS 页面已经被替换成了 Dash 3,内购解锁完整版的价格是 163 软妹币。因为我之前通过 MAS 购买了 Dash 2 的原因,给作者发邮件后拿到了优惠码,现在已经换成 Dash 3 了。
  • DNSPod 在 12月18日 解决了Let's Encrypt 的支持问题,之后如果可行的话所有子域名都会强制开启 HTTPS。
  • 前段时间作息有点不太规律,近期计划调整好。
  • 好像很久没画画了,记得不要荒废了自己的数位板。
  • Google Analytics 拖慢页面加载速度,加上很多用户都会开启 Adblock,其实并没有什么卯月,打算年底前找个替代品。
  • Gravatar 拖慢页面加载速度,目前换成了 typcn 的镜像,先观察一段时间。

那么额外说明一下该如何启用 HTTP2 吧(Ubuntu 系统)。首先卸载已经安装的所有 nginx

然后导入 Nginx 官方签名的 key:

wget -c http://nginx.org/keys/nginx_signing.key
cat nginx_signing.key | sudo apt-key add -

其次,在 /etc/apt/source.list 中加入 Nginx 官方源:

deb http://nginx.org/packages/mainline/debian/ codename nginx
deb-src http://nginx.org/packages/mainline/debian/ codename nginx

其中 codename 替换成你自己所使用 Ubuntu 版本的代码名称。
接下来 apt-get update 更新一下软件包列表,然后重新安装 nginx

这时候 nginx 应已经是 1.9 以上的版本了。在配置文件中修改启用 HTTP2:

server {
    listen 443 http2;
    ssl on;
    ...
}

然后重启 nginx 就好了。

开启了之后感觉飞快的样子,页面打开时间比之前减少一半以上,不知道是不是我的错觉。

6 月近况

一转眼又很久没更新博客了,这地方还真是快长草了。那么简单说一下最近的一些事情吧。

先是 4 月底的时候感染了水痘。对的,没错,我一个大好青年居然这个年龄感染了水痘,然后在家休息了差不多半个月。
前一周基本都是在去医院拿药 → 回家吃药 → 昏睡中度过的,而且出去拿外卖或是去医院拿药还要带着口罩躲着人群,生怕传染给别人。而且广州是很热的,于是电费开始爆炸……

- 阅读剩余部分 -

近况

也是有几个月没有更新博客了呢。这段时间我都在做什么呢?基本上,有时候折腾树莓派,有时候做做字幕,有时候看看小说,有时候就只是无意义地刷新各个社交网络。

广州大概是要进入传说中非常潮湿的一段时间了,早晨下楼时地面上还能看到凝结的水珠。真是非常可怕的季节,我从老家带来的散装零食如果不快点吃完的话估计要完蛋。
总感觉最近一个月都处于莫名的低谷期。自己的项目,各种坑开了一堆没有动力也没有灵感来填,在前端上也没有像以前一样追得那么紧了。如在其上,如在其下,总感觉似乎碰到了计算机基础不得了的天花板 / 地板。因为基础没怎么学,有些第一手资料开始看不懂了。

嘛,这段时间一直在看房子,因为我有点想在月底房租到期前搬走,现在住处的卫生实在是无法形容。以及,入手了 MacBook 但是暂时还没拿到手。入手了一个 Bamboo 数位板正在胡乱画画。

大概就这些吧。希望尽快恢复灵感,不然这个博客以及我开的众多坑看起来就太可怜了。

博客平台迁移基本完成

终于可以在自己的博客上写下划时代的第一篇文章了,这真是个里程碑。
话说上次在临时的 Ghost 博客上发表关于我之前的 VPS 提供商事情的文章时,我根本没想到我会自己写一个博客程序。
当时觉得自己从头写博客程序好麻烦,尤其是想到什么插件机制、主题机制之类的。
不过后来转念一想,如果只是自己用的话,什么主题支持根本不需要去做(况且 Django 的 App 分离策略可以让单一功能的模块做成一个 App ,对我来说也相当于插件)。
写就写,谁怕谁啊,又不是没做过网站。

- 阅读剩余部分 -

Maybe a new start?

This post was posted on my temporary blog site, as my blog went down during the last two months. Some information could have been changed after its publication.
Now the new website is online ( built with Django ), and that temporary blog will be offline in approximately two weeks.

Several weeks ago my former VPS provider stopped nearly all services for its users, without any proper notification. In the meanwhile, I was home for my winter vacation and could not do anything about it, as I had no Internet connection. And after trying to contact customer service, I thought it might be a good time to start blog again.

- 阅读剩余部分 -

近况

回来看看,才发现上一次写东西是快一个月之前了。这段时间真是有够忙的,不过真正在忙我自己的事的时间确实少得可怜。

首先,我跟计算机学院的同学和老师合作的一个网站上线了。点这里:录取线 - 往年各院校录取分数线查询,或者这里:录取线后备站点。这个网站其实非常简单,不过数据的收集存储是一件很麻烦的事情,所以从成型到上线花了比较多的时间。

其次就是,我加装了一块硬盘,空了一点空间出来安装了一个 Windows 7 系统,因为暑假有一个项目不得不用万恶的 Windows 。引导的问题,我本来想用 Grub2 自动检测解决,还为此专门在微博上请教了盖子老师,不过最终没有用。因为后来考虑到硬盘其实不会经常拆卸,所以把 Windows 硬盘挂到了主硬盘位置( BIOS 里设置主从顺序无效,不知道原因), Ubuntu 挂到了光驱位。 Windows 引导用的是 EasyBCD ,添加了 Ubuntu 系统; Ubuntu 用的是 Grub2 。

嗯,就是这样,然后我又开始了对 Windows 的狂轰滥炸。安装 Visual Studio 2012 的时候,看到它最先开始的操作是创建系统还原点,嗯,呵呵。一个公司要对自己的系统多么没有信心才能干出这种事来?其他各种问题我就不说了,简直人干事。

默认日记

好吧,我又在 GitCafe 上开了个坑, BooTypecho ,深度整合 Bootstrap 的 Typecho ,地址在:https://gitcafe.com/JokerQyou/BooTypecho 。

本来我打算全部整合完了再发布上去的,但是照这速度下去,寒假前是弄不完了,所以先发布下,然后慢慢推进。希望自己可以坚持下来,不让这个项目跟其他的一样夭折掉。