Set dialog window's border color - c++

The root question here is this: How do I set the color for the border around a window (more specifically, a dialog window)?
I have a dialog window which pops up with an alert. Due to the critical safety nature of the alert, there is a requirement that some parts of the window be red, including the dialog's window-border. When I got this requirement in, I thought it was a good idea. Seems reasonable and simple enough.
The application uses X/motif for its graphics. I started by making other requested parts red, such as the acknowledgement button. Getting everything else done was simple enough by changing graphics contexts and color resources.
The dialog's border, however, has been a pain. There is an XmNborderColor resource, so I tried changing that. It didn't seem to work. Eventually, after trying to set it for different widgets (frame and it's ancestors), I did the following out of desparation:
Widget w = button;
for(int i = 0; i <= 20; i += 1)
{
printf("i = %d, w = %d\n", i, w);
if(w <= 0) break;
XtVaSetValues( w, XmNborderColor, border, NULL);
w = XtParent(w);
}
I did that to just set it on everything from the button to the root and everything between.
After doing some more research, I realized that I might need to be changing the window attributes instead, such as via XChangeWindowAttributes(display, window, mask, values). The structure for the values includes a border_pixel, which I'm assuming is the border color but can't find confirmation on that - documentation just says it's for setting "the border pixel." Fortunately, there is a convenience function for setting just the border pixel so that you do not need to pass an entire values structure; the convenience function that changes only the border pixel is XSetWindowBorder(display, window, border_pixel).
So I wanted to try that. I now have:
// control_area is the widget containing the other
XSetWindowBorder(XtDisplay(shell), window, border);
shell is set elsewhere with the following function:
Widget myClass :: createShell( Widget parent, string title )
{
while( !XtIsApplicationShell(parent) )
{
parent = XtParent( parent );
}
shell = XtVaCreatePopupShell( name, xmDialogShellWidgetClass, parent,
XtNvisual, visual, // visual, colormap, depth are class member variables
XtNcolormap, colormap,
XtNdepth, depth,
NULL );
XtVaSetValues( shell,
XmNmwmDecorations, MWM_DECOR_BORDER,
XtNtitle, const_cast<char*> (title.c_str()),
XmNmwmFunctions, NO_FUNCTIONS,
XmNresizePolicy, XmRESIZE_NONE,
NULL );
return shell;
}
From another place in the code, it looks like window might be a reference to the root window - maybe that's the problem?
I am surprised by the lack of information about this and by how difficult it has been to find a direct answer.
How do I set the border color? If I should be using XSetWindowBorder(), what am I doing wrong? If it's because my window variable might not be referencing the correct window, how do I get the a reference to the correct window knowing the shell and contained widgets (maybe I should make a separate question out of this one if this question doesn't get traction)?

The colour of the border is most likely controlled by your window manager unless you are running without a window manager. You need to override the default colour for that specific window in your ~/.Xdefaults file. Something like:
[title]*bordercolor: red
Where [title] is the same as the string you pass to createShell().

Related

How can I resize an application menu bar in a MFC application?

I am working with MFC and I have created succesfully custom-drawn menus. Each menu-item is measured and drawn correctly, except the mainlevel-items. The only thing I can't get done is redrawing the application menubar.
I attached two images:
The first shows a part of the menubar. The font Consolas 11pt is drawed correct. The width of the buttons is calculated correct, the buttons need to be spread over two rows.
The second image shows the same menubar with font Consolas 20pt. Now the menu needs three rows to contain all menu-items. However, the height for each separate row, is not updated. (while debugging, I see the MeasureItem override calculates the correct height for each menu-item). Below the menubar, there is a toolbar (BCGToolBar), which calculates the correct height for its bar.
So whatever the fontsize is, the Application Menu Bar will never change its height?
How can I resize the application menu bar in this MFC application?
Things I have tried so far is following lines of code in different orders:
RECT barRect;
barRect.top = 0;
barRect.left = 0;
barRect.bottom = 100;
barRect.right = 1020;
m_pMainWnd->RepositionBars(0, 0, 0, 2, &barRect);
m_pMainWnd->GetTopLevelFrame()->RecalcLayout();
m_pMainWnd->DrawMenuBar();
for (POSITION pos = m_pMainWnd->GetTopLevelFrame()->m_listControlBars.GetHeadPosition(); pos != NULL;)
{
CControlBar* controlBar = reinterpret_cast<CControlBar*>(m_pMainWnd->GetTopLevelFrame()->m_listControlBars.GetNext(pos));
controlBar = nullptr; //Let's see what we can do with this. Is the menuBar a ControlBar? Didnt think so.
}
m_pMainWnd->RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);
The first part is not an answer to the direct question but it should clarify why there is no need for it.
The menu is part of the global UI. Also the size of a menu items is part of the global settings.
If the user wants it, he can change the windows settings to get a larger menu.
I don't think it is a good way to change the standard behaviour. A UI should be stable, persistent and consistent. All programs should have the same look and feel. This includes the menu bar.
Now to your question.
You receive the WM_MEASUREITEM message. Respond to it and you can change the height for an onwerdraw menu.
See: http://www.codeguru.com/cpp/controls/menu/article.php/c3719/The-Easiest-Way-to-Code-the-Owner-Drawn-Menu.htm

