I am really struggling how to make a window with three selections of options. I currently have a setup that uses a CFileDialog object and have successfully implemented two dropdown menus and multiple check items.
What I want is to implement a pop up window that has the two drop down menus and the check boxes. If a certain item is selected in one of the dropdown menus then the file dialog is opened.
Currently I am trying to make a CWnd object and try to write code for it there.
CWnd myWindow;
BOOL VALUE = myWindow.Create(_T("DesktopApp"), _T("test"), WS_VISIBLE | WS_BORDER | WS_CAPTION,
RECT{ 100,100,400,400 },
myWindow.GetDesktopWindow(), 12);
myWindow.ShowWindow(SW_SHOWNORMAL);
if (VALUE == FALSE) {
return 0;
}
Every time I run this, it prematurely returns (VALUE == FALSE). Did I do something wrong? Is there a simpler way to create a window?
The first argument to CWnd::Create is the window class name. A class with the requested name must have been registered before it can be created.
It is common to register an application local class for the application's main window. MFC provides a convenient wrapper function (AfxRegisterWndClass) to register a window class.
Related
I'm fairly new to MFC and would like to create an SDI application that has a pane of tabs always embedded on the right of the window with a view left of it. In my app I have a calculation core, with variables that are changed in the tabs with edit boxes. I would like to initialise these variables in the calculation class and then during the initialisation of the dialogs used for tabs set the initial values in the edit boxes to those of the corresponding variable in the calculator.
Currently, I create an instance of the calculator in my document class.
I also create a CTabbedPane in the MainFrame OnCreate Method as follows:
m_TabbedPane.Create(_T(""), this, CRect(0, 0, 290, 200),
TRUE,
(UINT)-1,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
WS_CLIPCHILDREN | CBRS_RIGHT |
CBRS_FLOAT_MULTI))
m_tab = new CParametersDlg();
m_tab->Create(IDD_TAB, this);
m_TabbedPane.AddTab(m_tab);
I would the like to be able in CParameterDlg's OnInitDialog do something like:
BOOL CParameterDlg::OnInitDialog() {
CDialog::OnInitDialog()
float value = pointerToDocument->GetCalculatorVariable();
And use value to initialise an edit box. However I can't access the document from in the main frames OnCreate as it returns null (using GetActiveDocument, AfxGetApp etc).
How can I initialise the tabs then? I have thought about trying to put the Calculator in the App class instead. Or possibly trying to initialise the dialogs somewhere else which is called later when the document is properly initialised and linked? Or should I be doing things entirely differently?
I think that CMainFrame::OnCreate() is too early in the sequence of events to access the document class, it would not normally be created yet.
It would be better to wait until the docuent is created / initialised, the document class could then call a new method in CMainFrame() passing this as a parameter to create the tabs.
I am stuck. I have just a little experience with MFC and inherited a MFC program from a former coworker.
I want to add a list of available com ports in the menu bar, so the user can select whatever he wants. During the further runtime of the program, this menu should be locked.
I already created the Menu and added it to my Dialog. But:
How can I dynamically show the list of available com ports during the initialization?
How can I figure out which Port was selected? Is there something. like a return value?
Actually the second question bugs me the most.
Edit1:
to be more clear: I already know how to get the list of available com ports and currently I am displaying them in a combo box. But I want to do it with a Menu instead.
Edit2: This is what I got so far. Question 1 is solved!
//create a menu object for main menu
CMenu *menu = new CMenu();
menu->CreateMenu();
//another menu object for submenu
CMenu *subMenu = new CMenu();
subMenu->CreateMenu();
//create subsubmenus
CMenu *ComPortSelect = new CMenu();
CMenu *ModeSelect = new CMenu();
ComPortSelect->CreateMenu();
ModeSelect->CreateMenu();
//append available ports (portlist created earlier)
for (INT_PTR i = 0; i < portlist.GetCount(); i++)
{
ComPortSelect->AppendMenu(MF_POPUP, ID_SHOW, portlist[i]);
}
ModeSelect->AppendMenu(MF_POPUP, ID_SHOW, _T("User"));
ModeSelect->AppendMenu(MF_POPUP, ID_SHOW, _T("Expert"));
//append subsubmenu to submenu
subMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT)ComPortSelect->m_hMenu, _T("ComPorts"));
subMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT)ModeSelect->m_hMenu, _T("Mode"));
//append submenu to menu
menu->AppendMenu(MF_POPUP | MF_STRING, (UINT)subMenu->m_hMenu, _T("Advanced"));
SetMenu(menu);
I played with interfacing a program to an Arduino some time ago. Different models of Arduinos that I had used different COM ports so I also had a need to scan for available ports.
I forget the exact ins and outs of it now, but you an use one syntax when opening COM ports upto about 8 or 10 I think, and a different one for any higher numbered ports. Fortunately, the syntax that works for higher numbered ports also works for the lower numbered ones - my code uses the higher-numbered port syntax and works fine for both.
The code I used for a non-mfc win32 project follows:
void initPortCombo(HWND combo)
{
int curPort;
char mPortName[16];
HANDLE hCom;
for (curPort=1; curPort<=20; curPort++)
{
sprintf(mPortName, "\\\\.\\COM%d", curPort);
hCom = CreateFile(mPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (hCom != INVALID_HANDLE_VALUE)
{
sprintf(mPortName, "COM%d", curPort);
CloseHandle(hCom);
SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)mPortName);
}
}
}
As for your second question, when you dynamically add a menu option, you need to specify the ID that the menu item has. So with that in mind, when your WM_COMMAND handler fires, you simply need to reverse the logic you used at the time you added the menu items.
For instance, if you assign the menu items an ID of (4000 + com_port_number), you can subtract 4000 from the ID of the control that fired the WM_COMMAND handler. If this results in a valid number (I guess from 1 to 20 or whatever port number you scan up to) then you know it was the menu item that corresponds to one of your com-ports.
Just have a play with adding dynamic menu items and then determining which one was selected. I dont MFC, so cant help you there.
One way to find the installed COM ports is to call the GetDefaultCommConfig API. There is some sample code for this at http://www.naughter.com/enumser.html
When a menu command is selected by the user you receive a WM_COMMAND message from the menu, with parameters that include the ID of the chosen menu item. You put an ON_COMMAND_RANGE statement in your message map to route these messages to a message handler function.
I am new to MFC & BGCControlBar.
Now I plan to use CBCGPListCtrl which is defined as:
class BCGCBPRODLLEXPORT CBCGPListCtrl : public CListCtrl
&
CBCGPListCtrl m_wndWatch;
Now in the demo code I plan to change:
int CWatchBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CBCGPDockingControlBar::OnCreate(lpCreateStruct) == -1)
return -1;
m_Font.CreateStockObject (DEFAULT_GUI_FONT);
CRect rectDummy;
rectDummy.SetRectEmpty ();
// Create output pane:
const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_VSCROLL | LVS_REPORT | LVS_EDITLABELS ;
m_wndWatch.Create (dwStyle, rectDummy, this, ID_LIST_1);
m_wndWatch.SendMessage (LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_wndWatch.InsertColumn (0, _T("Variable"), LVCFMT_LEFT, 100);
m_wndWatch.InsertColumn (1, _T("Value"), LVCFMT_LEFT, 100);
m_wndWatch.InsertItem (0, _T("m_nCount"));
m_wndWatch.SetItemText (0, 1, _T("100"));
m_wndWatch.SetFont (&m_Font);
return 0;
}
What I get is a list(as in pic), I can only edit the 1st colum and the data can not be retained. How can I edit the second column text and make the data retainable?
You need a grid control rather than a CListCtrl (or derived class). Actually, it's possible to add support for edition in other columns but it's a looooooot of work and not the kind of thing I'd recommend to a newcomer.
According to this page of their web site, they have a grid control.
There are a few things you need to do in order to make a MFC CListCtrl editable. This is a very broad overview without going into too many details:
As mentioned above it is quite a bit of work and you need to derive a class from CListCtrl, since CListCtrl by itself does not allow you to explicitly edit all of the columns.
You need a routine that will calculate the row/column number of the particular cell you clicked on, given a cursor position CPoint.
In the derived CListCtrl class you also need a method to edit the selected cell, creating and making visible a CEdit control of the appropriate size.
Create a derived CEdit control, such that it sends the LVN_ENDLABELEDIT message and self-destructs upon completion.
An example Visual Studio 2010 project implementing an editable list control is downloadable from this site:
http://www.technical-recipes.com/2014/making-a-mfc-list-control-editable/
Upon running/debugging the example, you get an example dialog project implementing an editable list control as shown:
I'm using CMenu::ModifyMenu in the OnCreate method of my CFrameWnd derived class to change the captions on my menu to match the user language.
I'm using VC++ designer and the menu is declared in a .rc file.
For the MENUITEM elements I use it as follow:
m_wndMenu->ModifyMenu(ID_APP_EXIT, MF_BYCOMMAND, NULL, CString((LPWSTR) ID_APP_EXIT));
For the POPUP elements (that don't have an ID) I use it as follow:
m_wndMenu->ModifyMenu(0, MF_BYPOSITION | MF_STRING, NULL, CString((LPWSTR) ID_MENU_POPUP_FILE));
It works as expected to change the captions, but for the menu items that are initialy disabled when I change the caption they get enabled. How do I fix this?
You may have to explicitly disable the menu item and set tool tip text after a call to ModifyMenu. Using ModifyMenu will effectively destroy the previous menu item and create a new one. You are losing any settings and initialization from the resource file or otherwise that you had on the previous item or menu.
See remarks: http://msdn.microsoft.com/en-us/library/4tbfebs6(v=vs.80).aspx
for such scenario, better to use EnableMenuItem function, like this
m_wndMenu->EnableMenuItem(ID_APP_EXIT, MF_BYCOMMAND| MF_ENABLED);
this will work...
I am using a QWinWidget inside of an MFC dialog and the QWinWidget is not drawing itself correctly and it is not handling keyboard input correctly.
Repainting [Unsolved]
Within the QWinWidget, I have a QTableWidget. When I scroll the QTableWidget, it does not redraw itself until I stop scrolling, at which point it redraws everything. Similarly, I can type into cells in the QTableWidget and the control is not updated until I force it to re-update by scrolling up or down (it re-updates when the scrolling stops).
Since this QWinWidget is housed in an MFC CDialog, I tried overriding the CDialog's OnPaint method and only call the QWinWidget::repaint method, however this has the opposite problem where now only the QWinWidget is updated and the CDialog is never redrawn, resulting in artifacts. If I call QWinWidget::repaint and CDialog::OnPaint, the result is the same as not overriding the OnPaint method. Has anyone ever seen this problem or know how to resolve it?
Keyboard Input [Solved]
None of the controls within the QWinWidget respond to the tab key or arrow keys correctly. The tab/arrow keys simply skip over the entire QWinWidget (and all child controls). Even if I click inside the QWinWidget and select a control, the next time I press the tab key, it skips the focus completely out of the entire QWinWidget.
I noticed that the QWinWidget has two functions, QWinWidget::focusNextPrevChild and QWinWidget::focusInEvent and both of them have a comment header saying "\reimp". Am I supposed to override these functions in order to get correct tab functionality? If so, how can these functions be implemented for correct tab functionality.
I have fixed the keyboard input issue. The QWinWidget class needed some changes:
in the QWinWidget::init method, the WS_TABSTOP must be added to the window style:
SetWindowLong(winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP);
Also, the QWinWidget::winEvent method needs to respond to the WM_GETDLGCODE to let Windows know that it is interested in receiving key/tab inputs. I had to add this if block:
if(msg->message == WM_GETDLGCODE)
{
*result = DLGC_WANTARROWS | DLGC_WANTTAB;
return(true);
}
I am still working on getting the widget to paint properly.
I don't know about whether you need to reimplement the focusNextPrevChild() and focusInEvent() functions, but I do know that the "\reimp" in the comment header is part of Qt's documentation generation, which merely specifies that the function was a reimplementation of another function in a parent class.
Thanks! It works for me! I have fixed an arrow keys navigation issue for a QTableView inside a QWinWidget.
I am using Qt5.3.0 and qtwinmigrate 2.8.
The QWinWidget::nativeEvent method needs to be modified.
#if QT_VERSION >= 0x050000
bool QWinWidget::nativeEvent(const QByteArray &, void *message, long *result)
#else
...
{
...
if (msg->message == WM_SETFOCUS) {
...
} else if (msg->message == WM_GETDLGCODE) {
*result = DLGC_WANTALLKEYS;
return true;
}
return false;
}
No idea about the keyboard input, but concerning the repainting: have you tried calling QWinWidget::repaint() in the CDialog's OnPaint method AFTER calling the CDialog::OnPaint()?