[Tex/LaTex] How to vertically and horizontally centre text and images in (different) table cells

graphicshorizontal alignmenttablesvertical alignment

I have a table which contains images in one column. I would like the first column to have text centred vertically and horizontally. I would like the second column to have text left justified and centred vertically. I would like the third column to contain a small image centred vertically and horizontally. The final two columns should both be left justified and aligned at the top of the cell.

The closest I have come to this is with the code below:

\documentclass[10pt]{article}

\usepackage{tikz}
\usepackage{array}
\usepackage{booktabs}

\newcommand*{\tabbox}[4][t]{%
    \vspace{#3}\parbox[#1][3.7\baselineskip]{#2}{\strut#4\strut}}


\begin{document}

\begin{tabular}{c p{2cm} c p{3cm} p{3cm}} 
        \toprule 
            \multicolumn{1}{c}{Header 1} & 
            \multicolumn{1}{c}{Header 2} & 
            \multicolumn{1}{c}{Header 3} & 
            \multicolumn{1}{c}{Header 4} & 
            \multicolumn{1}{c}{Header 5} \\ 
    \midrule
            Short Text &    
            Slightly Longer Text & 
            \tabbox[t]{3cm}{0pt}{
                \begin{tikzpicture}
                  % Draw beam and end lines
                  \draw (-1.5,-0.75) rectangle (1.5,0.75) ;
              \end{tikzpicture}
          } 
          & 
          Some text that extends onto more than one line as there's plenty of it. & 
          Some text that extends onto more than one line as there's plenty of it. Some text that extends onto more than one line as there's plenty of it. \\
            Short Text  & 
            Slightly Longer Text & 
            \tabbox[t]{3cm}{0pt}{
                \begin{tikzpicture}
                  % Draw beam and end lines
                  \draw (-1.5,-0.75) rectangle (1.5,0.75) ;
              \end{tikzpicture}
          }  & 
          Short Text & \\
            Short Text & Slightly Longer Text & Short Text & Short Text & \\
            Short Text & Slightly Longer Text & Short Text & Short Text & \\
    \bottomrule 
\end{tabular}

\end{document}

This is partly based on the advice here. The 'm' column specifier doesn't seem to have any effect on the first column. Also the picture is not automatically accommodated by the table cell vertically.

How can I achieve the effect I want?

Edit

Here is another attempt which almost works based on the advice in this question

\documentclass[10pt]{article}

\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{array}
\usepackage{booktabs}

\begin{document}

\begin{tabular}{c p{2cm} p{3cm} p{3cm} p{3cm}} 
        \toprule 
            \multicolumn{1}{c}{Header 1} & 
            \multicolumn{1}{c}{Header 2} & 
            \multicolumn{1}{c}{Header 3} & 
            \multicolumn{1}{c}{Header 4} & 
            \multicolumn{1}{c}{Header 5} \\ 
    \midrule
            Short Text &    
            Slightly Longer Text & 
                \begin{tikzpicture}[baseline={($(current bounding box.center)+(0,-0.5ex)$)}]
                  % Draw beam and end lines
                  \draw (-1.5,-0.75) rectangle (1.5,0.75) ;
                  \useasboundingbox (current bounding box.north west) ++(0,1ex) (current bounding box.south east) ++(0,-1ex);
              \end{tikzpicture}
          & 
          Some text that extends onto more than one line as there's plenty of it. & 
          Some text that extends onto more than one line as there's plenty of it. Some text that extends onto more than one line as there's plenty of it. \\
            Short Text  & 
            Slightly Longer Text & 
                \begin{tikzpicture}[baseline={($(current bounding box.center)+(0,-0.5ex)$)}]
                  % Draw beam and end lines
                  \draw (-1.5,-0.75) rectangle (1.5,0.75) ;
                  \useasboundingbox (current bounding box.north west) ++(0,1ex) (current bounding box.south east) ++(0,-1ex);
              \end{tikzpicture} 
          & 
          Short Text & \\
            Short Text & Slightly Longer Text & Short Text & Short Text & \\
            Short Text & Slightly Longer Text & Short Text & Short Text & \\
    \bottomrule 
\end{tabular}

\end{document}

Best Answer

The problem is in understanding precisely how tabular works.

Each cell has a reference point of reference and all the reference points are eventually put on the same horizontal line. For l, c, and r cells the reference point is on the baseline; for a p cell the reference point is on the first line's baseline; for m cells the reference point is midway from the top and the bottom of the text; for b cells it's on the last line's baseline.

Thus a tabular specification such as

{l m{3cm} p{3cm}}

will not place the middle cells of a row mid aligned with respect to the last cell, but rather its content will stick above the last column by (slightly less than) half its vertical size.

The kind of alignment you're trying to get can't be obtained without measuring the cells' contents, as Stefan Kottwitz's answer about \tabbox shows: that 3.7\baselineskip was good for that example, not in general.

Here's a way out, in your specific case (note the use of \adjustbox for the picture):

\documentclass{article}

\usepackage{tikz}
\usepackage{array}
\usepackage{booktabs,adjustbox}

\newcommand{\finalcells}[2]{%
  \begingroup\sbox0{\begin{minipage}{3cm}\raggedright#1\end{minipage}}%
  \sbox2{\begin{minipage}{3cm}\raggedright#2\end{minipage}}%
  \xdef\finalheight{\the\dimexpr\ht0+\dp0+\smallskipamount\relax}%
  \xdef\finalheightB{\the\dimexpr\ht2+\dp2+\smallskipamount\relax}%
  \ifdim\finalheightB>\finalheight
    \global\let\finalheight\finalheightB
  \fi\endgroup
  \begin{minipage}[t][\finalheight][t]{3cm}\raggedright#1\end{minipage}&
  \begin{minipage}[t][\finalheight][t]{3cm}\raggedright#2\end{minipage}}

\begin{document}

\begin{tabular}{c m{2cm} m{3cm}  m{3cm} m{3cm}} 
\toprule 
\multicolumn{1}{c}{Header 1} & 
\multicolumn{1}{c}{Header 2} & 
\multicolumn{1}{c}{Header 3} & 
\multicolumn{1}{c}{Header 4} & 
\multicolumn{1}{c}{Header 5} \\ 
\midrule
Short Text &    
Slightly Longer Text & 
\adjustbox{valign=c}{%
  \begin{tikzpicture}
  % Draw beam and end lines
  \draw (-1.5,-0.75) rectangle (1.5,0.75) ;
  \end{tikzpicture}%
}
& 
\finalcells{Some text that extends onto more than one line as there's plenty of it.}
  {Some text that extends onto more than one line as there's plenty of it. 
   Some text that extends onto more than one line as there's plenty of it.} \\
\bottomrule 
\end{tabular}

\end{document}

enter image description here