I have built an application that adds on-screen application help in context of an windows desktop application. When the object of help relates to a drop-down menu I am encountering problems that the drop-down menu disappears when adding a transparant overlay. What attributes should I use to keep the drop-down menu visible? Please see the following code where I define the window to draw on top of the current foreground window:
exStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT
style = win32con.WS_DISABLED | win32con.WS_POPUP | win32con.WS_VISIBLE
oWindow = win32gui.CreateWindowEx(
exStyle,
owndClassAtom,
'Per52Overlay', # WindowName
style,
winX1, # x
winY1, # y
#win32api.GetSystemMetrics(win32con.SM_CXSCREEN), # width
#win32api.GetSystemMetrics(win32con.SM_CYSCREEN), # height
winWidth, #width
winHeight, #height
hwnd, # hWndParent
None, # hMenu
hInstance,
None # lpParam
)
oWindowHndl = oWindow
# //msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx
win32gui.SetLayeredWindowAttributes(oWindow, 0x00ffffff, 255, win32con.LWA_COLORKEY | win32con.LWA_ALPHA)
hdc, paintStruct = win32gui.BeginPaint(oWindow)
hPen = win32gui.CreatePen(win32con.PS_SOLID,3, win32api.RGB(0,255,0))
win32gui.SelectObject(hdc, hPen)
win32gui.Rectangle(hdc, objX1, objY1, objX2, objY2)
win32gui.EndPaint(oWindow, paintStruct)
win32gui.SetWindowPos(oWindow, win32con.HWND_TOPMOST, winX1, winY1, winWidth, winHeight, win32con.SWP_DRAWFRAME | win32con.SWP_NOACTIVATE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
win32gui.ShowWindow(oWindow, win32con.SW_SHOW)
win32gui.UpdateWindow(oWindow)
At some stage the window shall be drawn:
winCrd = win32gui.GetWindowRect(activeWindow)
objCrd = (startX, startY, endX, endY)
drawOnApp(activeWindow, winCrd, objCrd, message)
win32gui.BringWindowToTop(activeWindow)
My guess is that I am doing something wrong with the attributes in combination with what window should be on top / activated / to foreground etc. etc.
Can you give me some clues to dive more in this matter?
Related
I have a windows application in which I am trying to create a status bar at the bottom of a PropertyPage. I have added a member variable of type CStatusBarCtrl named m_StatBar in the derived propertypage class.
Here is the code in the OnInitDialog of the PropertyPage
enter code here
int nTotWide; // total width of status bar
CRect rect3;
this->GetWindowRect(&rect3);
rect3.top = rect3.bottom - 70;
int m_bRvStatOk = m_StatBar.Create(WS_CHILD | WS_BORDER | WS_VISIBLE, rect3, this,IDC_STATUSBAR);
if (m_bRvStatOk == NULL)
{
AfxMessageBox("Status Bar not created!", NULL, MB_OK);
}
// get size of window, use to configure the status
// bar with four separate parts
nTotWide = rect3.right - rect3.left;
//
// Make each part 1/4 of the total width of the window.
//
m_Widths[0] = nTotWide / 4;
m_Widths[1] = nTotWide / 2;
m_Widths[2] = nTotWide - m_Widths[0];
m_Widths[3] = -1;
m_StatBar.SetMinHeight(70);
m_StatBar.SetParts(4, m_Widths);
m_StatBar.SetText("TEXT WITH BORDER.", 0, 0);
m_StatBar.SetText("TEXT WITHOUT BORDER.", 1, SBT_NOBORDERS);
m_StatBar.SetText("TEXT POPUP.", 2, SBT_POPOUT);
I am not able to change the height of the status bar.
appreciate any help on the same.
You cannot set the height of a status bar. However, you can request a minimum size by sending an SB_SETMINHEIGHT message to the control (which is what the CStatusBarCtrl::SetMinHeight implementation does).
This is not enough for the system to pick up the requested minimum height, though. While the MFC documentation doesn't provide any help or hint, the SB_SETMINHEIGHT documentation has the following remark:
An application must send the WM_SIZE message to the status window to redraw the window. The wParam and lParam parameters of the WM_SIZE message should be set to zero.
This translates to the following MFC implementation:
m_StatBar.SetMinHeight(70);
m_StatBar.SendMessage(WM_SIZE); // wParam and lParam have default arguments set to 0
I consider using an owner draw menu in a Windows application that should have the same look as the standard menu. (Reason: the standard menu doesn't work well in some mixed DPI situations.)
Currently I have a problem providing the correct width during WM_MEASUREITEM.
This is a screenshot of the Edit menu of notepad where each item has a shortcut.
We can see that there is a constant gap between the item texts and shortcut texts as if they were columns. It seems as if the widths of the item texts and the widths of the shortcut texts are retrieved separately, as the longest item text "Time/Date" reserves a shortcut width suitable for Ctrl+A while it only needs one for F5.
I could not find any API functionality where I can give the width of the item text and the shortcut text separately, nor did I find any metric specifying the size of the gap.
So my question is: Is it possible to achieve the desired behavior within the usual WM_MEASUREITEM message and if yes, how? If not, is there any other means to get this right or is it just not possible at all?
This is how ReactOS does it:
To measure a menu item:
if ((p = wcschr( lpitem->Xlpstr, '\t' )) != NULL) {
RECT tmprc = rc;
LONG tmpheight;
int n = (int)( p - lpitem->Xlpstr);
/* Item contains a tab (only meaningful in popup menus) */
/* get text size before the tab */
txtheight = DrawTextW( hdc, lpitem->Xlpstr, n, &rc,
DT_SINGLELINE|DT_CALCRECT);
txtwidth = rc.right - rc.left;
p += 1; /* advance past the Tab */
/* get text size after the tab */
tmpheight = DrawTextW( hdc, p, -1, &tmprc,
DT_SINGLELINE|DT_CALCRECT);
lpitem->dxTab += txtwidth;
txtheight = max( txtheight, tmpheight);
txtwidth += MenuCharSize.cx + /* space for the tab */
tmprc.right - tmprc.left; /* space for the short cut */
}
Then to draw it:
Text = lpitem->Xlpstr;
if(Text)
{
for (i = 0; Text[i]; i++)
if (Text[i] == L'\t' || Text[i] == L'\b')
break;
}
if(lpitem->fState & MF_GRAYED)
DrawTextW( hdc, Text, i, &rect, uFormat);
/* paint the shortcut text */
if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
{
if (L'\t' == Text[i])
{
rect.left = lpitem->dxTab;
uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
}
else
{
rect.right = lpitem->dxTab;
uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
}
DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
}
So to insert a keyboard accelerator in a menu item, you simply separate it from the item text with the tab character. The measuring and drawing code then looks for this tab character and acts accordingly.
Note, however, that for the keyboard accelerator to be right-aligned in the menu like it is in your screenshot (which is achieved with DrawText with DT_RIGHT) the drawing code expects it to be separated from the item text with the '\b' character, not the tab character, and unless I'm missing something this is not accounted for in the measuring code, so you might want to compensate for that.
Replicating the standard menu with owner draw is a world of pain. You have to deal with Visual Styles on and off, mnemonics/Access keys, accessibility and all the undocumented metrics. It is better just to use the normal menu if you can.
Per-monitor DPI support seems to change in every Windows 10 release. 1607 added EnableNonClientDpiScaling which scales the menu and other non-client areas. 1703 added Per Monitor v2 and MSDN says this about PMv2:
Scaling of non-client area - All windows will automatically have their non-client area drawn in a DPI sensitive fashion. Calls to EnableNonClientDpiScaling are unnecessary.
Scaling of Win32 menus - All NTUSER menus created in Per Monitor v2 contexts will be scaling in a per-monitor fashion.
Notepad is PMv2 and its menu seems to work fine:
Windows 8.1 and < 10 Anniversary Update will require more work and I would suggest that you just don't declare yourself DPI aware on these systems and let Windows scale your window for you (with some blurriness) if the system has multiple monitors.
I have Listbox with LBS_OWNERDRAWVARIABLE style, and trying resize items height with WM_MEASUREITEM on WM_SIZE.
I wrote code next in WM_SIZE procedure, referred http://www.codeproject.com/Articles/1401/Changing-Row-Height-in-an-owner-drawn-Control :
WINDOWPOS wp;
ZeroMemory (&wp, sizeof(WINDOWPOS));
wp.hwnd = hwndListbox;
wp.cx = iWidht;
wp.cy = iHeight;
wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
// WM_WINDOWPOSCHANGED for force generate WM_MEASUREITEM:
SendMessage (hwndListbox, WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
however, It dosen't work... (dosen't generate WM_MESUREITEM.)
Question: How to force generate WM_MESUREITEM, or Resizing of items height dynamically?
p.s I using C++ with Win32, not MFC.
Use the LB_SETITEMHEIGHT message to change the height of listbox items.
I create a single xlib window with the relevant code below. When I try to move the window, the cursor briefly changes to the grab cursor and I am unable to drag the window. However, if I change focus to another app, then return to my app, I am able to drag the window. I am new to xlib, and don't understand why I cannot drag the window after creation?
ms_display = XOpenDisplay(NULL);
int screen = DefaultScreen(ms_display);
Window rootWindow = RootWindow(ms_display,screen);
XSetWindowAttributes windowAttrib;
windowAttrib.background_pixel = 0;
windowAttrib.border_pixel = 0;
windowAttrib.colormap = XCreateColormap(ms_display,rootWindow,m_visual,AllocNone);
windowAttrib.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | PointerMotionMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask;
int width = m_displayInfo.m_windowWidth;
int height = m_displayInfo.m_windowHeight;
unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
ms_window = XCreateWindow(ms_display,rootWindow,0,0,width,height, 0, pVisInfo->depth,
InputOutput,pVisInfo->visual,mask,&windowAttrib);
XMapWindow(ms_display, ms_window);
XFlush(ms_display);
XSizeHints sizeHints;
sizeHints.x = (WidthOfScreen(ScreenOfDisplay(ms_display, screen)) - width) / 2;
sizeHints.y = (HeightOfScreen(ScreenOfDisplay(ms_display, screen)) - height) / 2;
sizeHints.width = width;
sizeHints.height = height;
sizeHints.flags = USPosition | USSize;
XSetWMSizeHints(ms_display,ms_window,&sizeHints,XInternAtom(ms_display,"WM_SIZE_HINTS",False));
XMoveResizeWindow(ms_display,ms_window,sizeHints.x,sizeHints.y,width,height);
I did run into a somewhat similar situation, where a newly created window would not get focus, receive mouse clicks or keyboard input until I called XSetWMHints(), even with a completely empty structure, e.g. the following was enough to get it working:
XWMHints xwmh;
xwmh.flags = 0;
XSetWMHints (m_display, m_window, &xwmh);
Weird, but it solved my problem.
How can you create a window without caption and border using CreateWindowEx()? And I why do you use '|' OR operator to combine styles instead of '&' And?
int WINAPI WinMain(....)
{
MSG msg;
WNDCLASS wc={0};
wc.lpszClassName="MyClass";
wc.lpfnWndProc=DefWindowProc;//You MUST use your own wndproc here
wc.hInstance=hInstance;
wc.hbrBackground=(HBRUSH)(COLOR_3DFACE+1);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
if (!RegisterClass(&wc)) {/*Handle Error*/}
HWND hwnd;
hwnd=CreateWindowEx(0,wc.lpszClassName,0,WS_POPUP|WS_VISIBLE|WS_SYSMENU,9,9,99,99,0,0,0,0);
if (!hwnd) {/*Handle Error*/}
while(GetMessage(&msg,0,0,0)>0)DispatchMessage(&msg);
return 0;
}
If you want a border, you can add WS_BORDER or WS_DLGFRAME (Not both). If you don't want to show the window in the taskbar, add the WS_EX_TOOLWINDOW extended style.
As to why you need to bitwise OR the styles; OR will combine all the style values, AND is used (by windows) to check which styles are set.
Say we had two styles (WS_FOO=1,WS_BAR=2):
1 AND 2 = 0 (Binary: 01 AND 10 = 00)
1 OR 2 = 3 (Binary: 01 OR 10 = 11)
See wikipedia for more info.