我正在尝试制作一个学术日历包。我知道市面上有很多这样的包,我浏览过很多,但似乎找不到我喜欢的。由于我(通常)对 LaTeX 相当熟练,所以我想我可以自己写一个。这导致了一个有点烦人的问题,应该很容易解决,但我似乎无法解决。
相关命令:
目前,日历生成得很好,除了在日历上填充日期时出现一个小问题。我将在底部包含所有 .sty 文件,但它很长而且仍然很粗糙(仍在写草稿),所以我将在这里提取重要部分;
日历是(故意)预先填充的,每一天都有自己的命令来填充其内容,然后我定义了一个“DayContent”命令来更新相关日子的命令以填充所需的内容(理想情况下,我实际上会通过构建一个条件来填充日历,该条件检查是否已为该天定义了命令,如果没有,它将使用默认的空白日期图块填充它)。命令如下:
\newcommand{\dayContent}[3]{% This puts content on the given day of the calendar.
% Syntax: \dayContent{Month}{Day}{Agenda}
% Renews the content of the command for day "Day" and month "Month" to display "Agenda"
\expandafter\def\csname calendarDay#2Month#1\endcsname{%
{\raggedleft #2}% We want dates in the top right corner
\scriptsize #3% Calendars are small, write inside it small.
\refstepcounter{dayVal}
}%
}
在我生成了必要的命令并确定要显示的月份(全部在下面的 termCalendar.sty 代码中)之后,我使用 printCalendar 命令打印所有内容;
\newcommand{\printCalendar}{% The user command to make the calendar
\monthLabel
\setcounter{monthMax}{\arabic{MonthOne}}% Start with the first Month
\stepcounter{curMonthNum}% Step counter to get the right number of days
\begin{center}
{\large \bfseries \curMonthText}% Print month's name at head
\end{center}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|X|r|}% Print Month's Calendar Heading
\hline \textbf{Sun}& \textbf{Monday}& \textbf{Tuesday}& \textbf{Wednesday}& \textbf{Thursday}& \textbf{Friday}& \textbf{Sat}\\ \hline\hline
\genFirstWeek% This will generate the first week, we need to be careful about semesters where the month ends in the same week the semester starts.
\genLastWeek\\ \hline% In this case we only need a first and last week Otherwise there would be as many \genFullWeek commands between the genFirst and genLast as we need.
\end{tabularx}
\stepcounter{monthVal}
\genFirstWeek
,\genLastWeek
命令基本上只是包装器,用于检查一些条件并根据月份第一天和月份最后一天所在的星期几来填充周数。
问题:
一切都进行得很顺利,但如果我想在给定的日历日有多行,它们就会缩进,而且无论我做什么似乎都无法消除缩进。
([ ] 中的以下文本不再准确,请参阅下面的编辑;不再使用嵌套的表格环境,因为换行符不会中断 tabularx)[我需要将换行符包含在某个内容中,以便换行符不会渗透到 tabularx 环境中并产生错误。目前,我正尝试将内容包装在表格环境中(从而将表格环境嵌套在 tabularx 环境中),这……有点有效。]
例如,我在开学第一天使用以下代码:
\dayContent{8}{22}{
First Day Of Class\\
\textbf{Intro \& Syllabus}}
问题是,它有一个小的缩进,无论如何我都无法摆脱它。([ ] 中不再相关的文本)[您可能会看到@{}
上面的内容,这是我尝试从中提取的解决方案这里,但它似乎不起作用(我完全不明白......它需要一个吗\makeatletter
?因为答案表明不需要,但无论如何它都不起作用)。无论如何,嵌套表格环境是因为]我无法弄清楚如何让 minipage 以任何有意义的方式工作......理想情况下,我希望每个日历日单元格都是它自己的 minipage,但我不知道如何做到这一点。
(\raggedleft
问题已由 David Carlisle 解决,请参阅下面的评论)此外,还有一个不太重要但有点令人厌烦的问题;\raggedleft
上面的命令似乎没有像我想象的那样将日历的日期数字显示在右上角。有什么建议可以解决这个问题吗?知道为什么它不起作用吗?
要清楚的是,我可能会对此进行破解并获得一些可行的方法,但我实际上更好奇为什么这个缩进会存在,即使在添加了诸如\noindent
和甚至之类的东西之后\hspace{(negative length)}
。除了它在某个地方保存一些“长度”值并以某种方式使用它们之外,我真的不知道缩进在基本/原始级别上是如何工作的……但机制让我困惑。如果有任何关于此内容的参考资料,我会真的除了任何答案之外,还感谢指向它们的链接。
谢谢!
编辑 正如 David Carlisle 在下面的评论中指出的那样,事实证明 tabularx 会生成 p 列,因此支持换行符。幸运的是,这意味着我可以放弃嵌套的表格环境。不幸的是,我仍然得到完全相同的行为,即日历日单元格内每行开头的小缩进。
正如承诺的那样;完整的代码:
%
% Tex Type: Latex2e
\NeedsTeXFormat{LaTeX2e}
% Provides Package:
\ProvidesClass{termCalendar}
% Required Packages for this style file
\RequirePackage{tabularx}
\RequirePackage{ifthenx}
\RequirePackage{forloop}
\RequirePackage[margin=1in]{geometry}
% New Counters
\newcounter{term}% Easier to track terms by a numeric value and have a detection for people sucking at writing terms.
\setcounter{term}{0}
\newcounter{countMonth}
\newcounter{MonthOne}
\newcounter{MonthTwo}
\newcounter{MonthThree}
\newcounter{MonthFour}
\newcounter{MonthFive}
\setcounter{MonthFive}{0}
\newcounter{Iteration1}% Generic Iteration Variable
\newcounter{dayVal}% Counter for the day's date.
\setcounter{dayVal}{1}
\newcounter{monthVal}% Current month number
\newcounter{monthMax}% Current month's total days
\newcounter{firstDay}% First day of the month's location. 1=Sunday, 2=Monday, etc.
\setcounter{firstDay}{1}
\newcounter{curMonthNum}% Cuurrent Month number.
\newcounter{firstOfMonth}
\newcounter{endWeek}
\newcommand{\curMonthText}{}
\newcounter{tmp}
%New Commands:
\newcommand{\term}[1]{
\ifthenelse{\equal{#1}{Fall}}{\setcounter{term}{1}}% Set "Fall" to value 1
{
\ifthenelse{\equal{#1}{fall}}{\setcounter{term}{1}}% Set "fall" to value 1
{
\ifthenelse{\equal{#1}{Spring}}{\setcounter{term}{2}}% Set "Spring" to value 2
{
\ifthenelse{\equal{#1}{spring}}{\setcounter{term}{2}}% Set "Spring" to value 2
{
\ifthenelse{\equal{#1}{SummerC}}{\setcounter{term}{3}}% Set "SummerC" to value 3
{
\ifthenelse{\equal{#1}{summerC}}{\setcounter{term}{3}}% Set "summerC" to value 3
{
\ifthenelse{\equal{#1}{Summerc}}{\setcounter{term}{3}}% Set "Summerc" to value 3
{
\ifthenelse{\equal{#1}{summerc}}{\setcounter{term}{3}}% Set "summerc" to value 3
{
\ifthenelse{\equal{#1}{SummerA}}{\setcounter{term}{4}}% Set "SummerA" to value 4
{
\ifthenelse{\equal{#1}{summerA}}{\setcounter{term}{4}}% Set "summerA" to value 4
{
\ifthenelse{\equal{#1}{Summera}}{\setcounter{term}{4}}% Set "Summera" to value 4
{
\ifthenelse{\equal{#1}{summera}}{\setcounter{term}{4}}% Set "summera" to value 4
{
\ifthenelse{\equal{#1}{SummerB}}{\setcounter{term}{5}}% Set "SummerB" to value 5
{
\ifthenelse{\equal{#1}{summerB}}{\setcounter{term}{5}}% Set "summerB" to value 5
{
\ifthenelse{\equal{#1}{Summerb}}{\setcounter{term}{5}}% Set "Summerb" to value 5
{
\ifthenelse{\equal{#1}{summerb}}{\setcounter{term}{5}}% Set "summerb" to value 5
{
\PackageError{calendar}{Unrecognized Term #1! Please enter "Fall", "Spring", "SummerC", "SummerA", or "SummerB"}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
\genDays% Populate Calendar numbers
}
\newcommand{\genDays}{
\ifthenelse{\expandafter\equal{\arabic{term}}{1}}{% If the term is 1, then it's Fall, ie August through December
\setcounter{countMonth}{5}% Term spans 5 months in total
\setcounter{curMonthNum}{8}% Term starts on month 8
\setcounter{MonthOne}{31}% First month aka August has 31 days
\genDayCommands{8}{31}
\setcounter{MonthTwo}{30}% Second Month, aka September
\genDayCommands{9}{30}
\setcounter{MonthThree}{31}% Third Month, aka October
\genDayCommands{10}{31}
\setcounter{MonthFour}{30}% Fourth Month, aka November
\genDayCommands{11}{30}
\setcounter{MonthFive}{31}% Fifth Month, aka December
\genDayCommands{12}{31}
}% End of Fall term options
{
\ifthenelse{\expandafter\equal{\arabic{term}}{2}}{% Else, if it's Spring
\setcounter{countMonth}{5}
\setcounter{curMonthNum}{1}% Term starts on month 1
\setcounter{MonthOne}{31}% First month aka January has 31 days
\genDayCommands{1}{31}
\setcounter{MonthTwo}{28}% Second Month, aka February
\genDayCommands{2}{28}
\setcounter{MonthThree}{31}% Third Month, aka March
\genDayCommands{3}{31}
\setcounter{MonthFour}{30}% Fourth Month, aka April
\genDayCommands{4}{30}
\setcounter{MonthFive}{31}% Fifth Month, aka May
\genDayCommands{5}{31}
}% End of Spring Term options
{
\ifthenelse{\expandafter\equal{\arabic{term}}{3}}{% Else, if it's SummerC
\setcounter{countMonth}{4}
\setcounter{curMonthNum}{5}% Term starts on month 5
\setcounter{MonthOne}{31}% First month aka May has 31 days
\genDayCommands{5}{31}
\setcounter{MonthTwo}{30}% Second Month, aka June
\genDayCommands{6}{30}
\setcounter{MonthThree}{31}% Third Month, aka July
\genDayCommands{7}{31}
\setcounter{MonthFour}{31}% Fourth Month, aka August
\genDayCommands{8}{31}
}% End of Spring Term options
{}% Else... not yet implemented.
}
}
}
\newcommand{\genFirstWeek}{% Generate the first week of the month
\ifthenelse{\arabic{dayVal}>\arabic{firstOfMonth}}{% First check if we are starting at the start of the month, or somewhere partway in.
%If we are starting partway through the month, it's the first month, in which case we can populate tiles all week until we hit the end of the month.
\setcounter{endWeek}{\arabic{dayVal}}
\addtocounter{endWeek}{6}% Add 6 to offset the < sign below.
\ifthenelse{\arabic{endWeek}<31}{% If there is room for a full week of dates then do so
\genFullWeek
}
{% If there is not enough room, then we are on the last week of the month, so we can use lastweek
\genLastWeek
}
}% End of the case where we are starting partway through the month. Now we may assume we are starting at the beginning.
{% Begin of case where we are starting at the first of the month.
\forloop{Iteration1}{2}{\arabic{Iteration1} < 8}{
\ifthenelse{\arabic{firstOfMonth}<\arabic{Iteration1}}{% Now, check to make sure we are populating the month, starting on the correct day of the week. If so, use a dated tile.
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
}
{% If this isn't the correct day of the week to start, then don't use a dated tile.
\formCell{} &
}
}
% We still need to add one last dated tile to the list.
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname
}% End of case where we are starting at the first of the month.
}
\newcommand{\genLastWeek}{%Generate the last week of the month
\setcounter{firstOfMonth}{1}
\stepcounter{monthMax}% Step the "last day" counter because forloops and ifthenelse don't like <= or >=
\forloop{Iteration1}{1}{\arabic{Iteration1} < 7}{% Use forloop to place a dated tile or a blank tile as necessary
\ifthenelse{\arabic{dayVal}<\arabic{monthMax}}{%
\stepcounter{firstOfMonth}
% \arabic{firstOfMonth}
% \arabic{monthMax}
% \arabic{dayVal}
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &}
{
\formCell{}&
\stepcounter{dayVal}
}
}
\addtocounter{monthMax}{-1}% Undo the step counter from above because we want to check equality now, not inequality
\ifthenelse{\arabic{dayVal}=\arabic{monthMax}}{% If it is equal, use another dated tile.
% \setcounter{firstOfMonth}{1}% This also means the last dated tile is a Saturday, so reset firstofMonth too.
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname}
{% Otherwise, use a blank tile.
\formCell{}
}
\setcounter{dayVal}{1}% Reset to finding the first day of the week.
}
%%%% Commands to populate the calendar
\newcommand{\genFullWeek}{% Generate a week in the calendar; Requires pre-set dayVal and monthVal counters.
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname &
\csname calendarDay\arabic{dayVal}Month\arabic{monthVal}\endcsname \\
\hline
}
\newcommand{\formCell}[1]{
{\raggedleft #1}% We want dates in the top right corner
}
\newcommand{\genDayCommands}[2]{% This command will generate 7 days for the month of #1.
\setcounter{monthMax}{#2}
\stepcounter{monthMax}
\forloop{Iteration1}{1}{\arabic{Iteration1} < \arabic{monthMax}}{
\expandafter\def\csname calendarDay\arabic{Iteration1}Month#1\endcsname{
\expandafter\formCell{\arabic{dayVal}}
\refstepcounter{dayVal}
}
}
}
\newcommand{\dayContent}[3]{% This puts content on the given day of the calendar.
% Syntax: \dayContent{Month}{Day}{Agenda}
% Renews the content of the command for day "Day" and month "Month" to display "Agenda"
\expandafter\def\csname calendarDay#2Month#1\endcsname{%
{\raggedleft #2}% We want dates in the top right corner
\scriptsize #3
\refstepcounter{dayVal}
}%
}
\newcommand{\monthLabel}{% Used to generate the month label at the top of the given month's calendar.
\setcounter{tmp}{\arabic{curMonthNum}}
\expandafter\ifthenelse\expandafter{\value{tmp}=1}{\renewcommand{\curMonthText}{January}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=2}{\renewcommand{\curMonthText}{February}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=3}{\renewcommand{\curMonthText}{March}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=4}{\renewcommand{\curMonthText}{April}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=5}{\renewcommand{\curMonthText}{May}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=6}{\renewcommand{\curMonthText}{June}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=7}{\renewcommand{\curMonthText}{July}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=8}{\renewcommand{\curMonthText}{August}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=9}{\renewcommand{\curMonthText}{September}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=10}{\renewcommand{\curMonthText}{October}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=11}{\renewcommand{\curMonthText}{November}}{%
\expandafter\ifthenelse\expandafter{\value{tmp}=12}{\renewcommand{\curMonthText}{December}}{%
}}}}}}}}}}}}% Closing all the above ifthenelse statements
}
\newcommand{\printCalendar}{% The user command to make the calendar
\monthLabel
\setcounter{monthMax}{\arabic{MonthOne}}
\stepcounter{curMonthNum}
\begin{center}
{\large \bfseries \curMonthText}
\end{center}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|X|r|}
\hline \textbf{Sun}& \textbf{Monday}& \textbf{Tuesday}& \textbf{Wednesday}& \textbf{Thursday}& \textbf{Friday}& \textbf{Sat}\\ \hline\hline
\genFirstWeek% This will generate the first week, we need to be careful about semesters where the month ends in the same week the semester starts.
\genLastWeek\\ \hline
\end{tabularx}
\stepcounter{monthVal}
\monthLabel
\setcounter{monthMax}{\arabic{MonthTwo}}
\stepcounter{curMonthNum}
\begin{center}
{\large \bfseries \curMonthText}
\end{center}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|X|r|}
\hline \textbf{Sun}& \textbf{Monday}& \textbf{Tuesday}& \textbf{Wednesday}& \textbf{Thursday}& \textbf{Friday}& \textbf{Sat}\\ \hline\hline
\genFirstWeek\\ \hline% This will generate the first week, we need to be careful about semesters where the month ends in the same week the semester starts.
\genFullWeek
\genFullWeek
\genFullWeek
\genFullWeek
\genLastWeek\\ \hline
\end{tabularx}
\stepcounter{monthVal}
\monthLabel
\setcounter{monthMax}{\arabic{MonthThree}}
\stepcounter{curMonthNum}
\begin{center}
{\large \bfseries \curMonthText}
\end{center}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|X|r|}
\hline \textbf{Sun}& \textbf{Monday}& \textbf{Tuesday}& \textbf{Wednesday}& \textbf{Thursday}& \textbf{Friday}& \textbf{Sat}\\ \hline\hline
\genFirstWeek\\ \hline% This will generate the first week, we need to be careful about semesters where the month ends in the same week the semester starts.
\genFullWeek
\genFullWeek
\genFullWeek
\genLastWeek\\ \hline
\end{tabularx}
\stepcounter{monthVal}
\monthLabel
\setcounter{monthMax}{\arabic{MonthFour}}
\stepcounter{curMonthNum}
\begin{center}
{\large \bfseries \curMonthText}
\end{center}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|X|r|}
\hline \textbf{Sun}& \textbf{Monday}& \textbf{Tuesday}& \textbf{Wednesday}& \textbf{Thursday}& \textbf{Friday}& \textbf{Sat}\\ \hline\hline
\genFirstWeek\\ \hline% This will generate the first week, we need to be careful about semesters where the month ends in the same week the semester starts.
\genFullWeek
\genFullWeek
\genFullWeek
\genLastWeek\\ \hline
\end{tabularx}
\stepcounter{monthVal}
\monthLabel
\setcounter{monthMax}{\arabic{MonthFour}}
\stepcounter{curMonthNum}
\begin{center}
{\large \bfseries \curMonthText}
\end{center}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|X|r|}
\hline \textbf{Sun}& \textbf{Monday}& \textbf{Tuesday}& \textbf{Wednesday}& \textbf{Thursday}& \textbf{Friday}& \textbf{Sat}\\ \hline\hline
\genFirstWeek\\ \hline% This will generate the first week, we need to be careful about semesters where the month ends in the same week the semester starts.
\genFullWeek
\genFullWeek
\end{tabularx}
\stepcounter{monthVal}
}