自动换行且带下划线的居中长标题的论文封面一种绘图实现
引言
在一些学位论文的封面上要求标题带有下划线,但长标题的情况下标题自动换行后下划线就会面临一些问题。
因此,往往需要一些特殊的处理。
在《如何制作自动换行且有定长下划线的论文封面模板?》,
《毕业论文封面上的标题下划线处理》
《不定长, 自动换行且有定长下划线的“论文标题”》
等文章中,
提供了一些很好的思路。主要有:利用表格内容下划线结合手动的画线;根据输入文本的长度直接对该文本分行并做下划线;利用两个同位置的adjustbox一个输出文本另一个根据行距指在定位置填充线作为下滑线。
然而,这个带下划线的长标题文本实际上只是封面等页面中的一个部分,在考虑实现时需要统筹页面中的其他要素。
考虑到在一个页面中过多的使用表、图等不同元素,实际上会导致精确定位等方面存在困难。
因为,为使下划线长文本能与其他要素更统一,也为了进一步简化代码,本文提供了一种新的实现,即直接利用绘图得到页面中的所有要素,从而避免使用表格来对齐,避免使用下滑线来处理复杂的换行,避免利用vspace等来定位,使得整个实现更易理解,更便于迁移和修改。
本文中对带下划线的多行长文本的处理类似于前述的第三种思路,但是利用tikz实现。首先利用tikz的node来输出自动换行的文本,然后从node中获得位置信息后直接根据行距绘制下划线。
值得注意的是,利用tikz绘制封面是一种比较常见的方法,所以本文只说是提供一种新的实现,相当于利用绘图这种方法来解决一些特殊的问题。
下面按从简到繁的顺序来介绍:自动换行且带下划线的长标题,长标题和其他元素构成的信息表,由信息表和其他要素构成的封面。
自动换行且带下划线的长标题
其思路如前所述,利用tikz的node输出文本,node中是parbox实现对文本的自动断行,然后根据node的信息和行距绘制下划线,同时利用node的位置对齐该标题所对应的标签。
比如:
\documentclass[twoside]{article}
\usepackage{ctex}
\usepackage{CJKfntef}
\usepackage{geometry}
\geometry{a4paper,top=27mm,bottom=25.4mm,left=30mm,right=30mm}
\geometry{headheight=7.7mm,headsep=4.3mm,footskip=7.9mm}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\ExplSyntaxOn
%获取node内部的文本行数存入counter:linesinnode中
\newdimen\mydimxs
\newdimen\mydimxe
\newdimen\myheight
\newcounter{linesinnode}
\NewDocumentCommand {\getnodedimen} {m} {
\pgfextracty{\mydimxs}{\pgfpointanchor{#1}{south~west}}
\pgfextracty{\mydimxe}{\pgfpointanchor{#1}{north~east}}
\pgfmathsetlength{\myheight}{\mydimxe-\mydimxs+\baselineskip-0.9\ccwd}%\the\myheight
\setcounter{linesinnode}{\numexpr\myheight/\baselineskip\relax}
}
%记录表格标签的宽度、表格中node的基点位置
\newlength\rowlabelwidth
\setlength\rowlabelwidth{69pt} %指定宽度,宽度小一点可以压缩全角冒号标点所占的空间
\def\lastrowbasepoint{\pgfpointadd{\pgfpointanchor{current~page}
{north~west}}{\pgfpoint{6.55cm}{-14cm}}}%\pgfpointorigin
\tikzstyle{multirow}=[inner~sep=0pt,minimum~width=295pt,
anchor=north~west,font=\fangsong]%draw=blue,
\tikzstyle{singlelabel}=[inner~sep=0pt,minimum~width=69pt,minimum~height=\baselineskip, text~height=\baselineskip-0.5mm,text~depth=0.1\baselineskip,anchor=north~east]
\tikzstyle{lineunderrow}=[black]
%绘制带多行文本的行
\NewDocumentCommand \nodeonepairmultirow {m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node [multirow] (noderightX) at (BasePoint) {\parbox{280pt}{\centering #2}};
\getnodedimen{noderightX}
\foreach \x in {1,...,\thelinesinnode} {
\draw [lineunderrow]
($(noderightX.south~east)+(0,\numexpr\x-1\relax\baselineskip-0.5mm)$) -- ($(noderightX.south~west)+(0,\numexpr\x-1\relax\baselineskip-0.5mm)$);
}
\node[inner~sep=0pt,anchor=north~east,minimum~width=69pt] (nodeleft) at (noderightX.north~west){\makebox[\rowlabelwidth][s]{#1}};
\def\lastrowbasepoint{\pgfpointanchor{noderightX}{south~west}}
}
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\linespread{1.68}\zihao{3}\bfseries\heiti
\nodeonepairmultirow{论文题目:}
{这是一个很长的很长的学位论文题目这是一个很长的学位论文XXX大学开题报告\LaTeX{} 模板}
\end{tikzpicture}
\end{document}
注意其中的关键是要利用\pgfextracty
获取node的上下y坐标从而确定node 的高度,进而确定其内文本的行数,从而绘制对应数量的下划线。
其结果为:
长标题和其他元素构成的信息表
类似的,长标题可以绘制,短标题的信息也可以采用类似的方式绘制,而且利用node之间的相互位置关系,可以让这些信息之间具有更精确的定位。
比如:
\documentclass[twoside]{article}
\usepackage{ctex}
\usepackage{CJKfntef}
\usepackage{geometry}
\geometry{a4paper,top=27mm,bottom=25.4mm,left=30mm,right=30mm}
\geometry{headheight=7.7mm,headsep=4.3mm,footskip=7.9mm}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\ExplSyntaxOn
%获取node内部的文本行数存入counter:linesinnode中
\newdimen\mydimxs
\newdimen\mydimxe
\newdimen\myheight
\newcounter{linesinnode}
\NewDocumentCommand {\getnodedimen} {m} {
\pgfextracty{\mydimxs}{\pgfpointanchor{#1}{south~west}}
\pgfextracty{\mydimxe}{\pgfpointanchor{#1}{north~east}}
\pgfmathsetlength{\myheight}{\mydimxe-\mydimxs+\baselineskip-0.9\ccwd}%\the\myheight
\setcounter{linesinnode}{\numexpr\myheight/\baselineskip\relax}
}
%记录表格标签的宽度、表格中node的基点位置
\newlength\rowlabelwidth
\setlength\rowlabelwidth{69pt} %指定宽度,宽度小一点可以压缩全角冒号标点所占的空间
\def\lastrowbasepoint{\pgfpointadd{\pgfpointanchor{current~page}
{north~west}}{\pgfpoint{6.55cm}{-14cm}}}%\pgfpointorigin
\tikzstyle{multirow}=[inner~sep=0pt,minimum~width=295pt,
anchor=north~west,font=\fangsong]%draw=blue,
\tikzstyle{singlelabel}=[inner~sep=0pt,minimum~width=69pt,minimum~height=\baselineskip, text~height=\baselineskip-0.5mm,text~depth=0.1\baselineskip,anchor=north~east]
\tikzstyle{lineunderrow}=[red]
\tikzstyle{singlerow}=[inner~sep=0pt,minimum~width=295pt,minimum~height=\baselineskip, text~height=\baselineskip-0.5mm,text~depth=0.1\baselineskip,
font=\fangsong,anchor=north~west]
\tikzstyle{singleshortrow}=[inner~sep=0pt,minimum~width=112pt,
minimum~height=\baselineskip,text~height=\baselineskip-0.5mm,
text~depth=0.1\baselineskip,font=\fangsong,anchor=north~west]
%绘制带多行文本的行
\NewDocumentCommand \nodeonepairmultirow {m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node [multirow] (noderightX) at (BasePoint) {\parbox{280pt}{\centering #2}};
\getnodedimen{noderightX}
\foreach \x in {1,...,\thelinesinnode} {
\draw [lineunderrow]
($(noderightX.south~east)+(0,\numexpr\x-1\relax\baselineskip-0.5mm)$) -- ($(noderightX.south~west)+(0,\numexpr\x-1\relax\baselineskip-0.5mm)$);
}
\node[inner~sep=0pt,anchor=north~east,minimum~width=69pt] (nodeleft) at (noderightX.north~west){\makebox[\rowlabelwidth][s]{#1}};
\def\lastrowbasepoint{\pgfpointanchor{noderightX}{south~west}}
}
%绘制带单行文本的行
\NewDocumentCommand \nodeonepairsinglerow {m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node[singlerow] (noderight) at (BasePoint)
{\parbox{280pt}{\centering #2}};
\draw [lineunderrow] ($(noderight.south~east)+(0,-0.5mm)$)
-- ($(noderight.south~west)+(0,-0.5mm)$);
\node[singlelabel] (nodeleft) at
(noderight.north~west){\makebox[\rowlabelwidth][s]{#1}};
\def\lastrowbasepoint{\pgfpointanchor{noderight}{south~west}}
}
%绘制带单行文本的行,但有两列
\NewDocumentCommand \nodedblpairsinglerow {m m m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node[singleshortrow] (noderight) at (BasePoint)
{\parbox{105pt}{\centering #2}};
\draw [lineunderrow] ($(noderight.south~east)+(0,-0.5mm)$) --
($(noderight.south~west)+(0,-0.5mm)$);
\node[singlelabel] (nodeleft) at
(noderight.north~west){\makebox[\rowlabelwidth][s]{#1}};
\node[singlelabel,anchor=north~west] (noderighta)
at (noderight.north~east){\makebox[\rowlabelwidth][s]{#3}};
\node[singleshortrow] (noderightb) at (noderighta.north~east)
{\parbox{105pt}{\centering #4}};
\draw [lineunderrow] ($(noderightb.south~east)+(0,-0.5mm)$)
-- ($(noderightb.south~west)+(0,-0.5mm)$);
\def\lastrowbasepoint{\pgfpointanchor{noderight}{south~west}}
}
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\linespread{1.68}\zihao{3}\bfseries\heiti
\nodeonepairmultirow{论文题目:}
{这是一个很长的很长的学位论文题目这是一个很长的学位论文XXX大学开题报告\LaTeX{} 模板}
\nodedblpairsinglerow{学\hspace{2em}号:}{160590XX}{姓\hspace{2em}名:}{谭同学}
\nodeonepairsinglerow{一级学科:}{控制科学与工程}
\nodeonepairsinglerow{研究方向:}{图像处理}
\nodedblpairsinglerow{指导教师:}{张老师}{职\hspace{2em}称:}{教~~授}
\nodeonepairsinglerow{学\hspace{2em}院:}{信息系统与管理学院}
\nodeonepairsinglerow{开题时间:}{2017 年 03 月 01 日}
\end{tikzpicture}
\end{document}
这里的关键则是,不同的行之间的相互定位关系。我们使用了pgfpoint和pgfcoordinate之间的转化。
在绘制前一行后,利用pgfpoint记录后一行的定位点\lastrowbasepoint
。绘制后一行时,将pgfpoint转化为pgfcoordinate来定位本行的node位置。
注意:使用\pgfpointanchor
命令从节点的各个位置上取出pgfpoint,利用\pgfcoordinate
从pgfpoint中取出坐标点。
其结果为:
由信息表和其他要素构成的封面
封面除了论文相关的信息表外,还有与机构相关的其他信息,为便于定位,而避免利用vspace等来不断调试定位,直接利用绘图定位封面内的所有要素。
注意:tikz绘图时利用精确定位,需要带选项 remember~picture,overlay。
比如:
\documentclass[twoside]{article}
\usepackage{ctex}
\usepackage{CJKfntef}
\usepackage{geometry}
\geometry{a4paper,top=27mm,bottom=25.4mm,left=30mm,right=30mm}
\geometry{headheight=7.7mm,headsep=4.3mm,footskip=7.9mm}
\renewcommand{\baselinestretch}{1.4} % line space setting
\usepackage{enumitem}
\AddEnumerateCounter{\chinese}{\chinese}{}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\usepackage{ctable}
\ExplSyntaxOn
%获取node内部的文本行数存入counter:linesinnode中
\newdimen\mydimxs
\newdimen\mydimxe
\newdimen\myheight
\newcounter{linesinnode}
\NewDocumentCommand {\getnodedimen} {m} {
\pgfextracty{\mydimxs}{\pgfpointanchor{#1}{south~west}}
\pgfextracty{\mydimxe}{\pgfpointanchor{#1}{north~east}}
\pgfmathsetlength{\myheight}{\mydimxe-\mydimxs+\baselineskip-0.9\ccwd}%\the\myheight
\setcounter{linesinnode}{\numexpr\myheight/\baselineskip\relax}
}
%记录表格标签的宽度、表格中node的基点位置
\newlength\rowlabelwidth
\setlength\rowlabelwidth{69pt} %指定宽度,宽度小一点可以压缩全角冒号标点所占的空间
\def\lastrowbasepoint{\pgfpointadd{\pgfpointanchor{current~page}
{north~west}}{\pgfpoint{6.55cm}{-14cm}}}%\pgfpointorigin
\tikzstyle{multirow}=[inner~sep=0pt,minimum~width=295pt,
anchor=north~west,font=\fangsong]%draw=blue,
\tikzstyle{singlerow}=[inner~sep=0pt,minimum~width=295pt,minimum~height=\baselineskip, text~height=\baselineskip-0.5mm,text~depth=0.1\baselineskip,
font=\fangsong,anchor=north~west]
\tikzstyle{singleshortrow}=[inner~sep=0pt,minimum~width=112pt,
minimum~height=\baselineskip,text~height=\baselineskip-0.5mm,
text~depth=0.1\baselineskip,font=\fangsong,anchor=north~west]
\tikzstyle{singlelabel}=[inner~sep=0pt,minimum~width=69pt,minimum~height=\baselineskip, text~height=\baselineskip-0.5mm,text~depth=0.1\baselineskip,anchor=north~east]
\tikzstyle{lineunderrow}=[black]
%绘制带多行文本的行
\NewDocumentCommand \nodeonepairmultirow {m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node [multirow] (noderightX) at (BasePoint) {\parbox{280pt}{\centering #2}};
\getnodedimen{noderightX}
\foreach \x in {1,...,\thelinesinnode} {
\draw [lineunderrow]
($(noderightX.south~east)+(0,\numexpr\x-1\relax\baselineskip-0.5mm)$) -- ($(noderightX.south~west)+(0,\numexpr\x-1\relax\baselineskip-0.5mm)$);
}
\node[inner~sep=0pt,anchor=north~east,minimum~width=69pt] (nodeleft) at (noderightX.north~west){\makebox[\rowlabelwidth][s]{#1}};
\def\lastrowbasepoint{\pgfpointanchor{noderightX}{south~west}}
}
%绘制带单行文本的行
\NewDocumentCommand \nodeonepairsinglerow {m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node[singlerow] (noderight) at (BasePoint)
{\parbox{280pt}{\centering #2}};
\draw [lineunderrow] ($(noderight.south~east)+(0,-0.5mm)$)
-- ($(noderight.south~west)+(0,-0.5mm)$);
\node[singlelabel] (nodeleft) at
(noderight.north~west){\makebox[\rowlabelwidth][s]{#1}};
\def\lastrowbasepoint{\pgfpointanchor{noderight}{south~west}}
}
%绘制带单行文本的行,但有两列
\NewDocumentCommand \nodedblpairsinglerow {m m m m} {
\pgfcoordinate{BasePoint}{\lastrowbasepoint}
\node[singleshortrow] (noderight) at (BasePoint)
{\parbox{105pt}{\centering #2}};
\draw [lineunderrow] ($(noderight.south~east)+(0,-0.5mm)$) --
($(noderight.south~west)+(0,-0.5mm)$);
\node[singlelabel] (nodeleft) at
(noderight.north~west){\makebox[\rowlabelwidth][s]{#1}};
\node[singlelabel,anchor=north~west] (noderighta)
at (noderight.north~east){\makebox[\rowlabelwidth][s]{#3}};
\node[singleshortrow] (noderightb) at (noderighta.north~east)
{\parbox{105pt}{\centering #4}};
\draw [lineunderrow] ($(noderightb.south~east)+(0,-0.5mm)$)
-- ($(noderightb.south~west)+(0,-0.5mm)$);
\def\lastrowbasepoint{\pgfpointanchor{noderight}{south~west}}
}
%定义两套Key-value设置,一套是NUDTlabelset,一套是NUDTvalueset
%前者用于在模板中定义,后者则作为用户接口
\NewDocumentCommand\definekey{mm}{\keys_define:nn { #1 }{#2 .tl_set:c = { l_#1_#2_tl }}}
\NewDocumentCommand\NUDTlabelset{m}{\keys_set:nn {NUDTlabel} { #1 }}
\NewDocumentCommand\NUDTvalueset{m}{\keys_set:nn {NUDTvalue} { #1 }}
\clist_const:Nn \l_NUDT_keys {author,title,author,title,schoollogo,schooltext,
proposaltype,classification,proposalnumber,authorid,major,field,advisor,
advisortitle,institute,date,formdate,mark}%在clist中定义key
\clist_map_inline:Nn \l_NUDT_keys{\definekey{NUDTlabel}{#1}}
\clist_map_inline:Nn \l_NUDT_keys{\definekey{NUDTvalue}{#1}}
%设置标签信息
\NUDTlabelset
{ author={姓\hspace{2em}名:},
title={论文题目:},
schoollogo={},
schooltext={},
proposaltype={},
classification={密级:},
proposalnumber={编号:},
authorid={学\hspace{2em}号:},
major={一级学科:},
field={研究方向:},
advisor={指导教师:},
advisortitle={职\hspace{2em}称:},
institute={学\hspace{2em}院:},
date={开题时间:},
formdate={二〇一八年一月},% 制表月份
mark={}, %XXX大学研究生院制
}
%封面的命令
%注意:其中不同元素的定位根据模板的要求来设置
\NewDocumentCommand\makecover{}{
\newpage\thispagestyle{empty}\noindent
\begin{tikzpicture}[remember~picture,overlay]
\begin{scope}
\linespread{1.4}
\node[anchor=center] at ($(current~page.north~west)+(5.45cm,-5.35cm)$)
{\l_NUDTvalue_schoollogo_tl};
\node[font=\zihao{4}\mdseries\heiti] at
($(current~page.north~east)+(-5.7cm,-5.5cm)$)
{\begin{tabular}{c c}
\l_NUDTlabel_classification_tl & {\fangsong\l_NUDTvalue_classification_tl} \\
\l_NUDTlabel_proposalnumber_tl & {\fangsong\l_NUDTvalue_proposalnumber_tl} \\
\end{tabular}};
\end{scope}
\begin{scope}
\node[] at ($(current~page.north~west)+(10.5cm,-8.3cm)$)
{\bfseries\l_NUDTvalue_schooltext_tl};
\node[] at ($(current~page.north~west)+(10.5cm,-11.3cm)$)
{\mdseries\fontsize{28}{12}\selectfont
\begin{tabular}{c}
\l_NUDTvalue_proposaltype_tl \\
开题报告\\
\end{tabular}};
\linespread{1.68}\zihao{3}\bfseries\heiti
\nodeonepairmultirow{\l_NUDTlabel_title_tl}{\l_NUDTvalue_title_tl}
\nodedblpairsinglerow{\l_NUDTlabel_authorid_tl}
{\l_NUDTvalue_authorid_tl}{\l_NUDTlabel_author_tl}
{\l_NUDTvalue_author_tl}
\nodeonepairsinglerow{\l_NUDTlabel_major_tl}
{\l_NUDTvalue_major_tl}
\nodeonepairsinglerow{\l_NUDTlabel_field_tl}
{\l_NUDTvalue_field_tl}
\nodedblpairsinglerow{\l_NUDTlabel_advisor_tl}
{\l_NUDTvalue_advisor_tl}{\l_NUDTlabel_advisortitle_tl}
{\l_NUDTvalue_advisortitle_tl}
\nodeonepairsinglerow{\l_NUDTlabel_institute_tl}
{\l_NUDTvalue_institute_tl}
\nodeonepairsinglerow{\l_NUDTlabel_date_tl}{\l_NUDTvalue_date_tl}
\node[] at ($(current~page.north~west)+(10.5cm,-25.5cm)$)
{\begin{tabular}{p{400pt}<{\centering}}
{\mdseries\l_NUDTvalue_mark_tl} \\
{\mdseries\l_NUDTlabel_formdate_tl}
\end{tabular}};
\end{scope}
\end{tikzpicture}
\clearpage
%%%% 说明页
\thispagestyle{empty}
\begin{center}
{\heiti \zihao{2} 说 \qquad 明}
\end{center}
{\songti\zihao{-4}\SetEnumitemKey{noenumsep}{labelsep=0pt,topsep=0pt,partopsep=0pt,itemsep=0pt,parsep=0pt}
\begin{enumerate}[label={\chinese*、},noenumsep]
\item 开题报告应按下述要求打印后装订成册:
\begin{enumerate}[label={\arabic*.},noenumsep]
\item 使用A4白纸,双面打印;
\item 封面中填写内容使用小3号仿宋字体;
\item 表中填写内容使用5号楷体字体。
\end{enumerate}
\item 封面中的编号由学院填写,采用八位数编码,前四位为审批日期,精确到年月即可,第五位为院别,后三位为审批流水号(按年)。如15016100,为6院15年审批的第100位开题申请者,审批时间为15年1月份。院别代码与编制序列一致,海洋科学与工程研究院代码为0。
\item 开题报告表中学员填写的内容包括学位论文选题的立论依据、文献综述、研究内容、研究条件、学位论文工作计划、主要参考文献等,指导教师认可学员开题报告内容后,对学员学位论文选题价值、对国内/外研究现状的了解情况、研究内容、研究方案等方面予以评价。
\item 开题报告评议小组一般由3-5名具有正高级专业技术职务的专家(包括导师)组成,其中一名为跨一级学科的专家。
\item 若开题报告获得通过,应根据评议小组意见对开题报告进行修改,并在开题报告会后两周内,将评议表和修订后开题报告纸质版原件交学院备案;若开题报告未获得通过,则填报延期开题申请,由原开题报告评议小组重新组织开题报告会。
\end{enumerate}}
}
\ExplSyntaxOff
\begin{document}
%设置论文信息
\NUDTvalueset
{
author={谭同学}, % 作者
title={这是一个很长的很长的学位论文题目这是一个很长的学位论文XXX大学开题报告\LaTeX{} 模板}, % 论文标题
schoollogo={\fbox{\parbox[c][2.7cm][c]{2.8cm}{\centering 某某大学logo}}},%大学logo
schooltext={\zihao{-1}\heiti\makebox[5cm][s]{某科技大学}},%大学名
proposaltype={\CJKunderline{博士}研究生学位论文}, % 研究生类别:硕士,博士需下划线
classification={公开}, % 密级:公开,秘密,机密或者绝密
proposalnumber={\underline{\makebox[1cm][c]{XXX}}}, % 编号:默认是下划线
authorid={160590xx}, % 学号
major={控制科学与工程}, % 一级学科
field={图像处理}, % 研究方向
advisor={张老师}, % 导师
advisortitle={教~~~~授}, % 职称
institute={信息系统与管理学院}, % 学院
date={2017~年~03~月~01日}, % 开题日期
mark={某科技大学研究生院制}, % 制表单位信息
}
%绘制封面
\makecover
\end{document}
注意:其中为了方便输入信息同时减少代码,我们利用了key-value的方式来实现。
其结果为:
小结
本文为一些学位论文封面设置提供了一种完全基于绘图的实现,其中实现了自动换行的带下滑线的长文本,并利用tikz的坐标定位得到精确的封面元素布局。