Ausschnitt von DrawText blitten
-
Ich weiß nicht wie ich es anders formulieren soll.
Folgendes Problem:
Ich möchte einen Text mit DrawText ausgeben. Soweit ganz schön. Jetzt kann ich dort ja ein RECT angeben, wo der Text auch schön rechts und unten abgeschnitten wird, wenn dieser nicht mehr reinpasst. Ich suche allerdings eine Möglichkeit, wie ich den Text auch links und oben abschneiden kann und zwar mitten in der Zeile/dem Buchstaben. Also, dass ich quasi einen negativen Offset für links/oben angeben kann. Ich hoffe ihr versteht, was ich meine.
Ich habe es jetzt so versucht, dass ich einen Memory-DC erstelle, wo ich den Text ausgebe und dann den entsprechenden Bereich in mein Fenster blitte, allerdings ist der Hintergrund in meinem Memory-DC immer schwarz und nicht transparent, was also auch keine Lösung des Problems darstellt. Evtl. ist das die Lösung und ich seh' den Wald vor lauter Bäumen nicht mehr und hab' nur einen kleinen Fehler, weshalb der Hintergrund schwarz ist. Ich hoffe ihr könnt mir helfen.
Hier ein kleines Testprogramm, womit ich experimentiert habe, ich denke, wenn ihr euch das Programm anseht, dann ist es evtl. klarer, was ich meine.
(Bitte nicht über den Code meckern, das ist nur ein Testcode mal eben so zusammengeschustert. :))Vielen Dank auf jeden Fall schonmal.

#include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HWND hWnd; MSG msg; WNDCLASS wc; HDC hdc1, hdc2; HBITMAP hbm1, hbm2; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); //wc.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH); wc.hbrBackground = (HBRUSH)CreateSolidBrush(0xCCCCCC); wc.lpszClassName = "myWin10"; wc.lpszMenuName = NULL; RegisterClass(&wc); RegisterClass(&wc); hWnd = CreateWindowEx(0, "myWin10", "Ein Fenster", WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, 0); HBRUSH hbr = ::CreateSolidBrush(0x0000FF); hdc1 = ::CreateCompatibleDC(::GetDC(hWnd)); hbm1 = ::CreateCompatibleBitmap(::GetDC(hWnd), 1000, 1000); ::SelectObject(hdc1, hbm1); RECT r; r.left = 0; r.top = 0; r.right = 1000; r.bottom = 1000; ::FillRect(hdc1, &r, hbr); ::DeleteObject(hbr); ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } ::DeleteObject(hbm1); ::DeleteDC(hdc1); return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: { } break; case WM_ERASEBKGND: { //return 0; } break; case WM_LBUTTONDOWN: { hdc2 = ::CreateCompatibleDC(::GetDC(hWnd)); hbm2 = ::CreateCompatibleBitmap(::GetDC(hWnd), 1000, 1000); SelectObject(hdc2, hbm2); ::SetBkMode(hdc2, TRANSPARENT); SetTextColor(hdc2, 0xFF0000); RECT r; r.left = 0; r.top = 0; r.right = 1000; r.bottom = 1000; HBRUSH hbr2 = ::CreateSolidBrush(0x000000); ::FillRect(hdc2, &r, hbr2); DrawText(hdc2, "test\ntest", 10, &r, 0); BitBlt(hdc1, 10, 10, 40, 40, hdc2, 5, 5, SRCCOPY); ::DeleteObject(hbr2); ::InvalidateRect(hWnd, 0, true); } break; case WM_LBUTTONUP: { ::DeleteObject(hbm2); ::DeleteDC(hdc2); } break; case WM_PAINT: { PAINTSTRUCT ps; HDC dc = ::BeginPaint(hWnd, &ps); BitBlt(ps.hdc, 0, 0, 500, 500, hdc1, 0, 0, SRCCOPY); ::EndPaint(hWnd, &ps); return true; } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, message, wParam, lParam); }
-
Die Lösung heißt "Clipping":
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/clipping_21d3.asp
-
Und so einfach geht es:
// rechteckige Clipping-Region erzeugen HRGN hRegion = CreateRectRgn(left, top, right, bottom); // in den Device-Kontext selektieren SelectClipRgn(hdc, hRegion); // hier Deine Ausgabe-Operationen ... ... // und aufräumen SelectClipRgn(hdc, NULL); DeleteObject(hRegion);
-
du kannst clipping regions verwenden:
#include <windows.h> HBRUSH hbrush; HWND hWnd; LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: hbrush=CreateSolidBrush(0x000000); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); RECT r; r.left = 0; r.top = 0; r.right = 100; r.bottom = 100; FillRect(hdc,&r,hbrush); HRGN rgn=CreateRectRgn(14,10,100,100); SelectClipRgn(hdc,rgn); r.left = 10; r.top = 10; r.right = 100; r.bottom = 100; DrawText(hdc,"test\ntest",10,&r,0); SelectClipRgn(hdc,0); // deselect clip region r.left = 10; r.top = 50; r.right = 100; r.bottom = 150; DrawText(hdc, "test\ntest", 10, &r, 0); EndPaint(hWnd,&ps); return true; } break; case WM_CLOSE: PostQuitMessage(0); break; case WM_DESTROY: DeleteObject(hbrush); break; } return DefWindowProc(hWnd, message, wParam, lParam); } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MSG msg; WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszClassName = "myWin10"; wc.lpszMenuName = NULL; RegisterClass(&wc); hWnd =CreateWindowEx(0, "myWin10", "Ein Fenster", WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, 0); ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }
-
OK, scheint genau das zu sein, was ich gesucht habe. Danke schön.

