2010-01-25 5 views
5

내 문제 :

현재 한 줄에 여러 텍스트 (각각 글꼴이 다를 수 있음)를 표시하는 사용자 지정 사용자 정의 컨트롤을 만들고 있습니다. 나는 모든 공통 부분의 텍스트를 정확히 일치 함께 정렬하고 싶습니다. 예를 들어 내가 직접이 작업을 수행 할 수있는 GDI + 기능을 발견하지 않았기 때문에GDI +를 사용하여 공통 기준선을 따라 여러 가지 글꼴로 텍스트를 정렬하는 가장 쉬운 방법은 무엇입니까?

Hello, I am George. 
------------------------------ <- all text aligns to a common baseline 
    ^  ^ ^
    |   |  | 
Courier Arial Times  <- font used for a particular bit of text 
    20pt  40pt  30pt 

, 나는 (아래 설명) 내 자신의 방법을 함께했다. 그러나 :

이 작업을 수행하는 것이 더 쉬운 방법이 아닌지 궁금합니다.

내 현재의 접근 방식 :

1) 텍스트를 그리기에 사용되는 모든 System.Drawing.Font의 목록을 수집합니다. 사용되는 모든 Font 초간

// variables used in code sample (already set) 
Graphics G; 
Font font; 
... 

// compute ratio in order to convert from font design units to pixels: 
var designUnitsPerPixel = font.GetHeight(G)/
          font.FontFamily.GetLineSpacing(font.Style); 

// get the cell ascent (baseline) position in design units: 
var cellAscentInDesignUnits = font.FontFamily.GetCellAscent(font.Style); 

// finally, convert the baseline position to pixels: 
var baseLineInPixels = cellAscentInDesignUnits * designUnitsPerPixel; 

3)로서 최대 baseLineInPixels 값을 결정 : 각 Font 들어

2) 다음 코드를 사용하여, 픽셀 단위로 기준의 수직 위치를 찾을 이 값을 maxBaseLineInPixels에 저장하십시오.

// variables used in code sample (already set): 
Graphics G; 
Font font; 
string text; 
... 

// find out how much space is needed for drawing the text 
var measureF = G.MeasureString(text, font); 

// determine location where text will be drawn: 
var layoutRectF = new RectangleF(new PointF(0f, 0f), measureF); 
layoutRectF.Y += maxBaseLineInPixels - baseLineInPixels; 
//^the latter value 'baseLineInPixels' is specific to the font used 

// draw text at specified location 
G.DrawString(text, font, Brushed.Black, layoutRectF); 

내가 뭔가를 누락 또는 AM 정말 더 쉬운 방법이 없다 :

4)는 다음과 같은 방법으로 텍스트의 각 비트를 그립니다?

+1

