2013-10-24 17 views
2

我試圖用「加載」文本創建一個遮罩窗口,以提醒用戶我的應用程序處於忙碌狀態。創建一個透明的位圖和UpdateLayeredWindow

對於這一點,我首先創建一個單一形式:

  • 邊框= bsNone
  • 顏色= clBlack
  • 的AlphaBlend =真
  • AlphaBlendValue = 180;

作爲第二步,我想創建另一個窗體,但是這個窗體會有動態內容。 我需要創建一個帶有一些狀態文本的透明位圖,並使用UpdateLayeredWindow將窗口繪製爲文本。

看一看,我期望的結果:

enter image description here

記住:文會不同在某些情況下,如:

  • 重新計算
  • 加載資源
  • 加載報告

這就是我需要動態位圖生成的原因。

問題

如何創建一個透明位圖與文字,並用它與UpdateLayeredWindow窗體上?

我想這一點,但沒有成功(嘗試代碼把Button5和label2在窗體上):

procedure Inc(var p: pointer); 
    begin 
    p := Pointer(Integer(p) + 1); 
    end; 

var 
    s: string; 
    frm: TForm; 
    f: HFont; 
    tx: HDC; 
    bmp, old: HBITMAP; 
    rc: TRect; 
    h: BITMAPINFOHEADER; 
    pvBits: Pointer; 
    t: tagBITMAPINFO; 
    x,y: integer; 
    a, r, g, b: byte; 
    sz: TSize; 
    p: tpoint; 
    BlendFunction: TBlendFunction; 
begin 
    tx := CreateCompatibleDC(0); 


    s := label2.Caption; 
    f := SelectObject(tx, label2.Font.Handle); 


    fillchar(rc, SizeOf(rc), 0); 
    DrawText(tx, PChar(s), length(s), rc, DT_CALCRECT); 

    fillchar(h, SizeOf(h), 0); 
    pvBits := nil; 

    h.biSize := SizeOf(h); 
    h.biWidth := rc.Right - rc.Left; 
    h.biHeight := rc.Bottom - rc.Top; 
    h.biPlanes := 1; 
    h.biBitCount := 32; 
    h.biCompression := BI_RGB; 

    FillChar(t, SizeOf(t), 0); 
    t.bmiHeader := h; 

    bmp := CreateDIBSection(tx, t, 0, pvBits, 0, 0); 
    old := SelectObject(tx, bmp); 
    if old > 0 then 
    begin 
    SetTextColor(tx, $00FFFFFF); 
    SetBkColor(tx, $00000000); 
    SetBkMode(tx, TRANSPARENT); 

    DrawText(tx, PChar(s), length(s), rc, DT_NOCLIP); 

    r := GetRValue($FF); 
    g := GetGValue($FF); 
    b := GetBValue($FF); 

    for x := 0 to h.biWidth-1 do 
     for y := 0 to h.biHeight-1 do 
     begin 
     a := Byte(pvBits^); 

     Inc(pvBits); 
     Byte(pvBits^) := (b * a) shr 8; 
     Inc(pvBits); 
     Byte(pvBits^) := (g * a) shr 8; 
     Inc(pvBits); 
     Byte(pvBits^) := (r * a) shr 8; 
     Inc(pvBits); 
     Byte(pvBits^) := a; 
     end; 

    SelectObject(tx, old); 
    end; 

    SelectObject(tx, f); 
    deleteDC(tx); 

    sz.cx := h.biWidth; 
    sz.cy := h.biHeight; 
    p := Point(0,0); 

    BlendFunction.BlendOp := AC_SRC_OVER; 
    BlendFunction.BlendFlags := 0; 
    BlendFunction.SourceConstantAlpha := 255; 
    BlendFunction.AlphaFormat := AC_SRC_ALPHA; 

    frm := TForm.CreateNew(self); 
    frm.BorderStyle := bsNone; 
    frm.Position := poOwnerFormCenter; 
    frm.Show; 

    UpdateLayeredWindow(frm.Handle, 0, nil, @sz, bmp, @p, 0, @BlendFunction, ULW_ALPHA); 
end; 
+0

而你的問題是什麼? –

+0

Eric:現在可以嗎? –

+1

我不明白:爲什麼不在透明表單上使用TLable? – kobik

回答

0

假設你可以使用Windows API函數從德爾福(因爲你已經標記winapi),一個簡單的方法是:

  • CreateDIBSection()創建一個32位的位圖
  • FillRect()來填充背景,DrawText()繪製文本
  • 修復了阿爾法
  • 使用與UpdateLayeredWindow()

修復了阿爾法是通過直接修改你從CreateDIBSection()回位圖位進行位圖。請注意,UpdateLayeredWindow()需要預乘alpha,因此您必須提前將alpha值乘以RGB分量。

下面的代碼是C,但希望會給你的想法:

LPVOID pBits; // bits from CreateDIBSection 
const int width, height; // size of bitmap 
const int alpha; // level of transparency 

RGBQUAD* pPtr = (RGBQUAD*)pBits; 
for (int y = 0; y < height; ++y) 
{ 
    for (int x = 0; x < width; ++x, ++pPtr) 
    { 
     pPtr->rgbBlue = (alpha * pPtr->rgbBlue)/255; 
     pPtr->rgbGreen = (alpha * pPtr->rgbGreen)/255; 
     pPtr->rgbRed = (alpha * pPtr->rgbRed)/255; 
     pPtr->rgbReserved = alpha; 
    } 
}