-
Ich nochmal.

Soweit funktioniert das mit der ClippingRegion, allerdings habe ich dabei noch ein Problem, wo mir auch keine Lösung einfällt. Hier erstmal der Quellcode:void DeviceContext::drawMultilineText(typ::Point _p, std::string _text, typ::Font _font, typ::HAlign::Type _halign, typ::Rectangle _cliprect) { HFONT newFont = ::CreateFont(0 - _font.getSize(), 0, 0, 0, _font.getWeight(), 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, 0, _font.getFamily().c_str()); HFONT oldFont = reinterpret_cast<HFONT>(::SelectObject(this->DC, newFont)); // output rectangle RECT r; r.left = _p.getX(); r.top = _p.getY(); r.right = this->Width; r.bottom = this->Height; // clipping region if (_cliprect.getArea() > 0) { HRGN rgn = ::CreateRectRgn(_cliprect.getX(), _cliprect.getY(), _cliprect.getX() + _cliprect.getWidth(), _cliprect.getY() + _cliprect.getHeight()); // (1) ::SelectClipRgn(this->DC, rgn); // (2) } COLORREF oldColor = ::SetTextColor(this->DC, _font.getColor()); ::DrawText(this->DC, _text.c_str(), _text.length(), &r, 0); ::SelectClipRgn(this->DC, 0); // (3) ::SetTextColor(this->DC, oldColor); ::SelectObject(this->DC, oldFont); ::DeleteObject(newFont); }Und zwar erstelle ich eine rechteckige ClippingRegion, wenn das Rechteck größer 0 ist bzw. der Flächeninhalt, gebe dann den Text aus und weise anschließend wieder 0 als ClippingRegion zu. Wenn ich jetzt mein Fenster resize, in meinem Test habe ich das so gemacht, dass ich die rechte untere Ecke mit der Maus gefasst habe, so dass sich das Fenster in der Höhe und Breite ändert, dann verschwindet nach einer gewissen Zeit das Fenster und ich bekomme komische Effekte, wenn ich mit Rechtsklick z.B. das Kontextmenü des Desktops öffne, dass das nicht komplett angezeigt wird, etc. Wenn ich nur so ein wenig resize, dann passiert nichts, wenn ich aber wie wild die Maus hin- und herschiebe, dann stellt sich dieser Zustand ziemlich schnell ein. Ich hoffe ihr wisst so ungefähr was ich meine.

Ich dachte erst an ein ResourceLeak, konnte das Problem dann aber auf oben genannte Zeilen einschränken, wenn ich keine Region erstelle und zuweise, dann kann ich minutenlang resizen ohne das etwas passiert. Meiner Meinung nach könnte es jetzt 2 Ursachen geben:
1. Ich muss die erstellte Region wieder freigeben, wobe ich in der MSDN aber keinerlei Funktion finden konnte, die das bewerkstelligen würde
2. Aus irgendeinem Grund weißt mein Programm ab einer gewissen Zeit die ClippingRegion jedem mit meiner Maus generierten Fenstern (Kontext-Menüs) zu. wenn ich ein KontextMenü z.B. mit meiner Tastatur öffne, dann wird das korrekt angezeigt, bei der Maus sehe ich nur einen Ausschnitt und der Rest ist schwarz.Bitte helft mir ...

-
The DeleteObject function deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object.
-
Argh, dass da auch region steht hab' ich natürlich völlig überlesen.

*Brille-putz*Vielen Dank, das war's.