오늘과 어제를 통해 확인했습니다. 유일한 해결책 인 것 같습니다. Font.GetHeight (Graphics)는 픽셀이 아니라 Graphics 객체의 PageUnit에있는 값을 반환합니다. 저는 Bob Powell의 솔루션 (http://www.bobpowell.net/formattingtext.htm)을 사용하고 있습니다. 그의 코드 (글쎄, C#)의 마지막 코드 블록을 사용하고 밀리미터로 변환합니다. 공유 인쇄/그림/PDF 작성 루틴. – OregonGhost

+0

의견에 감사드립니다. 나는 GDI +로 그려지는 텍스트가 사실 * 복잡하다는 것을 듣고 안심한다. 나는 이것을 상상하지 않고있다. 이후이 문제를 해결하고 WPF (GDI +는 더 이상 중요하지 않으며 일이 조금 더 쉬워 질 것입니다)로 이동하기로 결정했습니다. – stakx

답변

0

이런 식으로 생각합니다. 노력해주세요.

List<RectangleF> rects = new List<RectangleF>(); 

private void Form1_Paint(object sender, PaintEventArgs e) 
{ 
    ////////////////////Not Set baseLine 
    //baseline 
    e.Graphics.DrawLine(Pens.Red , new Point(100,200),new Point(800,200)); 

    //words 
    Point point = new Point(100,100); 
    e.Graphics.DrawString("hello world", new Font("Times", 30), Brushes.Black, point); 
    RectangleF rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Times", 30))); 
    e.Graphics.DrawRectangle(Pens.Green,rectangleF.X ,rectangleF.Y , rectangleF.Width , rectangleF.Height); 
    rects.Add(rectangleF); 

    point = new Point(400, 100); 
    e.Graphics.DrawString("hello world", new Font("Arial", 40), Brushes.Black, point); 
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Arial", 40))); 
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height); 
    rects.Add(rectangleF); 

    point = new Point(800, 100); 
    e.Graphics.DrawString("hello world", new Font("Courier", 20), Brushes.Black, point); 
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Courier", 20))); 
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height); 
    rects.Add(rectangleF); 

    ///////////////////SetBaseLine///////////////////////////// 
    var maxHeight = GetMaxHeight(); 
    /////////////////// 

    //baseLine 
    e.Graphics.DrawLine(Pens.Pink, new Point(100, (int) (400 + maxHeight/2)), new Point(800, (int) (400 + maxHeight/2))); 

    StringFormat stringFormat = new StringFormat(); 
    stringFormat.LineAlignment = StringAlignment.Center; 

    //words 
    point = new Point(100, 400); 
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Times", 30))); 
    e.Graphics.DrawString("hello world", new Font("Times", 30), Brushes.Black, new RectangleF(rectangleF.X ,rectangleF.Y , rectangleF.Width , maxHeight) , stringFormat); 
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height); 
    rects.Add(rectangleF); 

    point = new Point(400, 400); 
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Arial", 40))); 
    e.Graphics.DrawString("hello world", new Font("Arial", 40), Brushes.Black, new RectangleF(rectangleF.X, rectangleF.Y, rectangleF.Width, maxHeight), stringFormat); 
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height); 
    rects.Add(rectangleF); 

    point = new Point(800, 400); 
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Courier", 20))); 
    e.Graphics.DrawString("hello world", new Font("Courier", 20), Brushes.Black, new RectangleF(rectangleF.X, rectangleF.Y, rectangleF.Width, maxHeight), stringFormat); 
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height); 
    rects.Add(rectangleF); 

} 

private float GetMaxHeight() 
{ 
    float temp = 0; 
    foreach (RectangleF rectangleF in rects) 
     if (rectangleF.Height > temp) 
      temp = rectangleF.Height; 

    return temp; 
} 
+0

게시 주셔서 감사합니다. 그러나이 솔루션은 불행히도 도움이되지 않습니다 ... 죄송합니다. 이것은 두 가지 이유 때문입니다 : ** 1 ** ** 나는 이것을 포기한 이후로 (원래 게시일을 보았습니다.) 대신 WPF로 전환하기로 결정했습니다. ** 2. ** 당신의 코드에 좋은 접근법이 있다고 생각합니다 ('MeasureString','GetMaxHeight'); 불행히도, 나머지 코드의 대부분은 다른 것을 제안합니다. 즉, 미리 계산 된 고정 좌표로 작업하고 텍스트를 두 번 그리는 것 (불필요한 것으로 보임)입니다. 그럼에도 불구하고 대답 할 시간을내어 주셔서 감사합니다. – stakx

0

나는 지난 몇 일 동안 같은 일을 연구하고 있었고, 나는 마침내 대답 on this blog page을 발견했다. 기사의 맨 아래에있는이 코드는 저에게 정말 잘 돌아 갔고 희망적으로이 문제로 어려움을 겪고있는 다른 사람들을 도왔습니다.

private void DrawOnBaseline(string s, Graphics g, Font f, Brush b, Point pos) 
    { 
     float baselineOffset=f.SizeInPoints/f.FontFamily.GetEmHeight(f.Style)*f.FontFamily.GetCellAscent(f.Style); 
     float baselineOffsetPixels = g.DpiY/72f*baselineOffset; 

     g.DrawString(s,f,b,new Point(pos.X,pos.Y-(int)(baselineOffsetPixels+0.5f)),StringFormat.GenericTypographic); 
    }