Is there anyway to display a splash screen without the window? Like just the image pops up for a few seconds, then after that shows a dialog box asking the player if he/she wants to create a new project or open one. I know, two questions in one. I am using Visual Studio right now.
Thanks!
You mean like:
Code Blocks:
Photoshop:
Or even, the very program you're using, Visual Studio:
Other ones include anything in the Adobe suite, and anything in the office suite, just off the top of my head.
So, obviously the answer is yes. The way to do this is to create a borderless window. With C++, this seems to be a bit difficult. I would highly suggest sticking to a rectangle splash screen, unless you want to handle the paint events to draw whatever is below you, which is a pain.
I found a how-to over here at Programmers Heaven, which is below so it's also on this site per SO guidelines.
The other option, is to simply use C#, which makes this kind of thing really easy.
First Create a window with the WS_POPUP flag
Also - When creating your window take into account the fact that the system will likely still want to draw the border and title bar etc... so calculate that into your window dimensions as follows
#define WINDOW_WIDTH 300 // whatever size you need
#define WINDOW_HEIGHT 256
// Calculate the proper size for the window given a client
DWORD dwFrameWidth = GetSystemMetrics( SM_CXSIZEFRAME );
DWORD dwFrameHeight = GetSystemMetrics( SM_CYSIZEFRAME );
DWORD dwMenuHeight = GetSystemMetrics( SM_CYMENU );
DWORD gdwWindowXPos = ( GetSystemMetrics( SM_CXSCREEN ) - WINDOW_WIDTH ) / 2;
DWORD gdwWindowYPos = ( GetSystemMetrics( SM_CYSCREEN ) - WINDOW_HEIGHT ) / 2;
DWORD gdwWindowWidth = WINDOW_WIDTH + dwFrameWidth * 2;
DWORD gdwWindowHeight = WINDOW_HEIGHT + dwFrameHeight * 2 + dwMenuHeight;
You should then have something like this for your window creation:
HWND hwnd = CreateWindowEx(0,
"Class Name",
"Window Name",
WS_POPUP, // and any other flags you need
gdwWindowXPos, // these just center the
gdwWindowYPos, // window on the screen
gdwWindowWidth, // Calculated width
gdwWindowHeight, // and height
NULL, // Parent window
NULL, // Menu (don't want one)
hInst, // hInstance
NULL // Other Parameters
);
... Right ....
The next thing is to set the window region, so that you only draw the area you're interested in by using CreateRectRgn, and SetWindowRgn like so:
HRGN hrgn = CreateRectRgn( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );
SetWindowRgn( hwnd, hrgn, TRUE );
This clips the window to the size I wanted when I #defined WINDOW_WIDTH and WINDOW_HEIGHT
Related
void Initialize_Window(void)
{
RECT rConsole;
GetWindowRect(GetConsoleWindow(), &rConsole);
SetWindowPos(GetConsoleWindow(), NULL, 0, 0, 800, 700, 0);
SetWindowLong(GetConsoleWindow(), GWL_STYLE, GetWindowLong(GetConsoleWindow(), GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX));
SetWindowPos(GetConsoleWindow(), NULL, (GetSystemMetrics(SM_CXSCREEN) - rConsole.right - rConsole.left) / 2, (GetSystemMetrics(SM_CYSCREEN) - rConsole.bottom - rConsole.top) / 2, 0, 0, SWP_NOSIZE);
}
I'm trying to center my console window by using the code above, but seems like the window just moved to a random position on my screen every time I execute the program, any idea how to fix it?
You need (GetSystemMetrics(SM_CXSCREEN) - (rConsole.right - rConsole.left))/2 to get center.
Side note: you can use one SetWindowPos instead of two (and do not need to get window Rect)
const int width = 800;
const int height = 700;
//SetWindowLong()...
SetWindowPos(GetConsoleWindow(), NULL,
GetSystemMetrics(SM_CXSCREEN)/2 - width/2,
GetSystemMetrics(SM_CYSCREEN)/2 - height/2,
width, height, SWP_SHOWWINDOW);
Don't use GetSystemMetrics() for this because it only returns the metrics of the primary monitor. Multi monitor setups are quite common these days so users will be rightly upset if you ignore that.
In addition, a window normally should not be aligned to the physical monitor surface, but to the work area which excludes the taskbar(s). Yes, there can be multiple taskbars (called "appbars" in Windows slang) on either side of the screen. An exception where you would actually use the full physical surface are full screen windows.
To cover both aspects we can use MonitorFromWindow() and GetMonitorInfo().
First we get the "nearest" monitor from the window handle. This is the monitor that either shows the window completely or that has the biggest area of the window on it:
HWND hConsoleWnd = ::GetConsoleWindow();
HMONITOR hMonitor = ::MonitorFromWindow( hConsoleWnd, MONITOR_DEFAULTTONEAREST );
Then we get the work area rectangle of that monitor and center the window relative to that:
if( hMonitor )
{
MONITORINFO info{ sizeof(info) }; // set cbSize member and fill the rest with zero
if( ::GetMonitorInfo( hMonitor, &info ) )
{
int width = 800;
int height = 700;
int x = ( info.rcWork.left + info.rcWork.right ) / 2 - width / 2;
int y = ( info.rcWork.top + info.rcWork.bottom ) / 2 - height / 2;
::SetWindowPos( hConsoleWnd, nullptr, x, y, width, height,
SWP_NOZORDER | SWP_NOOWNERZORDER );
}
}
That's it. In a real-world application you should of course not hardcode the window size because it is a user preference. For first launch a default size can be reasonable but even that should not be hardcoded but scaled according to the Windows DPI settings.
Could you give the simplest way to achieve double buffering for this example code (to prevent flickering):
HWND hwnd = FindWindow(0, "Untitled - Notepad");
HDC hDC_Desktop = GetDC(hwnd);
...
while( )
{
RECT rect = { 10, 10, 10 + 50, 10 + 50 };
FillRect(hDC_Desktop, &rect, ColorBrush);
InvalidateRect (hwnd, NULL, TRUE);
}
The reason it's "flickering" is because the target window is getting invalidated and it is being redrawn. Since it's not your window - you don't necessarily have control over that.
If this was your own window there is a simple strategy to speed up your drawing speed and reduce flicker: Use a Memory DC to draw on and capture WM_ERASEBKGND to suppress background redraws.
In depth explanation and strategy for fixing it (in your application's window): http://www.catch22.net/tuts/win32/flicker-free-drawing
If your intent is to draw on another application, might I suggest creating a window on top of that application and draw on that.
I need to get the maximum possible height and width of a window being created (window is not maximized first). How to do it?
You can get screen height and width, and pass that value to get maximum possible size of window.
Try this:
int X = GetSystemMetrics( SM_CXSCREEN );
int Y = GetSystemMetrics( SM_CYSCREEN );
Here in X you will get the Width of the screen.
And in Y you will get the Height of the screen.
You can use GetSystemMetrics with SM_CXSCREEN and SM_CYSCREEN. This is the width and height off your primary display monitor.
Another way would be to determine the desktop workarea size:
CRect rectWorkArea;
SystemParametersInfo(SPI_GETWORKAREA,0,&rectWorkArea,0);
Or to determine the size of the work area of a specific monitor were your window exists
CRect rectWorkArea;
MONITORINFO mi;
mi.cbSize = sizeof(mi);
::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi);
rectWorkArea = mi.rcWork;
MONITORINFO also contains the monitor size.
Depends what you need to do.
Me again guys, I've managed to learn up till now about most basics regarding window creation and message system, now I wanted to ask about formatting because I didn't manage to find anything about my particular case on google.
Here is what it looks like so far:
The boxes with 0s in them are Static windows since I didn't really get the Rect paint job. I also need it to be dynamic; the boxes will display an element from an int array that I'll transfer over to a wchar_t array for output.
Now is it possible to change the font, lets say increase it and make it bold? Or is it only possible using print text function?
Any help would be much appreciated since I'm really trying to make this "centered" so to speak.
EDIT:
Another question just so I don't make another post:
I just noticed that my stupid static windows don't update after I change the values in array I'm printing in them and repaint them. E.g. each zero is contained in wchar_t array[16][15]; and after I print this setup and change lets say array[13][0] = 'A'; nothing happens, is it due to Static window type or is it because of me being noobish and using MoveWindow to repaint them XD?
The windows message WM_SETFONT will do it. First there should be a font created, and then it is used in the parameter for WM_SETFONT.
When the font and window have been created, use
SendMessage(wnd, WM_SETFONT, (WPARAM)font, FALSE);
to set the default font for the window.
If you want to use a default windows font, you can create one like this:
HFONT font = NULL;
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(NONCLIENTMETRICS));
ncm.cbSize = sizeof(NONCLIENTMETRICS);
if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICS), &ncm, 0)) {
font = CreateFontIndirect(&ncm.lfMessageFont);
}
There are other default fonts in NONCLIENTMETRICS that you could use.
Of course you can also create a font from a typeface name and other information, but there is no guarantee that there is such a font on different systems.
HFONT CreateFont(
int nHeight, // height of font
int nWidth, // average character width
int nEscapement, // angle of escapement
int nOrientation, // base-line orientation angle
int fnWeight, // font weight
DWORD fdwItalic, // italic attribute option
DWORD fdwUnderline, // underline attribute option
DWORD fdwStrikeOut, // strikeout attribute option
DWORD fdwCharSet, // character set identifier
DWORD fdwOutputPrecision, // output precision
DWORD fdwClipPrecision, // clipping precision
DWORD fdwQuality, // output quality
DWORD fdwPitchAndFamily, // pitch and family
LPCTSTR lpszFace // typeface name
);
For my application I need to create a Dialog Box without using resource.
I am trying to do it with DialogBoxInderect function.
The code is unbelievably ugly but somehow I succeeded to do it.
The problem is that dialog, for some reason, is much bigger than I asked with much bigger fonts.
Here is how the dialog looks like if I load it from resource:
And here is the dialog with the same size stated when I call DialogBoxInderect function.
Here is how it is defined in code:
HGLOBAL hGlobal;
LPDLGTEMPLATE wlsDialogTemplate;
LPDLGITEMTEMPLATE wlsDialogItemTemplate;
LPWORD nextItem;
LPWSTR itemString;
int32_t itemStringLength;
// Check for memory allocation errors
hGlobal = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hGlobal)
return -1;
wlsDialogTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
// Define a dialog box.
wlsDialogTemplate->style = WS_CAPTION;
wlsDialogTemplate->x = 0;
wlsDialogTemplate->y = 0;
wlsDialogTemplate->cx = 320;
wlsDialogTemplate->cy = 115;
GlobalUnlock(hGlobal);
retCode = DialogBoxIndirect(0, (LPDLGTEMPLATE)hGlobal, 0, ActivateWlsMsgDialog);
And here is how it is defined in RC file:
IDD_WLS_SMALL_MESSAGE_DLG DIALOGEX 0, 0, 320, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",ID_CUSTOM_OK,175,95,120,15
PUSHBUTTON "Cancel",ID_CUSTOM_CANCEL,45,95,120,15
CTEXT "Static",IDC_HEADER_TEXT,120,10,170,70
CONTROL "",IDC_LOGO,"Static",SS_BITMAP,16,10,83,70
END
As you can see, the second dialog is much bigger than defined. I tried to play with various style flags but without any success (That is why there is red cross on the bigger dialog).
Any help with that?
Thanks!
The larger size is easy to explain. Windows automatically sizes the dialog in accordance with its font, and the larger dialog uses a different font. In fact, it is using the default system font (more info on the confusing issue of Windows dialog fonts is found in my answer here).
So the real issue to focus on is why it's using a different font, and fixing that will solve the size problem.
In the dialog box resource file, you specify the DS_SETFONT flag as one of the dialog box styles. According to the documentation, this flag
[i]ndicates that the header of the dialog box template (either standard or extended) contains additional data specifying the font to use for text in the client area and controls of the dialog box. If possible, the system selects a font according to the specified font data. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message.
So that explains why that one is displaying with the expected font.
The next logical question is what's different about your dynamically-created dialog template, shown with the DialogBoxIndirect function. The culprit is, once again, the DS_SETFONT flag, but in this case, the flag is absent. That means that the dialog doesn't contain any information about which font to use to display its controls, and the system defaults to the default system font (which is the ugly Windows 2.0-era font that you see in the second screenshot).
Once we've come to this understanding, the solution should be obvious: you need to tell the dialog which font you want it to use. There are two possible ways of doing so that come to mind:
You can set the DS_SETFONT flag and provide the font information in the header of the dialog box template as described in the above-linked documentation.
Or you can simply create and set the dialog's font in response to the WM_INITDIALOG message.
The latter is probably what you really want to do, as it allows you to use the actual system font (which, confusingly, is different from what I've been calling the "default" system font), which is Segoe UI in Windows Vista and later. Note that even in your first screenshot, it's using MS Sans Serif and therefore sticks out like a sore thumb in the Aero interface. Again, see this answer for more about fonts than you ever wanted to know and sample code for making this work. You'll need to make sure that you set the font for the dialog itself and all of its child controls.
I had played with DialogBoxIndirect (actually with DialogBoxIndirectParam), and here's the part of the code that sets the font. Observe the DS_SHELLFONT option.
LPWORD lpwAlign(LPWORD lpIn, int nAlignment)
{
return (LPWORD)(((ULONG_PTR)lpIn + nAlignment - 1) & -nAlignment);
}
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPMYMESSAGEPARAMS pParams)
{
WORD mem[1024]; // Buffer for dialog resource
LPDLGTEMPLATEW lpdt; // Pointer to heading resource structure
LPDLGITEMTEMPLATEW lpdit; // Pointer to current control
LPWORD lpw; // Cursor to resource buffer
LPWSTR lpwsz; // Cursor to resource buffer (of type WCHAR)
LPCWSTR lpwszCaption; // Aux pointer for text copying
LRESULT ret; // Function's return value
lpdt = (LPDLGTEMPLATEW)lpwAlign( mem, 4 );
//-----------------------
// Define a dialog box.
//-----------------------
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION |
DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
lpdt->dwExtendedStyle = 0;
lpdt->cdit = 3; // number of controls
lpdt->x = 0; lpdt->y = 0;
lpdt->cx = 164; lpdt->cy = 49;
lpw = (LPWORD)(lpdt + 1);
// Dialog menu
*lpw++ = 0;
// Dialog class
*lpw++ = 0;
// Dialog title
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"Choose language";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
// Dialog font
if ( lpdt->style & (DS_SETFONT | DS_SHELLFONT) )
{
// Size
*lpw++ = 8;
// Typeface name
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"MS Shell Dlg";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
}
// Define the rest of the controls
...
ret = DialogBoxIndirectParamW( hinst, lpdt,
hwndOwner, MyMessageProc, (LPARAM)pParams );
return ret;
}
This can be solved in your dialog handler by looking for the WM_INITDIALOG message, and then setting the font for all the controls in the dialog.
int CALLBACK SetChildFont(HWND child, LPARAM font) {
SendMessage(child, WM_SETFONT, font, TRUE);
return TRUE;
}
static int CALLBACK MyMessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
/* Set font for dialog and all child controls */
EnumChildWindows(hwnd, (WNDENUMPROC)SetChildFont, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
break;
}
return 0;
}