How does one resize the form(dialog) in a MFC SDI CFormView application?

I've tried
MoveWindow(50,50,150,200,TRUE) in CMyFormView::OnInitialUpdate();
Also, I have tried following code in
CWinApp::InitInstance();
RECT desktop;
const HWND hDesktop = ::GetDesktopWindow();
::GetWindowRect(hDesktop,&desktop);
MoveWindow(hDesktop,0,0,900,400,TRUE);
I am having no luck resizing the form(dialog).
I would appreciate any suggestions.
In an SDI program the dialog is sized by the mainframe window to fill the client area. Resize the frame window and the dialog will follow. Put this in the formview's OnInitialUpdate
AfxGetMainWnd()->MoveWindow(....);
KEY THINGS:
MINIMUM SIZE - YOU SET - The dialog template - or form view - you make IS the absolute minimum size CFormview will use
MAXIMUM SIZE - AUTOMATICALLY SIZED - The dialog template has no maximum. CFormview dynamically stretches it out to fit the CMainFrame window.
STARTING THE APPLICATION TO THE TEMPLATE SIZE
Naturally you might want the CMainFrame window to be as compact as possible, this is achieved using 3 mandatory lines of code in your CFormView::OnInitialUpdate()
void CSimpleSDIView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit(); // FORCES CMainframe to be as small as the dialog template
}
FORCE CMainFrame to LIMIT MINIMUM SIZE - If necessary. Using WM_GETMINMAXINFO Here's the code:
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
lpMMI->ptMinTrackSize.x = 500; // absolute minimum width for CMainFrame
lpMMI->ptMinTrackSize.y = 500; // absolute minimum height for CMainFrame
CFrameWnd::OnGetMinMaxInfo(lpMMI);
}
SET TO IDEAL SIZE This can achieved in CFormView ::OnInitialUpdate by using the following code (Step 3 is still required):
AfxGetMainWnd()->MoveWindow(0, 0, 1024, 600, 1);
TWEAK CONTROL POSITIONS With the advent of the ribbon in MFC things are looking good, but using steps 1 - 5 doesn't work without extra tweaking. Basically, the ribbon sends the main window an extra resize as it would seem, so even if you sent a minimum template size, things get a little out of proportion due to the extra resizing -- mainly because a group within a ribbon can be collapsed into a single icon. ** BEFORE DOING STEP 5** you might want to add the following code:
if(::GetSystemMetrics(SM_CXSCREEN) > 1024)
{
RECT r;
CWnd *someControl = GetDlgItem(IDC_SOMECONTROL);
someControl->GetWindowRect(&r);
ScreenToClient(&r);
r.right += 300;//r.right += 30;
r.bottom += 150;
someControl->MoveWindow(&r)
}
EXPLANATION:
The short answer, you don't! Basically, I had the same issue, made a dialog box template for use in a CFormView derived class. When I wanted to stretch the CMainFrame window out like any normal window, I wanted the content of the formview to resize accordingly. That worked fine with some code, but the problem came when I made the window very small. When I did that, I would get these ugly scrollbars. My thought was the scrollbars were there because they are trying to respect the original dialog template size. That thought is correct! For example, you make your dialog box 500 x 500 and you resize small less than that, you will get scrollbars - since CFormview respects that the application MUST BE AT A MINIMUM 500x500. The minimum size is governed by the template you make and you can not dynamically make it smaller.
Usually, child window's size, position is changed in child's init code.
If you change this in parent window code, you always have to check whether the child window handle value is valid.
I input this code WM_CREATE handler of CAboutDlg.
int CAboutDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
RECT desktop;
const HWND hDesktop = ::GetDesktopWindow();
::GetWindowRect(hDesktop,&desktop);
MoveWindow(&desktop,TRUE);
return 0;
}

