I was recently developing my own GUI library. The window is created using Win32 API and then Direct2D RenderTarget was created inside. All the drawing (buttons, labels, etc.) happens inside the RenderTarget. Everything is fine except for the quality of the text. When I look at visual studio buttons for example, the text looks so clear compared to DirectWrite method DrawTextW().
Here is an image example:
I use DirectWrite to directly draw text.
`
ID2D1SolidColorBrush* brush;
RenderTarget->CreateSolidColorBrush(D2D1::ColorF(red, green, blue, alpha), &brush);
IDWriteTextFormat* format;
HRESULT h = WriteFactory->CreateTextFormat(std::wstring(font.begin(), font.end()).c_str(), NULL, fontWeight,
fontStyle, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"", &format);
// Center the text horizontally and vertically.
format->SetTextAlignment(textAllignment);
format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
// Draw text
RenderTarget->DrawTextW(std::wstring(text.begin(), text.end()).c_str(), std::wstring(text.begin(), text.end()).size(), format, D2D1::RectF(xPos, yPos, xPos+width, yPos+height), brush);
brush->Release();
format->Release();
`
I was just wondering, is this something that I should just accept and move on or do I have to tweak something with DWriteFactory?
It appears that you have high-DPI monitor and haven't defined proper manifest for your executable. By default Windows will think that your app is designed for old 96ppi systems and so each "pixel" will span four physical pixels if your monitor uses 192ppi for example.
Check this for how to add high-DPI awareness to your application.
In Visual Studio 2015 and above there is a flag in project settings: "Configuration Properties > Manifest Tool > Input and Output > DPI Awareness"
Related
I am trying to create a simple transparent window where I can draw with Direct2D.
So far what I have done:
Created window
Set style to WS_EX_LAYERED
Set alpha color key as #FFF
Draw using Windows Graphics a white rectangle
Now window is transparent with per-pixel alpha
Then make a target out of the window and draw using Direct2D
Make ALPHA _PREMULIPLIED target
Clear with #FFF with 0.0f alpha
Window is now black
I just don't know how to make window to transparent. If you can point out my mistake, I would be obliged
Here how it's achievable using DirectComposition API
Russian: http://www.oszone.net/25395/
English: https://msdn.microsoft.com/magazine/dn745861.aspx
Basically what author does is
Sets WS_EX_NOREDIRECTIONBITMAP extended style to remove redirection bitmap of DWM. Content of window is now empty.
Creates DirectComposition device
Creates Composition SwapChain (and not hwnd swapchain)
Places one visual with SwapChain as content as root visual.
Renders into SwapChain using Direct2D API.
It also works well with WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST for creating event-transparent overlays.
I don't think it's possible with directX. However GDI does work.
Take a look at the source here to see how it's done: http://pastebin.com/NJf8wi2V
In the source you can see that there is an option to attempt to use directx/opengl. However as you can see from running they do not work.
I'm currently developing an application with OpenCV to do visual recognition of elements on the screen.
While a visual representation of the process is not needed, it would be very useful for debugging purposes if I could find a way to draw circles, lines and possibly text directly on the screen, without having an app window.
There are certain applications that, for instance, draw HUDs over the screen. How do they go about doing that?
I need a way for my drawing to always be at the front. In general, all the ways I managed to find involve painting on a window (WinAPI, Direct2D, OpenGL). Is there a workaround to make it appear like it's simply a layover on the desktop (including all open windows)?
for the purpose of debugging, just literally draw on the screen. IIRC GetDC(0) will get you a device context for the screen, but check out that whole family of functions. in Windows 7 it doesn't even foul up other applications' displays, and reportedly it's likewise "safe" on the mac.
for example, this draws an ellipse in the upper left of the screen:
#include <windows.h>
int main()
{
HDC const dc = GetDC( 0 );
Ellipse( dc, 10, 10, 200, 200 );
}
the graphic disappears if it's on top of a window and that window is moved.
You can achieve the device context (DC) of the screen, and draw in that DC as usual. The output will be directed to the screen. To achieve that, call WinApi GetDC("DISPLAY"), if i'm not mistaken.
It's been a long time since I've had to deal with Win32 menus. I need to add some PNG icons to a Win32 context popup menu. Naturally, I want to preserve PNG transparency and all the per-pixel-alpha in the process. Is this possible?
I was thinking on using SetMenuItemBitmaps. Is that the way to go?
I imported my PNGs as "PNG" resources but I can't seem to load them neither with LoadBitmap nor with LoadImage. I found some suggestions about using Gdi+ but obviously I won't be drawing the menu - the system will.
There seems to be a way to get a HBITMAP from a Gdi+ Bitmap but it looks as if all the alpha is getting lost in the process. AFAIK, a HBITMAP can happily host alpha information.
You need GDI+ to load a PNG. Then you need to create a 32-bit alpha bitmap of the correct size, create a Graphics on the bitmap, and use DrawImage to copy the PNG to the bitmap. That gives you a bitmap with an alpha channel.
Something like this:
Image* pimgSrc = Image::FromFile("MyIcon.png"L, FALSE);
Bitmap* pbmpImage = new Bitmap(
iWidth, iHeight,
PixelFormat32bppARGB
);
Graphics* pgraphics = Graphics::FromImage(bmpImage))
{
// This draws the PNG onto the bitmap, scaling it if necessary.
// You may want to set the scaling quality
graphics->DrawImage(
imageSrc,
Rectangle(0,0, bmpImage.Width, bmpImage.Height),
Rectangle(0,0, imgSrc.Width, imgSrc.Height),
GraphicsUnitPixel
);
}
// You can now get the HBITMAP from the Bitmap object and use it.
// Don't forget to delete the graphics, image and bitmap when done.
Perhaps you could use icon instead?
Here are my reasons for using icons instead of PNGs:
The Win32 API has good support icons, and it relatively much easier to draw icons, since GDI+ is not required.
Icons also support 8-bit transparency (just like PNGs).
Icons can be any size in pixels (just like PNGs).
Icons can easily be embedded in the executable as a resource.
Icons can be edited via Visual Studio.
To load an icon from a resource or a file use:
LoadImage()
To draw the icon, use:
DrawIcon() or DrawIconEx()
I've got an MFC application that is built with VC6. When ClearType is enabled (Windows XP) some texts are rendered smoothly, i.e. with ClearType, and others are not.
Dialog texts don't seem to ever get rendered with ClearType. Some list controls, however, have it enabled completely, others only in their headers.
What could be the reason for this? Where should I look to find out why it works only in some places and doesn't in others?
Update
As requested, here is an enlarged screenshot. Obfuscated but the important parts should be visible.
In List 1 only the heading is smooth, the content is not.
In List 2 both, heading and list items are smooth.
The Dialog at the bottom is not using ClearType either.
Bitmap fonts will never use ClearType. Usually you won't use a bitmap font, but I believe the default selected into a DC is the System font, which is bitmap.
ClearType is a quality property for fonts. You should get the LOGFONT for your CFont and set the lfQuality property. Here's an example.
CFont *pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
LOGFONT logFont;
pFont->GetLogFont(&logFont);
logFont.lfQuality = CLEARTYPE_NATURAL_QUALITY;
CFont font2;
font2.CreateFontIndirect(&logFont);
Note: you can use either CLEARTYPE_QUALITY or CLEARTYPE_NATURAL_QUALITY, test both to see which looks best.
I would like to update some toolbar-like code we have to have a Vista/Win7 gradient roundedness to them.
Currently, the buttons have the Windows 2000 look & feel: blocky, single-tone.
I've played around with the XP themes, and using DrawThemeBackground, DrawThemeEdge, etc.; but I'm very dissatisfied with the theme drawing mechanics (the buttons are large, and the theme draws them as 2-tone, top half and bottom half, which looks okay when the buttons are small - it gives them a halfway decent appearance of being a gradient or having a rounded quality to them. But as large as these buttons are, they look stupid.
Experimenting by simply observing how many of the controls are drawn in various apps and controls, I can see that most of them seem to use gradients - where the top of the control appears a light color and fades to the bottom to a darker color - OR - where it is a lighter color than the background at the top, increases towards near-white at the middle, then fades back to a darker color towards the bottom.
I'm not really sure where to go from here. DrawThemeXXX seem to be inadequate. I don't really want to replace the entire control with a new one that has improved drawing but would require that I swap out some of the code for how the current custom control works, and risk various problems with some other library. I'd rather just have a way to draw arbitrary objects in the style of the current version of Windows that I'm running on. I would have thought that the theme drawing functions would have covered this. But they're fairly brain damaged, as I described.
Can someone point me towards 'How are modern C++ applications supposed to draw custom GUI elements so that they might reasonably expect a graceful appearance under XP, Vista, and Windows 7?'
We use MFC, Gdiplus, and raw Win32 APIs in our code, currently.
Here's to hoping someone knows a great deal about drawing modern GUIs under Windows from C++!
Just so that this isn't a wall of text, here's the current version of the paint handler, which draws the button with an etched border when 'hot-tracking' and both an etched border and the icon + text "depressed" (shifted by 1,1) when in a pressed state:
void CPlacesButton::PaintButton(CDC & dc, CRect & rcClient)
{
const int kLabelHeight = 8;
COLORREF clrHiLt = GetSysColor(COLOR_BTNHIGHLIGHT);
COLORREF clrShdo = GetSysColor(COLOR_BTNSHADOW);
COLORREF clrText = GetSysColor(COLOR_BTNTEXT);
COLORREF clrFace = GetSysColor(COLOR_BTNFACE);
// draw the button's background & border
if (m_bPressed || m_bDrawPressed || m_bMouseOnButton)
{
COLORREF clrDarkened = Darken(clrFace, -0.01f);
dc.FillRect(rcClient, &CBrush(clrDarkened));
//dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
//dc.RoundRect(&rcClient, CPoint(10,10));
dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT|BF_FLAT);
//dc.DrawFrameControl(&rcClient, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
}
// else if (m_bMouseOnButton) // hot draw
// //dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
// dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT);
// //dc.RoundRect(&rcClient, CPoint(10,10));
else
dc.FillRect(rcClient, &CBrush(clrFace));
// use transparent mode for everything that follows
dc.SetBkMode(TRANSPARENT);
// center icon
CPoint ptIcon((rcClient.Width() - m_nIconSize) / 2, ((rcClient.Height() - m_nIconSize) / 2) - kLabelHeight);
if (m_bPressed || m_bDrawPressed)
ptIcon.Offset(1, 1);
// determine the state to draw ourselves in
const UINT nState = DST_ICON | (IsEnabled() ? DSS_NORMAL : DSS_DISABLED);
// draw our icon
dc.DrawState(ptIcon, CSize(m_nIconSize, m_nIconSize), m_hIcon, nState, (HBRUSH)NULL);
// create & select the font to use for the button's label
CFont guiFont;
VERIFY(guiFont.CreateStockObject(DEFAULT_GUI_FONT));
AutoSelectGDIObject select_font(dc, guiFont);
// determine clipping rect for label
CRect rcText(0, ptIcon.y+m_nIconSize+kLabelHeight, rcClient.Width(), ptIcon.y+m_nIconSize+kLabelHeight);
rcText.InflateRect(0,20);
if (m_bPressed || m_bDrawPressed)
rcText.OffsetRect(1, 1);
dc.SetTextColor(clrText);
if (IsEnabled())
dc.DrawText(m_strCaption, rcText, DT_VCENTER|DT_SINGLELINE|DT_CENTER);
else
dc.GrayString(NULL, NULL, (LPARAM)(LPCTSTR)m_strCaption, 0, rcText.TopLeft().x, rcText.TopLeft().y, rcText.Width(), rcText.Height());
}
I left some of the commented out variations in the code to indicate some hints as to what other possibilities I've tried. However, they're just a hint, as the complete alternate examples are not present.
Actually duplicating the look of the various flavors of Windows is ridiculously difficult, especially if your app can run on more than one version of windows.
I think that they intended to give you the api's to do this back in the Win2k/Win95 days, but then WinXP came along with shading and overlays, and the old API was completely inadequate.
So they came up with the theme stuff, which isn't really even an API so much as an API and a set of graphical primitives all jammed together. But they didn't follow through and allow the set of graphical primitives to be extended or replaced, so themes only works when your controls are a close match to the standard set.
So, for Win9x/Win2k. You use
DrawFrameControl
DrawEdge
For WinXP
DrawTheme
For WinVista/7
DrawTheme
DwmXXX functions
GradientFill ??
Now I suspect that Windows isn't actually using GradientDraw. I suspect it's actually using some DX10 shaders that are built in to the window manager code, but I don't know how to get at that, s I've been using GradientDraw instead. This code will give you a linear fade from the top of the control to the bottom.
INLINE void SetTrivertex(TRIVERTEX & vtx, int x, int y, COLORREF cr)
{
vtx.x = x;
vtx.y = y;
vtx.Red = (SHORT)(GetRValue(cr) * 256L);
vtx.Green = (SHORT)(GetGValue(cr) * 256L);
vtx.Blue = (SHORT)(GetBValue(cr) * 256L);
vtx.Alpha = (SHORT)(255 * 256L);
}
...
// fill the interior from the top down with a gradient that starts at crTop
// and ends with the crBottom
TRIVERTEX vtx[2];
SetTrivertex (vtx[0], prc->left+1, prc->top+1, crTop);
SetTrivertex (vtx[1], prc->right-1, prc->bottom-1, crBottom);
GRADIENT_RECT gRect = { 0, 1 };
GradientFill(hdc, vtx, 2, &gRect, 1, GRADIENT_FILL_RECT_V);
You never mentioned the MFC Feature Pack. Have you taken a look at it yet? Download for VS2008, included with VS2008 SP1. The CDrawingManager has lots of special effects. It has great support for application themes.
MFC alone isn't exactly skinning friendly. Apart from using another GUI (Qt is great for custom skinning) you can look at solutions like SkinCrafter.