目标
实现汉字竖排输入和显示(WYS/WYG),如图:
难点
竖排的汉字需要在同一个文本框,且光标是横向的。
尝试
限制文本框宽度,每行只能显示一个字体,这样能间接实现竖排。但是缺点也很明显:
- 只能实现单行文本的竖排
- 光标是竖向的,这样看起来还是横排的,如下图:
解决方案
在仔细观察了word和wps的竖排文本框之后,我想出了一个解决办法:
- 先把文本框顺时针旋转90度,就可以解决光标竖向显示的问题;
- 将字体逆时针旋转90度,与文本框的旋转结合就可以实现汉字竖排(文本框顺时针旋转,字体逆时针旋转相同角度,最后显示出来的字体是没有旋转的,但是光标因为随着文本框旋转,变成横向的了)。
实现方法
页面和文本框
首先,在主窗口创建一个QGraphicsView
;接着创建一个QGraphicsScene
,显示在QGraphicsView
上;然后在QGraphicsScene
上绘制一个QGraphicsRectItem
白色矩形作为页面,并以一定间距绘制QGraphicsPathItem
作为行界。这样一个简单的线装书页面排版就形成了。
我使用的是QGraphicsTextItem
作为可编辑的文本框(有尝试用QTextEdit
,但是它不支持分页)。
创建QGraphicsTextItem
,用SetPos()
函数设置其位置(从右边第一行起)、SetFont()
函数设置字体(字体是稍后的重点)、setTextWidth()
函数设置文本框高度(如果不设置会默认不分行)、setTextInteractionFlags(Qt::TextEditorInteraction)
函数实现文本可编辑、setRotation(90)
函数实现文本框顺时针旋转90度。
字体
修改字体是实现这个程序的目标的重点。我这里使用的是FontForge。用它将windows系统自带的“华文宋体”的所有字形逆时针旋转了90度。具体方法如下:
- 导入字体:系统字体一般放在
C:\Windows\Fonts
中,复制其中的“华文宋体 常规”到另一个文件夹(防止把原字体改崩了)。然后导入FontForge.
- 旋转字体:全选之后,Element->Transformations->Transform。原点选择字形原点(Glyph Origin),添加旋转动作(Rotate),并把角度选为90、方向选择逆时针(Withershins)。这里需要提一下上面的Move动作,因为字形原点有时候并不在字形的正中心,比如英文和数字字形,所以旋转之后需要再移动,这就需要用到Move动作。这个我也没有弄得很清楚,我只做了旋转。
- 保存字体:这里的一些步骤是我自己摸索的,不专业,仅供参考。旋转完成之后,先Element->Add Extrema;然后再Element->Font Info->PS Names修改PS名称;接着在TTF Names中修改TTF名称;点击OK后它会让你修改UniqueID,点击Change修改即可。最后File->Generate Fonts,选择保存的文件夹,选择True Type类型,定义文件名,点击Generate即可。
最后生成的字体缩略图和预览图如下:
可以看出英文和数字的坐标还是有问题,这个后面继续研究。
程序
将生成的字体ttf文件放入Qt程序文件夹,并双击安装;然后在程序中安装该字体。
程序Mainwindow.cpp
代码如下:
#include "mainwindow.h"
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QFont>
#include <QFontDatabase>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//安装自定义字体
QFontDatabase::addApplicationFont(QStringLiteral("D:/QTexm/textdocument/STSongV.ttf"));
this->resize(800,600); //重置主窗口大小
QGraphicsView *view = new QGraphicsView(this);
setCentralWidget(view); //将view作为中心窗口,主窗口中心显示
QGraphicsScene *scene = new QGraphicsScene();
scene->setBackgroundBrush(Qt::gray);
view->setScene(scene); //将scene放在view上显示
QPen pen;
pen.setColor(Qt::white);
float mm = 1/0.26; //将像素单位转换成毫米
//绘制页面
QGraphicsRectItem *pageRect = new QGraphicsRectItem();
pageRect->setRect(0, 0, 400*mm, 300*mm);
pageRect->setPen(pen);
pageRect->setBrush(Qt::white);
scene->addItem(pageRect);
//绘制行界
QGraphicsRectItem *rect = new QGraphicsRectItem(pageRect);
rect->setRect(20*mm, 30*mm, 360*mm, 250*mm);
pen.setColor(Qt::black);
pen.setWidth(2*mm);
rect->setPen(pen);
for (int i = 1; i < 19; ++ i ){
QGraphicsPathItem *line = new QGraphicsPathItem(rect);
line->setPos(i*20*mm, 30*mm);
pen.setWidth(0.5*mm);
QPainterPath path;
path.lineTo(0, 250*mm);
line->setPen(pen);
line->setPath(path);
}
QString text = "天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往秋收冬藏闰余成岁律吕调阳云腾致雨露结为霜金生丽水玉出昆冈剑号巨阙珠称夜光果珍李奈菜重芥姜";
QFont font("华文宋体竖",50);
//创建文本框
QGraphicsTextItem *textItem = new QGraphicsTextItem(pageRect);
//设置文本框
textItem->setPos(380*mm, 30*mm);
textItem->setPlainText(text);
textItem->setFont(font);
textItem->setTextWidth(font.pointSizeF()*20);
textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
textItem->setRotation(90); //旋转文本框
}
MainWindow::~MainWindow()
{
}
写在最后
本人正在自己钻研怎么实现古籍数字化。如今的古籍电子资源一般都是影印版,以图片的形式呈现。本人计划开发一个适应古籍排版的文本编辑器。编辑器可以导出OFD或者PDF文件。这样使用者可以自己排版自己的线装书(想象一下自己编一本古文集或古诗集),也可以在阅读古籍的时候加入自己的注解和笔记,也方便传阅和修改。
这是一个不小的工程。本人不是计算机相关专业出身的,所以能力有限。如果有同好的话,欢迎让我抱大腿。而且,开发软件只是第一步,如果你也对传统书籍或传统文化感兴趣,并有志于将其与信息化的方式融合,或者以信息化的方式推广,那么欢迎聊一聊!