How to set a bitmap as the background of a CHILD window (WIN32)

First of all this is not MFC.
Here is a cropped version of the GUI I have been working on:
As you can see there is a bitmap image above the tab control (which uses the default window's handle), I will refer to it as "Blue Bitmap" I have no problems with it, it is functioning perfectly.
The problem I am having is setting another bitmap (from a bitmap file on disk) to the background of the child window (more specifically the tab control child window), replacing the grey colour. Here are some things I did to try and set the bitmap as the background for the child window (the tab).
1) I used the same method as was used to assign the blue bitmap to the window by first importing the bitmap using LoadImage like so:
index->hbmBitmapBanner = (HBITMAP)LoadImage(index->hInstance,L"Images\\horizontal.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
Then in the WM_PAINT message:
case WM_PAINT:
{
PAINTSTRUCT ps1;
if (BeginPaint(WINDOWHANDLE,&ps1))
{
HDC hdcBanner = CreateCompatibleDC(ps1.hdc);
HBITMAP hbmOldHorizontal = (HBITMAP)SelectObject(hdcBanner,index->hbmBitmapBanner); // banner
BitBlt(ps1.hdc,0,0,516,101,hdcBanner,5,0,SRCCOPY);
SelectObject(hdcBanner,hbmOldHorizontal);
DeleteDC(hdcBanner);
EndPaint(WINDOWHANDLE,&ps1);
}
break;
}
That code was successful in setting blue bitmap to the window, but not in setting the other bitmap into the window, (with the blue bitmap's variables substituted into, size and orientation changed as well of course). It simply did not display the bitmap on the screen, and the window remained unchanged, yet no functions failed. ALSO, when I swapped the file locations around, it loaded the bitmap into where the blue bitmap was, so there is definitely no failure in the loading function.
2) Using the above code, I tried changing the first argument of BeginPaint to the window handle of the tab control box, this proved yet again of no use, and the window remained unchanged. I also tried changing the first argument of BeginPaint to a child window which is displayed on the information tab, this caused the child window (which is a groupbox) to disappear, yet still no bitmap appeared on the window.
3) As a last resort I stupidly attempted to use this function on the child window
SetClassLongPtr(tab->hTabIndex[0],GCLP_HBRBACKGROUND,(DWORD)GetStockObject(BLACK_BRUSH));
And of course, it didn't work
If it is of any use, here is how I created the tabbing in my window:
TCITEM tie = {0};
tab->hTab = CreateWindowEx(0,WC_TABCONTROL,L"",WS_CHILD | WS_VISIBLE,0,101,600,400,
WINDOWHANDLE,NULL,(HINSTANCE)GetWindowLong(WINDOWHANDLE,GWLP_HINSTANCE),NULL
);
Is the main tab control, followed by inserting individual the tabs (i.e the information tab)
TCHAR pszTab1 [] = L"Information"; // tab1's text
tie.pszText = pszTab1; // the tab's text/caption
TabCtrl_InsertItem(tab->hTab, 0, &tie); // insert the tab
Additional info: The tab control, and the windows are working/interacting perfectly apart from this. I was testing/attempting this for only one tab, because I knew if it worked on one tab, then it would work on all the tabs, hence saving time.
I have Programming For Windows Fifth Edition, by Charles Petzold beside me as reference, and there is a rather large section on bitmaps, but he doesn't go into talking about loading a bitmap to a child window, the closest he gets is using a bitmap in a menu, which is completely different than a window.
I think that the issue here is that Windows Common Controls do not interact with your application via your main thread's window procedure but via their own (system-defined) window procedures.
So, for example, when your tab window redraws itself, it does not do so in response to a WM_PAINT message arriving at the window procedure defined in your code. You should be able to verify for yourself that this is so by examining the window handles of messages passed to your window procedure, eg WM_PAINT.
If you wish to 'tap into' the default behaviour of a common control you have to 'subclass' it (see here) but in my experience attempting to change the re-draw behaviour is generally problematic.
In the case of a tab control the best thing to do is create an array of child windows sized to the client area of the tab control and arrange that the one displayed at any one time corresponds to the tab that is selected.
If you're using C++ you might consider creating a base class to wrap these windows in which the background (bitmap) drawing is handled. You can then derive a series of wrappers to handle each individual tab. I've used exactly this approach in the past and it works well.
It may be helpful to bear in mind that the tabs of the tab control do not extend over the whole of the control's client area but are just literally the tabs themselves. I don't remember the details but I think they are handled internally by the control and that manipulating them in any way is rather trick, even when the control is subclassed - may be wrong about that.
Hope that helps.
Cheers, Ian.

