Content Table

MyBatis 传递多个参数

MyBatis 传递多个参数一般有以下几种方法:

  • 使用 Map
  • 把参数封装成 Bean,传递 Bean 的对象
  • 使用 @Param
  • 编译时使用 -parameters 参数 (推荐使用)

下面以用户名和密码作为参数查询用户为例进行介绍。

Layout 秘录

布局管理器 QHBoxLayout、QVBoxLayout、QGridLayout 相信大家都很熟悉了,对于常用的功能就不一一列举,这里将介绍一下几个不常用,在复杂的自定义界面时又可能会用到的功能:

  • QGridLayout 中多个 Widget 放在同一个位置
  • 把一个 Widget 替换为另一个 Widget
  • QHBoxLayout、QVBoxLayout 中插入 Widget
  • 从 Layout 中删除 Widget

自定义标题栏无边框阴影窗口

Qt 的默认窗口使用系统风格,不能修改标题栏和边框,满足不了高度自定义的窗口设计,这时只能把窗口的默认标题栏和边框隐藏起来,替换上我们自定义的标题栏和边框,下面就以实现自定义标题栏无边框阴影窗口为例进行介绍。

技术要点:

  • 隐藏系统标题栏和边框: QWidget::setWindowFlags(Qt::FramelessWindowHint)
  • 窗口透明隐藏默认背景: QWidget::setAttribute(Qt::WA_TranslucentBackground)
  • QWidget::paintEvent(QPaintEvent *event) 里绘制任意形状的自定义背景
  • 拖拽移动窗口
  • 缩放窗口

带阴影的圆形 Label

圆形头像大家应该都见过不少软件里用过吧,例如 QQ 的好友列表,网页里的人物头像,有没有想过在 Qt 里怎么做到呢?

这一节中就来介绍怎么实现下图中的圆形 QLabel,然后扩展到给 QLabel 添加阴影效果、模糊效果以及加上边框:

圆形 Label

最核心的就是圆形 QLabel 的实现,有很多种方法能够做到,这里使用 QSS 来实现: Border Image + Border Radius,也就是几行代码的事:

  • 圆形: 先设置 QLabel 的大小为固定大小,这样当窗口大小变化时不会影响 QLabel 的大小,并且设置 border-radius 为 QLabel 高度的一半
    • 必须正好是一半出来的效果才能是正圆
    • 大于一半 border-radius 就失去了效果,出来的是矩形,这应该是 QSS 的 Bug,CSS 里就不这样
    • 小于一半的效果是圆角矩形
  • 背景: 为了让背景图缩放填满 QLabel,需要使用 border-image 并且设置 QLabel 边框的宽度为 0
1
2
3
4
5
6
7
8
9
10
QQLabel {
min-width: 100px;
max-width: 100px;
min-height: 100px;
max-height: 100px;

border-radius: 50px;
border-width: 0 0 0 0;
border-image: url(/Users/Biao/Desktop/estas.jpg) 0 0 0 0 stretch strectch;
}

上面的 QSS 就能得到左边第一个圆形 QLabel 的效果。

MongoDB 初接触

MongoDB 的结构是:数据库 > 集合 (collection) > 文档 (document) > 属性 (field)

MySQL 的结构是: 数据库 > 表 (table) > 记录 (record or row) > 属性 (field or column)

下载安装

不同的系统安装 MongoDB 差别挺大的:

  • Mac: 使用 brew install mongodb

  • Linux: 参考 http://qtdebug.com/mac-centos7/#安装-MongoDB

  • Windows: 下载然后安装,安装的时候不要选择安装 MongoDB Compass,因为需要联网下载,国内有可能很久都装不好, 或者下载压缩版解压直接用:

    在 bin 目录中创建文件 mongod.conf, 内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    systemLog:
    destination: file
    path: D:\MongoDB\logs\mongodb.log #日志输出文件路径
    logAppend: true
    storage:
    dbPath: D:\MongoDB\data #数据库路径
    net:
    bindIp: 0.0.0.0 #允许其他电脑访问

    然后创建 path 和 dbPath 指向的文件夹 (文件夹不存在则会导致启动失败)

启动访问

  • 启动 MongoDB:
    • mongod
    • mongod --config C:/etc/mongod.conf
    • mongod --auth --config C:/etc/mongod.conf
  • 访问 MongoDB:
    • mongo
    • mongo --host IP
    • 使用 IDEA 的插件 Mongo Plugin
    • 漂亮的免费客户端 dbKoda
    • 智能的免费客户端 NoSQLBooster for MongoDB (推荐使用)
  • 删除 MongoDB:
    • CentOS
      • 关闭 MongoDB 服务: kill -9 pid
      • 查看有 MongoDB 哪些包: rpm -qa | less | grep mongo
      • 删除 MongoDB 的包: yum erase $(rpm -qa | grep mongodb-org)
      • 删除 MongoDB 的目录: rm -rf /var/log/mongodb ; rm -rf /var/lib/mongo

使用百度 OCR 服务识别图片中的文本

