2011-10-10 42 views
7

Tôi đang sử dụng Delphi 7. Tôi quen với việc sử dụng canvas và vẽ văn bản cho canvas và cũng sử dụng TCanvas.TextHeight v.v. Vấn đề nảy sinh khi tôi muốn để triển khai Word Wrap. Tôi không chỉ cần cách tốt nhất để vẽ văn bản vào một khung hình và nó sẽ tự động quấn vào một giới hạn chiều rộng nhất định, nhưng tôi cũng cần phải biết mức độ cao (hoặc bao nhiêu dòng) sau khi nó được bao bọc. Tôi cần phải chuẩn bị một hình ảnh khác trước khi tôi vẽ văn bản, một hình ảnh cần phải đủ lớn để đặt văn bản được bao bọc. Đây là một nỗ lực để tái tạo như thế nào một iPhone hiển thị tin nhắn SMS, với một baloon ở hai bên của màn hình trong một hộp chiều cao di chuyển biến (TScrollingWinControl là cơ sở của tôi).Tính kích thước văn bản trước khi vẽ lên canvas

+3

Sử dụng DrawText và để cho hệ thống làm từ gói –

Trả lời

32

Sử dụng (hầu như) toàn năng DrawText chức năng sử dụng một hình chữ nhật ban đầu, và những lá cờ DT_WORDBREAK (nghĩa là chuỗi nên word-bọc) và DT_CALCRECT:

procedure TForm1.FormPaint(Sender: TObject); 
const 
    S = 'This is a sample text, I think, is it not?'; 
var 
    r: TRect; 
begin 
    r := Rect(10, 10, 60, 60); 
    DrawText(Canvas.Handle, 
    PChar(S), 
    Length(S), 
    r, 
    DT_LEFT or DT_WORDBREAK or DT_CALCRECT); 

    DrawText(Canvas.Handle, 
    PChar(S), 
    Length(S), 
    r, 
    DT_LEFT or DT_WORDBREAK); 
end; 

Do cờ DT_CALCRECT, là người đầu tiên DrawText sẽ không vẽ bất kỳ thứ gì, nhưng chỉ thay đổi chiều cao của r sao cho nó có thể chứa toàn bộ chuỗi S (hoặc giảm độ rộng r nếu S xảy ra để vừa trên một dòng, ngoài ra, nếu S chứa một từ ot phù hợp trên một dòng, chiều rộng của r sẽ được tăng lên). Sau đó, bạn có thể làm bất cứ điều gì bạn muốn với r, và sau đó bạn có thể vẽ chuỗi cho thực.

Hãy thử điều này, ví dụ:

procedure TForm1.FormPaint(Sender: TObject); 
const 
    S: array[0..3] of string = ('Hi! How are you?', 
    'I am fine, thanks. How are you? How are your kids?', 
    'Fine!', 
    'Glad to hear that!'); 
    Colors: array[boolean] of TColor = (clMoneyGreen, clSkyBlue); 
    Aligns: array[boolean] of integer = (DT_RIGHT, DT_LEFT); 
var 
    i, y, MaxWidth, RectWidth: integer; 
    r, r2: TRect; 
begin 

    y := 10; 
    MaxWidth := ClientWidth div 2; 

    for i := low(S) to high(S) do 
    begin 

    Canvas.Brush.Color := Colors[Odd(i)]; 

    r := Rect(10, y, MaxWidth, 16); 
    DrawText(Canvas.Handle, 
     PChar(S[i]), 
     Length(S[i]), 
     r, 
     Aligns[Odd(i)] or DT_WORDBREAK or DT_CALCRECT); 

    if not Odd(i) then 
    begin 
     RectWidth := r.Right - r.Left; 
     r.Right := ClientWidth - 10; 
     r.Left := r.Right - RectWidth; 
    end; 

    r2 := Rect(r.Left - 4, r.Top - 4, r.Right + 4, r.Bottom + 4); 
    Canvas.RoundRect(r2, 5, 5); 

    DrawText(Canvas.Handle, 
     PChar(S[i]), 
     Length(S[i]), 
     r, 
     Aligns[Odd(i)] or DT_WORDBREAK); 

    y := r.Bottom + 10; 

    end; 

end; 

procedure TForm1.FormResize(Sender: TObject); 
begin 
    Invalidate; 
end; 

Screenshot http://privat.rejbrand.se/DrawTextChat.png

+7

1 Thất vọng cuộc nói chuyện không phải là ở Thụy Điển ...... ;-) –

+0

Tuyệt vời, thực sự tôi đã phát hiện ra điều này ngay trước khi tìm thấy câu trả lời này ... Cảm ơn bạn một loạt, điều này sẽ làm việc tuyệt vời trong thành phần này. Bây giờ nếu tôi có thể nhận được một số lời khuyên thừa kế tốt nhất cho thành phần này là gì - TScrollingWinControl/TImage (Canvas trực tiếp) hoặc TScrollingWinControl/TDrawGrid (Lưới vải)? Tất nhiên nó cần để có thể dễ dàng di chuyển lên và xuống - Tôi có một phiên bản làm việc với một TDrawGrid trong một TScrollBox - nhưng cần một thừa kế trực tiếp hơn. –

+0

Hi Andreas - Câu trả lời tuyệt vời như bình thường! – Ampere

Các vấn đề liên quan