C++/CLI Visual C++ 2010 Express - Drawing different shapes inside one panel

I got a problem. There is panel1 which i want to use as my paiting window. And i also have 2 buttons. One should draw "fillRectangle" in the middle of panel and second one should draw "fillellipse" next to it. I dont have the problem with drawing itself
Color aColor = Color::FromArgb( 255, 0, 0 );
SolidBrush^ aBrush = gcnew SolidBrush(aColor);
Rectangle rect = Rectangle(x, y, 10, 10);
e->Graphics->FillEllipse(aBrush, rect);
But i want to know, how to make that pressing each button draws different shape inside panel. Do i need to put both, ellipse and rectangle in panel1_Paint and use flags like...
if(ellip == 1) FillEllipse;
if(recta == 1) FillRectangle
which are set using buttons? I hoped i can code drawing part inside button or function, and then somehow refer to that panel. Is it possible?
If you want the buttons to have their own painting routines, then they draw themselves and your panel is unnecessary, in terms of drawing anyway, they'll have their own canvas.
If you want a panel that draws shapes on itself dependant on some property, then yes you go down something like the route you suggested, though I'd be tempted by some sort of shape class even if it wasn't a control. Would make adding other shapes or more of a shape much easier.
You could have panel carry a collection of shapes that implement say IDraw which takes a Graphics reference, and then just iterate through them and call it with Panel1's graphics instance.
If it was me though particulary if I wanted enabled, visible, tab, click etc. I'd have a ShapedButton Control.

Automatically display vertical scrollbar in multiline text edit control

On a windows mobile device I have a mutliline text edit control that is set to read-only and has some static text displayed during it's display lifetime. I would like to only display a vertical scrollbar when it's actually useful (i.e. the text is larger than the display).
I can't easily figure out if the text is to large to display because of two reasons.
There is no horizontal scroll bar displayed so the text wraps.
Under windows mobile, the win32 routines to calculate the size of what text will display does not work correctly. They return a incorrect rectangle.
The edit control must tell the scroll bar what it's scroll range is at some point. I was wondering if I could get in between then and hide the scroll bar if it's not going to be used.
This is how I solved this problem.
First off:
It only works with read-only mode of a edit control (as you don't want the text to change often).
I think is specific to Windows Mobile MFC, big windows can handle this a lot better.
The solution is very very hacky.
Solution:
I have a standard CEdit bound to the control.
CEdit m_Message;
DDX_Control(pDX, IDC_MESSAGE,
m_Message);
During the InitDialog and OnSize calls, turn on the display of the scroll bar and setup a timer message.
m_Message.ShowScrollBar(SB_VERT,
TRUE);
SetTimer(DO_ADJUST_DISPLAY_STATE, 50,
0);
In the timer handling code, use the scroll information to determine if the scroll bar needs to be displayed.
If not being displayed, turn off the scroll bar and force the window to redisplay.
void CMessageDlg::OnTimer( UINT_PTR nIDEvent )
{
switch(nIDEvent)
{
case DO_ADJUST_DISPLAY_STATE:
KillTimer(nIDEvent);
// deselect all text
m_Message.SetSel(0, 0);
SCROLLINFO info;
m_Message.GetScrollInfo(SB_VERT, &info);
if(info.nPage > (UINT)info.nMax)
{
// need to re-display the non scroll bar version
m_Message.ShowScrollBar(SB_VERT, FALSE);
// I could not find any other way to force a redisplay
// correctly without display problems...
// first move the window to a know invisible area
// then wait (using a timer) for the window to move
// then move the window back to it's original position
RECT rt;
rt.left = 0;
rt.right = 5;
rt.top = 0;
rt.bottom = 5;
m_Message.MoveWindow(&rt);
SetTimer(DO_REDISPLAY_MESSAGE, 50, 0);
}
break;
case DO_REDISPLAY_MESSAGE:
KillTimer(nIDEvent);
// m_MessagePosition holds the original position
// worked out dynamically during the WM_SIZE
// processing
m_Message.MoveWindow(&m_MessagePosition);
break;
}
}
I hope that helps out other people who may have similar requirements.
I was wondering if I could get in between then and hide the scroll bar if it's not going to be used.
I highly doubt it. But I bet you could call SetScrollInfo some time after the text box is created, and send your own scroll parameters.
EDIT: Wrong link, my bad. Here's the one for the Windows CE