访问 https://cloud.baidu.com/product/ocr/general 可以先体验一下百度的 OCR 文字识别,在功能演示处上传一个含有文字的图片就可以看到识别效果,还是挺不错的,接下来就介绍使用 OCR 服务的编程实现:

  1. 点击立即使用

  2. 点击创建应用 (需要登陆)

  3. 得到应用 API KeySecret Key (在程序中需要使用,对应程序中的 APP_IDAPP_KEY)

  4. 使用 API KeySecret Key 换取 access_token,请参考鉴权认证机制

  5. 使用 OCR 服务识别图片中的文字,请参考通用文字识别

    • 把图片进行 Base64 编码成为字符串

      文档中说所有图片均需要 Base64 编码后再进行 urlencode,这里容易造成困扰,其实 Base64 后就够了,因为 Base64 包含的 64 个字符为 a-z, A-Z, 0-9, /, + 以及填充字符 = 都包含在了 urlencode 不需要进行编码的字符内。

    • 去掉图片头,如 data:image/jpg;base64,

    • 传给百度,然后就能得到识别的 JSON 结果

Qt 项目中使用 OpenCV

相信很多人在 Qt 项目中使用 OpenCV 都遇到过麻烦,Windows 开发者软件推荐 一文中介绍过使用 Vcpkg 来管理第三方库,这里就使用 Vcpkg 安装 OpenCV 然后在 MSVC 的 Qt 项目中使用(因为 Vcpkg 使用的是 MSVC 编译器,OpenCV 是 C++ 库,不能够跨编译器,所以 MinGW 的项目不能使用):

  1. 安装 Vcpkg 就不用多说了,安装到 C 盘根目录下吧

  2. 安装 OpenCV: vcpkg install opencv

  3. Qt Creator 中 创建 Qt 项目

  4. 修改项目的 .pro 文件,主要是下面 2 句引入 OpenCV

    1
    2
    INCLUDEPATH += C:/vcpkg/installed/x86-windows/include
    LIBS += C:/vcpkg/installed/x86-windows/lib/opencv_*.lib

    使用 opencv_*.lib 引入所有 opencv_ 开头的 lib 文件,这样就不需要一个一个的引入 lib 了。

    引入 dll 的时候也可以使用 * 来匹配一次引入多个,例如 tiff*.dll

  5. main.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <opencv2/opencv.hpp>
    using namespace cv;

    int main() {
    Mat img = imread("D:/Wallpaper/desktop.jpg");
    imshow("TEST", img);
    waitKey(6000);

    return 0;
    }
  6. 把 OpenCV 相关的 DLL 从 C:/vcpkg/installed/x86-windows/bin 目录复制到编译出的 exe 所在目录

  7. 运行程序,然后就看到打开一个窗口,图片显示在窗口中

Windows 开发者软件推荐

包管理器 Chocolatey

Chocolatey 是一款专为 Windows 系统开发的、基于 NuGet 的包管理器工具,类似于

  • Node 的 npm
  • MacOS 的 brew
  • Ubuntu 的 apt-get
  • CentOS 的 yml

Chocolatey 的设计目标是成为一个去中心化的框架,便于开发者按需快速安装应用程序和工具,官网为 https://chocolatey.org,安装很简单,根据说明安装即可。

常用命令

  • 搜索: choco search something

  • 列出: choco list -lo

  • 安装: choco install cmake

    可访问 https://chocolatey.org/packages 查看已有的包和说明

  • 卸载: choco uninstall cmake

  • 升级: choco upgrade cmake

  • 固定包的版本,防止包被升级: choco pin windirstat

MyBatis Collecton

MyBatis 中一对多的关系使用 collection 进行映射,但是怎么确定哪些行是同一个对象的数据呢?关键是使用 <id> 来归类数据(MyBatis 的文档只提到是为了提高效率),下面介绍使用 <id><result> 的区别。

数据表

name email country province street
Biao biao@gmail.com china 北京 天河街
Biao biao@icloud.com Deutschland Braunschweig Wiesenstrasse
Alice alice@gmail.com china 河北 鼓楼大街

Xml Mapper

查找所有用户

1
SELECT name, email, country, province, street FROM user

映射文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<mapper namespace="com.xtuer.mapper.UserMapper">
<select id="users" resultMap="userResultMap">
SELECT name, email, country, province, street FROM user
</select>

<resultMap id="userResultMap" type="User">
<id property="name" column="name"/> <!-- 关注这里 -->
<result property="email" column="email"/>
<collection property="addresses" resultMap="addressResultMap"/>
</resultMap>

<resultMap id="addressResultMap" type="Address">
<result property="country" column="country"/>
<result property="province" column="province"/>
<result property="street" column="street"/>
</resultMap>
</mapper>

Java 按照拼音排序

Java 中按照拼音序对字符串排序,只需要使用 CHINA 的 Collator 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.text.Collator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

public class Test {
public static void main(String[] args) {
List<String> tokens = new LinkedList<>();
tokens.add("黄"); // h
tokens.add("慌"); // h
tokens.add("晃"); // h
tokens.add("欢"); // h
tokens.add("中"); // z
tokens.add("这"); // z
tokens.add("国"); // g
tokens.add("古"); // g
tokens.add("安"); // a

Collator collator = Collator.getInstance(Locale.CHINA);
tokens.sort((a, b) -> collator.compare(a, b));

System.out.println(tokens);
}
}