Hello Everyone,
I want to know if there is an image control in VC++ like there is one in VB. Actually using the picture box i face the problem of not being able to re size the image at design time for my dialog. But in image control this is possible. I there is no image control is there a way to check the height and width of a dialog from the dialog editor at design time ???
If you're writing an unmanaged C or C++ project it's a little bit more difficult than using the PictureBox control that would be available when designing managed Windows Forms application, but still doable.
If you are using a DialogBox resource for the window (note: I wrote this part using Visual Studio 2015 as a reference, not 2008, but the general process should be the same):
Insert the image as a resource in your project. Let's say we named the resource for the bitmap IDB_BITMAP1 for simplicity.
Create a new Static child window in the dialog box.
Right click on the new Static window and select Properties.
Under the Misc subheading in Properties, change Type to Bitmap.
Under the Misc subheading in Properties, change Image to IDB_BITMAP1.
If you are hand-coding the window (i.e. manually writing calls to CreateWindow and CreateWindowEx to create the window):
Insert the image as a resource in your project. Make sure to add the line #include "resource.h" to your code.
Get a handle to the bitmap using the LoadBitmap function.
Create the static window as a child window of the main window, and specify the SS_BITMAP window style.
Send the STM_SETIMAGE message to the window using the previously identified handle to the bitmap resource.
Example code, assuming your image is IDB_BITMAP1:
#include <Windows.h>
#include <tchar.h>
#include "resource.h"
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
{
HWND hWnd, hStcImage;
MSG Msg;
HBITMAP hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
// ... register the window class etc
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, _T("ExampleClassName"), _T("Simple Window"), WS_VISIBLE | WS_SYSMENU, 100, 100, 350, 370, NULL, NULL, hInstance, NULL);
hStcImage = CreateWindow(_T("Static"), NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 10, 10, 0, 0, hWnd, NULL, hInstance, NULL);
SendMessage(hStcImage, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Related
When I'm about to resize a simple GUI created on Windows/c++
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
LoadStringW(hInstance, IDC_PROJECT2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
return FALSE;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PROJECT2));
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)){
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
It creates a transparent rectangle showing where it will be expanded to:
I would like to disable it, as i'm working with a custom frameless GUI.
I tried searching for how this transparent rectangle is called or what WINAPI creates it, but I could not find it.
Appreciate any help on this.
Its principle is similar to that of sheet of glass.
Basically, sheet of glass expands to become a parent window, and the window being dragged is a layered window when the window touches the edge of the screen.
The system uses SetLayeredWindowAttributes to make sheet of glass transparent, and dragged windows are not affected by WS_POPUP parameter.
The documentation explains how to achieve transparency and de-transparency.
To make this window completely opaque again, remove the WS_EX_LAYERED bit by calling SetWindowLong and then ask the window to repaint. Removing the bit is desired to let the system know that it can free up some memory associated with layering and redirection. The code might look like this:
// Remove WS_EX_LAYERED from this window styles
SetWindowLong(hwnd,
GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
// Ask the window and its children to repaint
RedrawWindow(hwnd,
NULL,
NULL,
RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
I wrote a sample, and it does work after testing.
When I create a window in C using the CreateWindow() function, it works fine it just disappears instantly, so I used the getch() function to try to resolve the issue but it does not work. The window does not display the button, and crashes.
But when I used MessageBox() instead of getch(), it stays and functions normally. I am trying to figure out why this happens.
I tried many things, like using MessageBox() and getch() together, using getch() before and after ShowWindow(), but every time it gives me some interesting result but not the normal functionality of the window.
Code that works:
#include <windows.h>
int _stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND h;
HINSTANCE i;
h = CreateWindow("Button", "XYZ", WS_OVERLAPPEDWINDOW, 15, 20, 250, 200, 0, 0, i, 0);
ShowWindow(h, nCmdShow);
MessageBox(0, "Stop", "Wait", MB_OK);
return 0;
}
Code that does not work:
#include <windows.h>
int _stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND h;
HINSTANCE i;
h = CreateWindow("Button", "XYZ", WS_OVERLAPPEDWINDOW, 15, 20, 250, 200, 0, 0, i, 0);
ShowWindow(h, nCmdShow);
getch();
return 0;
}
I want to know the reason for this error. I think it is because getch() is a DOS function, but still the compiler should at least show a warning.
There is no crash in this code.
Your getch() example simply lacks a message loop needed to service the window, and also getch() is meaningless in a non-console app. So your WinMain() exits immediately after showing the button window.
Whereas your MessageBox() example has a message loop (inside of MessageBox() itself) which keeps WinMain() running, and the button window processong UI messages, until the MessageBox dialog is closed.
Also, it doesn't make sense to try to display a button as its own overlapped window. You should be registering and creating a separate overlapped window that then creates the button as a child. User actions on the button are sent to the button's parent window, so you need to create a parent window for it.
Is there a way to set true full focus on a push button (button window class) in WinAPI?
SetFocus() somewhat sets focus (the button gets an inner dotted border), but the button is actually partially focused and still cannot be pressed with the Enter key, only the Spacebar key works. At the same time, if I move focus to a sibling button with the Tab key, then this sibling button (as well as the first button if I then return focus to it using Shift+Tab) gets a true focus (visually, not just inner dotted focus border is added to the really focused button, but its main outer border becomes blue [Windows 7]), and now it reacts to Enter as intended.
How to make a button such fully focused programmatically?
Screenshot of the three button states:
Some background for clarity: there is a window (created with the regular combination of WNDCLASSEX / RegisterClassEx / CreateWindowEx() with WS_OVERLAPPEDWINDOW as its style) with a multiline edit box (edit window class with ES_MULTILINE style) and several push buttons. To implement keyboard navigation using the Tab key, I process the WM_KEYDOWN event in the edit box's procedure (subclassed via SetWindowLong()), otherwise I could navigate between buttons and from buttons to the edit box, but not from the edit box to a button. All the controls have WS_TABSTOP style. The issue with the button focus takes place when I set focus using SetFocus() when the Tab key is pressed on the edit box having focus and caret.
Minimal relevant C++ code:
HWND mainWindow;
WNDPROC defaultEditCallback = NULL;
int WINAPI WinMain(HINSTANCE instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEXW wc;
wchar_t windowClass[] = L"testcase";
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = 0;
wc.lpfnWndProc = mainWindowCallback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instance;
wc.hIcon = NULL;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)windowClass;
wc.hIconSm = NULL;
RegisterClassExW(&wc);
mainWindow = CreateWindowW(
(LPCWSTR)windowClass, (LPCWSTR)windowClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, instance, NULL
);
HWND edit = CreateWindowExW(
WS_EX_CLIENTEDGE, (LPCWSTR)L"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | WS_TABSTOP,
0, 0, 0, 0, mainWindow, (HMENU) 10,
(HINSTANCE) GetWindowLongPtrW(mainWindow, GWLP_HINSTANCE),
NULL
);
defaultEditCallback = (WNDPROC)SetWindowLongPtrW(edit, GWLP_WNDPROC, (LONG)editCallback);
HWND firstButton = createButton(mainWindow, 20, L"First", buttonWidth, buttonHeight);
HWND secondButton = createButton(mainWindow, 30, L"Second", buttonWidth, buttonHeight);
HWND thirdButton = createButton(mainWindow, 40, L"Third", buttonWidth, buttonHeight);
// [Skipped] Sizing and positioning controls.
ShowWindow(mainWindow, nCmdShow);
UpdateWindow(mainWindow);
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(mainWindow, &msg)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK mainWindowCallback(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_DESTROY == msg) {
PostQuitMessage(0);
}
return DefWindowProcW(window, msg, wParam, lParam);
}
LRESULT CALLBACK editCallback(HWND control, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_KEYDOWN == msg && VK_TAB == wParam) {
HWND next = GetNextDlgTabItem(mainWindow, control, (int)(GetKeyState(VK_SHIFT) & 0x8000));
SetFocus(next);
return 0;
}
return CallWindowProc(defaultEditCallback, control, msg, wParam, lParam);
}
HWND createButton(HWND parentWindow, int id, wchar_t* caption, int width, int height) {
return CreateWindowW(
(LPCWSTR)L"button", (LPCWSTR)caption, WS_VISIBLE | WS_CHILD | WS_TABSTOP,
0, 0, width, height, parentWindow, (HMENU)id, NULL, NULL
);
}
Thanks.
The question does not make it clear whether the WS_OVERLAPPEDWINDOW main window is either a dialog, or subclassed to work like a dialog (i.e. based on DefDlgProc). Some hints about TAB navigation and DM_SETDEFID in the OP and following comments appear to indicate that it's a dialog(-styled) window.
For dialogs, the correct way to move the input focus between child controls is by sending the WM_NEXTDLGCTL message, rather than calling SetFocus directly. As noted in the docs:
This message performs additional dialog box management operations beyond those performed by the SetFocus function WM_NEXTDLGCTL updates the default pushbutton border, sets the default control identifier, and automatically selects the text of an edit control (if the target window is an edit control).
More details at How to set focus in a dialog box, including this part:
As the remarks to the DM_SETDEFID function note, messing directly with the default ID carelessly can lead to odd cases like a dialog box with two default buttons. Fortunately, you rarely need to change the default ID for a dialog.
A bigger problem is using SetFocus to shove focus around a dialog. If you do this, you are going directly to the window manager, bypassing the dialog manager. This means that you can create “impossible” situations like having focus on a pushbutton without that button being the default!
To avoid this problem, don’t use SetFocus to change focus on a dialog. Instead, use the WM_NEXTDLGCTL message.
[EDIT] After the OP edit, the main window turns out to be a regular window, not a dialog. The newly posted code, however, does not remember the focused child (nor does it remove/restore the default pushbutton style) after the main window is deactivated and reactivated, relegates keyboard navigation such as VK_TAB to child controls etc. Those introduce inconsistencies with the default dialog-like behaviors.
In order to make the main window behave like a dialog (and do it right), the WNDPROC would need to mimic the relevant parts of DefDlgProc, at least those that pertain to navigation. From Dialog Box Programming Considerations, among the messages such a WNDPROC would need special handling for are DM_GETDEFID, DM_SETDEFID, WM_ACTIVATE, WM_NEXTDLGCTL, WM_SHOWWINDOW, WM_SYSCOMMAND. Once that's done, my original answer still applies.
I want to add a statusbar to my Win32 application. I found out that I can use CreateStatusWindow function. I works fine until I re-size my window. See a part of my block of code:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
CreateStatusWindow(WS_CHILD | WS_VISIBLE, _T("Welcome to SpyWindows"), hWnd, 9000);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Here are two printscreens of my application main window:
What can I do to have a good status bar? (I also want to divide it in more areas)
The documentation mentions that the status bar will recompute its appropriate position and size when it receives a WM_SIZE message:
The window procedure automatically adjusts the size of the status bar
whenever it receives a WM_SIZE message. Typically, when the size of
the parent window changes, the parent sends a WM_SIZE message to the
status bar.
So, the simplest way to achieve this is to relay to the status bar the WM_SIZE messages received by the parent (with SendMessage(), from its window procedure). The message parameters do not matter, as the status bar does not use them in its computations.
I am having trouble using the function SHAutoComplete. It simply does not work correctly when I use it on a edit box whose parent window is not a dialog box.
The auto-complete functionality seems to be working fine, but the rendering of the drop-down list with the possible candidates based on what was typed on the edit box is very messed up. Basically only the borders of the drop-down are shown. The borders are rendered wide enough to fit the possible suggestions, but the suggestions themselves are never drawn. Even the drop-down list background color is wrong. It is as if it was never painted and remains with the original parent window color.
And if the number of suggestions is big enough so the drop-down needs a scroll-bar, the scrollbar also does not get rendered correctly - the arrows do not get drawn.
On both cases, with or without scrollbars, the drop-down list does not accept mouse input, i.e., I cannot click on the items. If I press the "down" key on the keyboard while the drop-down is being shown, it kind of works as expected. After the second or third press the items finally start to appear. But the scrollbar still is does not get rendered correctly.
If instead of registering my own windows class I simply use a dialog with ::DialogBoxParam(), then it all goes as expected. The auto-complete works without any problems at all.
Here is what I am doing. This code will register a window class, create the main window, create an edit box and then call SHAutoComplete on it. It must be linked with Shlwapi.lib
// this code must be linked with Shlwapi.lib
#include <Windows.h>
#include <Shlwapi.h>
// name of the class that will be created for the main window
static const char WindowClassName[] = "SHAutoCompleteDoesNotWorkWithoutADialogWindowClassName";
// the main window procedure
static LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_CHILD | WS_VISIBLE,
10,
10,
300,
25,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 0;
}
case WM_DESTROY:
::PostQuitMessage(1);
return 0;
default:
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
// the app entry point
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
::CoInitialize(NULL);
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW ;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = WindowClassName;
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
ATOM atom = ::RegisterClassEx(&wcex);
HWND hwnd = ::CreateWindowEx(
0,
MAKEINTATOM(atom),
"SHAutoComplete Test",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
MSG msg;
while(::GetMessage(&msg, hwnd, 0, 0) > 0)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::UnregisterClass((LPCTSTR)atom, NULL);
::CoUninitialize();
return 0;
}
That code produces the following:
the drop-down when a scroll bar is needed
http://www.abload.de/img/shautocomplete_2i1sk4.jpg
the drop-down after a couple of presses to the "down" key. Notice how the scroll bar still is not rendered correctly.
http://www.abload.de/img/shautocomplete_3efsgw.jpg
Now, when I switch to Dialog Boxes, works like a charm. In the code below, IDD_DIALOG1 is simply an empty dialog box resource, created automatically by the IDE.
Here is the relevant part of the rc file
IDD_DIALOG1 DIALOGEX 0, 0, 316, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
And here is the code that uses it
// this code must be linked with Shlwapi.lib
#include <windows.h>
#include <Shlwapi.h>
#include "Resource.h"
BOOL CALLBACK DialogProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_VISIBLE | WS_CHILD,
0,
0,
300,
20,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 1;
}
case WM_CLOSE:
::EndDialog(hwnd, 0);
return 1;
default:
return 0;
}
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
::CoInitialize(NULL);
::DialogBoxParam(
NULL,
MAKEINTRESOURCE(IDD_DIALOG1),
NULL,
DialogProc,
0);
::CoUninitialize();
return 0;
}
Could you please point out where I am going wrong? As far as I can see, other than the creation and destruction of the main window, there seems to be no difference at all between the two of them. Am I missing something on the SHAutoComplete docs that states it can only be used on edit boxes inside dialogs?
You are using a filtered message loop so any messages for the drop down are not being processed. Pass NULL as the second parameter to GetMessage