我正在尝试使用 TikZ 制作更精美的框架。我使用了一个聪明的\tikzmark
方法安德鲁·史黛西写道将节点放在环境主体的左上角和右下角。
然后我用这些节点来绘制时髦的装饰。我确信我正在重新发明轮子,但我正在学习,所以一切都很好。我知道我想做的事情是可能的,因为mdframed
两者listings
都能做到这一点,但它们的代码对我来说很难阅读,也不清楚相关部分是什么……
现在,这可以正常工作,直到环境跨越一页。然后节点位于不同的页面上,当环境的结束代码来绘制装饰时,它找不到左上角的节点(因为它已在最后一页上发货)。
因此,我希望针对页面环境中断的情况设置不同的行为。当段落像这样中断时,最简单的测试方法是什么?
答案1
您可以将和模块zref
一起使用(例如加载和包),并在段落开头的和段落结尾处添加一个。如果您使用环境,只需在和处放置一个。然后您可以在环境末尾检查两者的绝对页码是否相同。为此,您可以使用:abspos
user
zref-abspos
zref-user
\zlabel{labelname}
\tikzmark
begin
end
\ifnum\zref@extract{<begin-label>}{abspage}=\zref@extract{<end-label>}{abspage}\relax
<same page>
\else
<different page>
\fi
(注意:也许\zref@extractdefault
更好,因为您可以提供在标签尚未设置时用于第一次运行的默认值。)
另请参阅我的回答如何在文本下方而不是上方绘制文本锚定的 tikz 线?我做了一些非常相似的事情!
我现在想出了一个解决方案。如果结束宏不在同一页,它会在开始宏中绘制第一半边框。此外,环境跨越两页以上的情况(例如从第 1 页开始并结束于第 3 页)由额外的代码覆盖。
\documentclass[twoside]{book}
\usepackage{zref-abspage}
\usepackage{zref-user}
\usepackage{tikz}
\usepackage{atbegshi}
\usetikzlibrary{calc}
\makeatletter
\newcommand{\currentsidemargin}{%
\ifodd\zref@extract{textarea-\thetextarea}{abspage}%
\oddsidemargin%
\else%
\evensidemargin%
\fi%
}
\newcounter{textarea}
\newcommand{\settextarea}{%
\stepcounter{textarea}%
\zlabel{textarea-\thetextarea}%
\begin{tikzpicture}[overlay,remember picture]
% Helper nodes
\path (current page.north west) ++(\hoffset, -\voffset)
node[anchor=north west, shape=rectangle, inner sep=0, minimum width=\paperwidth, minimum height=\paperheight]
(pagearea) {};
\path (pagearea.north west) ++(1in+\currentsidemargin,-1in-\topmargin-\headheight-\headsep)
node[anchor=north west, shape=rectangle, inner sep=0, minimum width=\textwidth, minimum height=\textheight]
(textarea) {};
\end{tikzpicture}%
}
\tikzset{tikzborder/.style={line width=1mm,red,double=blue}}
\newcounter{tikzborder}
\newcounter{tikzborderpages}
\newenvironment{tikzborder}[1][]{%
\medskip\par
% Allow user to overwrite the used style locally
\ifx&\else
\tikzset{tikzborder/.style={#1}}%
\fi
\settextarea
\stepcounter{tikzborder}%
\tikz[overlay,remember picture] \coordinate (tikzborder-\thetikzborder);% Modified \tikzmark macro
\zlabel{tikzborder-begin-\thetikzborder}%
% Test if end-label is at the same page and draw first half of border if not
\ifnum\zref@extract{tikzborder-begin-\thetikzborder}{abspage}=\zref@extract{tikzborder-end-\thetikzborder}{abspage} \else
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
let \p0 = (textarea.north west), \p1 = (tikzborder-\thetikzborder), \p2 = (textarea.south east) in
(\x0-\fboxsep-.5\pgflinewidth,\y2-\fboxsep-.5\pgflinewidth)
|-
(\x2+\fboxsep+.5\pgflinewidth,\ht\strutbox+\fboxsep+.5\pgflinewidth)
--
(\x2+\fboxsep+.5\pgflinewidth,\y2-\fboxsep-.5\pgflinewidth)
;
\end{tikzpicture}%
% If it spreads over more than two pages:
\setcounter{tikzborderpages}{\numexpr-\zref@extract{tikzborder-begin-\thetikzborder}{abspage}+\zref@extract{tikzborder-end-\thetikzborder}{abspage}}
\ifnum\value{tikzborderpages}>1
\AtBeginShipoutNext{\tikzborderpage}%
\fi
\fi
}{%
\zlabel{tikzborder-end-\thetikzborder}%
% Test if begin-label is at the same page and draw while border if so
\ifnum\zref@extract{tikzborder-begin-\thetikzborder}{abspage}=\zref@extract{tikzborder-end-\thetikzborder}{abspage}
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
let \p0 = (textarea.north west), \p1 = (tikzborder-\thetikzborder), \p2 = (textarea.south east) in
(\x0-\fboxsep-.5\pgflinewidth,\y1+\ht\strutbox+\fboxsep+.5\pgflinewidth)
|-
(\x2+\fboxsep+.5\pgflinewidth,-\dp\strutbox-\fboxsep-.5\pgflinewidth)
|-
(\x0-\fboxsep-.5\pgflinewidth,\y1+\ht\strutbox+\fboxsep+.5\pgflinewidth)
-- cycle
;
\end{tikzpicture}%
% Otherwise draw second half of border
\else
\settextarea
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
let \p0 = (textarea.north west), \p1 = (tikzborder-\thetikzborder), \p2 = (textarea.south east) in
(\x0-\fboxsep-.5\pgflinewidth,\y0+\fboxsep+.5\pgflinewidth)
|-
(\x2+\fboxsep+.5\pgflinewidth,-\dp\strutbox-\fboxsep-.5\pgflinewidth)
--
(\x2+\fboxsep+.5\pgflinewidth,\y0+\fboxsep+.5\pgflinewidth)
;
\end{tikzpicture}%
\fi
\par\medskip
}
\newcommand{\tikzborderpage}{%
\settextarea
\begin{tikzpicture}[overlay,remember picture]
\draw [tikzborder]
([shift={(-\fboxsep-.5\pgflinewidth, \fboxsep+.5\pgflinewidth)}]textarea.north west)
--
([shift={(-\fboxsep-.5\pgflinewidth,-\fboxsep-.5\pgflinewidth)}]textarea.south west)
;
\draw [tikzborder]
([shift={( \fboxsep+.5\pgflinewidth, \fboxsep+.5\pgflinewidth)}]textarea.north east)
--
([shift={( \fboxsep+.5\pgflinewidth,-\fboxsep-.5\pgflinewidth)}]textarea.south east)
;
\end{tikzpicture}%
\addtocounter{tikzborderpages}{-1}%
\ifnum\value{tikzborderpages}>1
\AtBeginShipoutNext{\tikzborderpage}%
\fi
\vspace{-\baselineskip}% Compensate for the generated extra line at begin of the page. No idea why exactly this happens. Also \baselineskip seems not to be 100% right.
}
\makeatother
\usepackage{lipsum}
\newcommand\xlipsum[1][]{{\let\par\relax\lipsum*[#1]}}
\begin{document}
\begin{tikzborder}
\xlipsum[1]
\end{tikzborder}
\lipsum[2-4]
\begin{tikzborder}
\xlipsum[1]
\end{tikzborder}
\lipsum[2-4]
\begin{tikzborder}
\xlipsum[1-9]
\end{tikzborder}
\lipsum[2-4]
\begin{tikzborder}
\xlipsum[1-20]
\end{tikzborder}
\end{document}
(由于分辨率低等原因,画面中框架无法完全正确显示。
点击放大)
答案2
我在这里的评论中写了一个mdframed
例子tikzsetting
需要mdframded v0.7a
\documentclass[parskip=half-]{scrartcl}
\usepackage[%
style=1,%
splitbottomskip=0.8cm,splittopskip=0cm,
innerrightmargin=1cm,innertopmargin=1cm,%
innerlinewidth=2pt,outerlinewidth=2pt,middlelinewidth=10pt,
backgroundcolor=red,%
roundcorner=25pt,
%leftline=false,
% rightline=false,
% %topline=false,
% bottomline=false
]{mdframed}
%example 1
\mdfsetup{%
tikzsetting={draw=yellow,line width=3pt,dashed,dash pattern= on 10pt off 3pt}}
%%example 2
%\mdfsetup{%
%linecolor=blue,middlelinecolor=gray,tikzsetting={line width=2pt,double=blue,draw=red,double distance=3pt,dashed}}
%%example 3
%\mdfsetup{%
%linecolor=blue,middlelinecolor=gray,tikzsetting={dashed,draw=red}}
\usepackage{lipsum}
\begin{document}
\begin{mdframed}
\lipsum[1]
\end{mdframed}
~
%
\begin{mdframed}
\lipsum[1-8]
\end{mdframed}
\end{document}
我希望它能有所帮助。顺便说一句:我认为我以一种简单的方式编写了代码;-)——我是包编写的初学者
示例 1:
示例 2:
示例 3: