Qt 实现汉字竖排输入(QGraphicsTextItem+FontForge)

文章介绍了如何使用Qt框架结合自定义旋转字体,实现汉字竖排输入的效果,包括文本框的旋转和字体逆时针旋转90度的技巧。作者还分享了开发古籍编辑器的目标,旨在创建一个适应古籍排版的文本编辑器,支持导出OFD或PDF,便于古籍的个人编排、注解和笔记。
摘要由CSDN通过智能技术生成

目标

实现汉字竖排输入和显示(WYS/WYG),如图:
汉字竖排显示和输入

难点

竖排的汉字需要在同一个文本框,且光标是横向的

尝试

限制文本框宽度,每行只能显示一个字体,这样能间接实现竖排。但是缺点也很明显:

  1. 只能实现单行文本的竖排
  2. 光标是竖向的,这样看起来还是横排的,如下图:

限制文本框宽度实现竖排

解决方案

在仔细观察了word和wps的竖排文本框之后,我想出了一个解决办法:

  1. 先把文本框顺时针旋转90度,就可以解决光标竖向显示的问题;
  2. 将字体逆时针旋转90度,与文本框的旋转结合就可以实现汉字竖排(文本框顺时针旋转,字体逆时针旋转相同角度,最后显示出来的字体是没有旋转的,但是光标因为随着文本框旋转,变成横向的了)。

实现方法

页面和文本框

首先,在主窗口创建一个QGraphicsView;接着创建一个QGraphicsScene,显示在QGraphicsView上;然后在QGraphicsScene上绘制一个QGraphicsRectItem白色矩形作为页面,并以一定间距绘制QGraphicsPathItem作为行界。这样一个简单的线装书页面排版就形成了。
我使用的是QGraphicsTextItem作为可编辑的文本框(有尝试用QTextEdit,但是它不支持分页)。
创建QGraphicsTextItem,用SetPos()函数设置其位置(从右边第一行起)、SetFont()函数设置字体(字体是稍后的重点)、setTextWidth()函数设置文本框高度(如果不设置会默认不分行)、setTextInteractionFlags(Qt::TextEditorInteraction)函数实现文本可编辑、setRotation(90)函数实现文本框顺时针旋转90度。

字体

修改字体是实现这个程序的目标的重点。我这里使用的是FontForge。用它将windows系统自带的“华文宋体”的所有字形逆时针旋转了90度。具体方法如下:

  1. 导入字体:系统字体一般放在C:\Windows\Fonts中,复制其中的“华文宋体 常规”到另一个文件夹(防止把原字体改崩了)。然后导入FontForge.
    系统字体文件夹

FontForge导入字体

  1. 旋转字体:全选之后,Element->Transformations->Transform。原点选择字形原点(Glyph Origin),添加旋转动作(Rotate),并把角度选为90、方向选择逆时针(Withershins)。这里需要提一下上面的Move动作,因为字形原点有时候并不在字形的正中心,比如英文和数字字形,所以旋转之后需要再移动,这就需要用到Move动作。这个我也没有弄得很清楚,我只做了旋转。
    字形变换

字形旋转

  1. 保存字体:这里的一些步骤是我自己摸索的,不专业,仅供参考。旋转完成之后,先Element->Add Extrema;然后再Element->Font Info->PS Names修改PS名称;接着在TTF Names中修改TTF名称;点击OK后它会让你修改UniqueID,点击Change修改即可。最后File->Generate Fonts,选择保存的文件夹,选择True Type类型,定义文件名,点击Generate即可。
    Add Extrema
    修改PS名称

修改TTF名称
生成字体
选择True Type类型
最后生成的字体缩略图和预览图如下:
字体缩略图
字体预览图
可以看出英文和数字的坐标还是有问题,这个后面继续研究。

程序

将生成的字体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文件。这样使用者可以自己排版自己的线装书(想象一下自己编一本古文集或古诗集),也可以在阅读古籍的时候加入自己的注解和笔记,也方便传阅和修改。
这是一个不小的工程。本人不是计算机相关专业出身的,所以能力有限。如果有同好的话,欢迎让我抱大腿。而且,开发软件只是第一步,如果你也对传统书籍或传统文化感兴趣,并有志于将其与信息化的方式融合,或者以信息化的方式推广,那么欢迎聊一聊!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值