Why can't I add a string to a combo box? - c++

This seems trivial, but with MFC I always end up with some stupid trivial problem that puts a stop to my workflow.
I am getting a "Debug Assertion Failed" error pointing to afxcmn2.inl line 352:
_AFXCMN_INLINE int CComboBoxEx::AddString(LPCTSTR lpszString)
{ UNUSED_ALWAYS(lpszString); ASSERT(FALSE); return CB_ERR;}
I am attempting to just add some strings to a combo box on initialization like so:
BOOL myDialog::OnInitDialog()
{
CDHtmlDialog::OnInitDialog();
cb_direction.AddString(CString("North"));
}
Most of the answers on Google seem to suggest that the AddString is happening before OnInitDialog, which doesn't seem to be the case here. Another series of answers on Google suggests the data exchange isn't happening or it's wrong, but it's not:
void myDialog::DoDataExchange(CDataExchange* pDX)
{
CDHtmlDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_WHEDIT_DIR, cb_direction);
}
Another suggestion was that the combo box hasn't been created yet, but if I disable the combobox using the following code, not only do I NOT get an error, but it actually works and disables the box!
BOOL myDialog::OnInitDialog()
{
CDHtmlDialog::OnInitDialog();
cb_direction.EnableWindow(FALSE);
}
I've cleaned the solution and rebuilt it. I'm not sure what else I am missing. And all I want to do is to add a string to a combo box, which would take 2 seconds in .Net (this program that was written years ago by someone else which is why it's in MFC rather than .Net, but I digress).

Entering the game a little late but, who knows, this might help someone someday:
COMBOBOXEXITEM item;
ZeroMemory(&item, sizeof(item));
item.mask = CBEIF_TEXT;
item.iItem = 0;
item.pszText = _T("Hello");
m_ComboEx.InsertItem(&item);
FWIW, AddString() functionality is removed from CComboEx because the purpose of the control is to display advanced items (with images, identation, whatever...), not straight regular text items.

Well if you look at what the method is doing they have an ASSERT(FALSE) in there, so no wonder. It doesn't actually do anything that would indicate it adds an item to the ComboBoxEx control. Per the docs
This function is not supported by the Windows ComboBoxEx control. For more information on this control, see ComboBoxEx Controls in the Platform SDK.
The documentation is your friend :)

Related

MFC's CTabCtrl::HitTest function returns "1" for any tab clicked

Hi (although greeting usually gets deleted),
I'm using the MFC's CTabCtrl control and try to determine which tab was clicked (to drag & drop it later). Should be quite easy I thought - anyway got stuck with the HitTest function which returns "1" for whichever tab is clicked.
As I started the project very recently, it's literaly just a handful of lines. The mentioned HitTest function is used in Tdi.cpp file in CHlavniOkno::CTdi::OnLButtonDown function (full source code at http://nestorovic.hyperlink.cz/cpp_mfc.zip ):
afx_msg void CHlavniOkno::CTdi::OnLButtonDown(UINT flagy,CPoint bod){
if (::DragDetect(m_hWnd,bod)){
TCHITTESTINFO hti={bod};
if (int idZalozky=HitTest(&hti)>=0)
parametryTazeneZalozky=new TParametryTazeneZalozky(this,idZalozky);
}
CTabCtrl::OnLButtonDown(flagy,bod);
}
I definitely must have omitted something tiny, as is almost always the case...
Thanks for your time by having a look at the problem.
Tomas
The statement int idZalozky=HitTest(&hti)>=0 is setting idZalozky to the result of the test HitTest(&hti)>=0. As a boolean test this will always return either 0 or 1.
You probably want:
int idZalozky=HitTest(&hti);
if (idZalozky>=0)
{
...
}

Add accelerator ctrl+F for text search

I am trying to add a Ctrl+F accelerator to my gtkmm textview program. I already implemented the search function into an gtk Entry field, so the only thing I need is to get focus the find entry when Ctrl+F is pressed.
I googled and checked tutorials/reference of gtkmm (2.4, I'm working with that) but the only things I found were accelerators in context with menus and toolbars using UIManager, which I don't have in that .cc file I use (and I can't add them, cause its an existing program).
I tried to add an action with an AccelKey on a button or tried the function add_accelerator() but I wasn't able to use them properly (I am pretty new to gtkmm and there aren't enough samples - at least none I understand). Here some examples I tried:
_gtkActionGroup->add(
Gtk::Action::create("find", "Find", "search in file"),
Gtk::AccelKey("<control>F"),
sigc::mem_fun(this, &SrcFilesView::onGtkTxtFindAccKeyPressed));
I didn't know how to add this action to the button (in the toolbar) I created...
_gtkAccelGroup(Gtk::AccelGroup::create()) //initialized in the constructor of the class
...
_gtkBtnFind.add_accelerator("find", _gtkAccelGroup, GDK_Find,
Gdk::ModifierType::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
I tried here something, but I didn't really understand neither the parameters I needed to enter here nor how this method works - ofc it didn't work...
I'd be really happy if anyone can explain me how this things work properly and sorry for my bad english. If there are any things you need just tell me please. Thanks in advance
Greetings
edit: I looked up in the gtk sources and tried to understand the parameters of add_accelerator. Now I tried this but still doesn't work...:
_gtkBtnFind.add_accelerator("clicked", _gtkAccelGroup, GDK_KEY_F /* or better GDK_KEY_f ?*/,
Gdk::ModifierType(GDK_CONTROL_MASK), Gtk::AccelFlags(GTK_ACCEL_VISIBLE));
_gtkBtnFind.signal_clicked().connect(
sigc::mem_fun(this, &SrcFilesView::onGtkTxtFindAccKeyPressed));
UPDATE:
Okay I have understood most I think now, and I know why it doesn't work. The problem is that I have to add the accel_group to the window widget, but I got only a scrolled window and boxes in my program....and now I have no clue how to continue... :)
UPDATE2:
Alright I managed to do it without accelerators by using the "on_key_press_event" handler by checking the state and keyval parameter. Hope this helps some ppl at least ^^.
bool on_key_press_event(GdkEventKey* event) { /* declaration in my constructor removed */
if(event->state == GDK_CONTROL_MASK && event->keyval == GDK_KEY_f
|| event->state == (GDK_CONTROL_MASK | GDK_LOCK_MASK)
&& event->keyval == GDK_KEY_F) {
_gtkEntFind.grab_focus();
}
return false;
}
I would be still interested in a solution with the accelerators if there is any ! Greetings

MFC WebBrowser Control: How many (normal) lines of code does it take to simulate Ctrl+N?

Update: Answer: Two normal lines of code required. Thanks Noseratio!
I banged my head on the keyboard for more hours than I would have cared to trying to simulate IEs Ctrl+N behavior in my hosted Browser control app. Unfortunately, due to complications which I've abstracted out of my code examples below, I can't just let IE do Ctlr+N itself. So I have to do it manually.
Keep in mind that I am running a hosted browser. So typically, opening links in new windows will actuall open it within a new "tab" within my application (it's not really a tab, but another window... but appearance-wise it's a tab). However, Ctrl+N is different -- here, it is expected a fully-fledged IE window will launch when pressed.
I think my problem is that of framing the questions -- admittedly I am new to WebBrowser control and I find it to be a lot of yucky. Regardless, I've scoured the Internet for the past day and couldn't come up with an elegant solution.
Basically, the ideal solution would be to call a "NewWindow" function within WebBrowser control or its affiliate libraries; however, all I was able to find where the *On*NewWindow methods, which were event handlers, not event signallers. Which I understand that most of the time, the user will be creating the events... but what about programmatic simulation?
I tried looking into an SENDMESSAGE approach where I could use the IDs that the OnNewWindow events use... that ended up in nothing than crashes. Perhaps I could go back to get it work, but I'd like confirmation is that approach is even worth my time.
The next approach, which should have been the most elegeant, but sadly didn't pan out, was like the following:
Navigate2(GetLocationURL().GetBuffer(), BrowserNavConstants::navOpenInNewWindow);
It would have worked marvelously if it weren't for the fact that the new window would open in the background, blinking in the taskbar. needing clicking to bring it to the front.
I tried to get around the limitation in a myriad of ways, including getting the dispatcher of the current context, then calling OnNewWindow2 with that IDispatch object. Then I would invoke QueryInterface on the dispatch object for an IWebBrowser control. The webBrowser control (presumably under the control of the new window) could then navigate to the page of the original context. However... this too was a pretty messy solution and in the end would cause crashes.
Finally, I resorted to manually invoking JavaScript to get the desired behavior. Really?? Was there really no more elegant a solution to my problem than the below mess of code?
if ((pMsg->wParam == 'N') && (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000))
{
LPDISPATCH pDisp = CHtmlView::GetHtmlDocument();
IHTMLDocument2 *pDoc;
if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc)))
{
IHTMLWindow2* pWnd;
pDoc->get_parentWindow(&pWnd);
BSTR bStrLang = ::SysAllocString(L"JavaScript");
CString sCode(L"window.open(\"");
sCode.Append(GetLocationURL().GetBuffer());
sCode.Append(L"\");");
BSTR bStrCode = sCode.AllocSysString();
COleVariant retVal;
pWnd->execScript(bStrCode, bStrLang, retVal);
::SysFreeString(bStrLang);
::SysFreeString(bStrCode);
pDoc->Release();
}
pDisp->Release();
I find it hard to believe that I must resort to such hackery as this to get something as simple as opening a new window when the user presses Ctrl+N.
Please stackoverflow, please point out the clearly obvious thing I overlooked.
Ctrl-N in IE starts a new window on the same session. In your case, window.open or webBrowser.Navigate2 will create a window on a new session, because it will be run by iexplore.exe process which is separate from your app. The session is shared per-process, this is how the underlying UrlMon library works. So you'll loose all cookies and authentication cache for the new window. On the other hand, when you create a new window which hosts WebBrowser control within your own app process, you'll keep the session.
If such behavior is OK for your needs, try first your initial Navigate2 approach, precededing it with AllowSetForegroundWindow(ASFW_ANY) call. If the new window still doesn't receive the focus correctly, you can try creating an instance of InternetExplorer.Application out-of-proc COM object, and use the same IWebBrowser2 interface to automate it. Below is a simple C# app which works OK for me, the new window is correctly brought to the foreground, no focus issues. It should not be a problem to do the same with MFC.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace IeApp
{
public partial class MainForm : Form
{
// get the underlying WebBrowser ActiveX object;
// this code depends on SHDocVw.dll COM interop assembly,
// generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
// and add as a reference to the project
public MainForm()
{
InitializeComponent();
}
private void NewWindow_Click(object sender, EventArgs e)
{
AllowSetForegroundWindow(ASFW_ANY);
// could do: var ie = new SHDocVw.InternetExplorer()
var ie = (SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application"));
ie.Visible = true;
ie.Navigate("http://www.example.com");
}
const int ASFW_ANY = -1;
[DllImport("user32.dll")]
static extern bool AllowSetForegroundWindow(int dwProcessId);
}
}

How to disable Edit control's focus on Dialog first launch?

Hello everybody reading this. Thanks in advance for your time.
One thing before question: I DO NOT use neither MFC nor Windows Forms, just WinApi in C++.
Well, I am making a polynomial calculator in Visual C++. I added a Dialog to it, which was created in resources (.rc file) using drag'n'drop method. I suppose there would be no such a problem if i created my Dialog with CreateWindowEx (but I don't want to).
My Dialog has a few of Edit Controls. Everything is fine except that when the Dialog is launched, one of Edit controls takes focus to be ready to take keyboard input.
I have included management of EN_KILLFOCUS (Edit sends it to parent when loses focus due to selecting another control).
Here I read from control to wstring (string of wide characters - _UNICODE is defined), use some kind of parser to verify this wstring and remove bad characters, and then put correct string into the same edit control. It works fine, but here is the source of my problem:
When there was no input, parser returns string "0" (not the NULL, string is just set to "0"), as if control had focus and then lost it even before I clicked anything in Dialog.
Due to that, and something else (this is what I have to figure out), at the Dialog launch parser puts this string "0" to edit.
I want to make my edit not be able to take input from keyboard until i click one of the Edits (including this one).
If it is not possible, I want to clear the whole text at the beginning of dialog (being able to take input is not a problem, I just want to prevent parser from entering string "0" at the beginning)
My code:
In DlgProc I have:
//up here is switch to manage all controls
case MyEditID: // here is ID of one of my edits from resources
switch (HIWORD(wParam))
{
case EN_KILLFOCUS: // edit lost focus - another control selected
if (LOWORD(wParam)==MyEditID) //necessary to determine if
// one of allowed Edits sent this message
// because I have also other Edits
{
GetDlgItemText(hPanel, LOWORD(wParam), MyTempWcharArray, 100);
MyTempString.assign(MyTempWcharArray);
w1 = polynomial(MyTempWcharArray); // parser takes the string
// and removes bad chars in constructor
// polynomial is my class - you don't have to care of it
// w1 is declared before as object of polynomial class
MyTempString = w1.ConversionToString();
SetDlgItemText(hDialog, LOWORD(wParam), sw1);
}
break;
}
break;
does it matter what integer number is set to Edit's ID?
I know SetFocus(), and WM_SETFOCUS message. In this case I just can't get this working.
If i haven't included something important to make you see my point please let me know. I'm sorry I'm just a newbie in WinAPI world.
EDIT:
For those with a similar problem: Do not do this:
I made an workaround with global variable ProcessKillFocus set to false indicating that instructions in message management should not be processed, except that at the end (just before break;) I am changing it to true, so next time and later it will be processed:
case EN_KILLFOCUS:
if (ProcessKillFocus && LOWORD(wParam)==MyEditID)
{
// first time global ProcessKillFocus is false so all this is skipped
// 2nd time and later do all the stuff
}
ProcessKillFocus = true;
break;
Huge thanx to Sheyros Adikari for making my question easy to understand!!!
Huge thanx to patriiice for simple answer on a huge messing question!!!
ANSWER:
BTW: patriiice, I tried this:
case WM_INITDIALOG:
SetFocus(GetDlgItem(hDialog, Desired_Control_ID));
return (INT_PTR)FALSE;
break;
IT JUST WORKS!!!
You have to return FALSE to WM_INITDIALOG message and set the correct focus by yourself.

Weird bug in Qt application

In my application, I have my re-implemented QGraphicsView checking for a mouseReleaseEvent(), and then telling the item at the position the mouse is at to handle the event.
The QGraphicsItem for my view is made up of two other QGraphicsItems, and I check which one of the two is being clicked on (or rather having the button released on), and handle the respective events.
In my Widget's constructor, I set one of the items as selected by default, using the same methods I used when the items detect a release.
When I debugged, I found that for the LabelItem, select is called without a problem from the constructor (and the result is clear when I first start the application). But, when I click on the items, the application terminates. I saw that I was getting into the select function, but not leaving it. So the problem is here.
Which is very weird, because the select function is just a single line setter.
void LabelItem::select()
{
selected = true;
}
This is the mouseReleaseEvent;
void LayerView::mouseReleaseEvent(QMouseEvent *event)
{
LayerItem *l;
if(event->button() == Qt::LeftButton)
{
l = (LayerItem *) itemAt(event->pos());
if(l->inLabel(event->pos()))
{ //No problem upto this point, if label is clicked on
l->setSelection(true); //in setSelection, I call select() or unselect() of LabelItem,
//which is a child of LayerItem, and the problem is there.
//In the constructor for my main widget, I use setSelection
//for the bottom most LayerItem, and have no issues.
emit selected(l->getId());
}
else if(l->inCheckBox(event->pos()))
{
bool t = l->toggleCheckState();
emit toggled(l->getId(), t);
}
}
}
When I commented the line out in the function, I had no errors. I have not debugged for the other QGraphicsItem, CheckBoxItem, but the application terminates for its events as well. I think the problem might be related, so I'm concentrating on select, for now.
I have absolutely no clue as to what could have caused this and why this is happening. From my past experience, I'm pretty sure it's something simple which I'm stupidly not thinking of, but I can't figure out what.
Help would really be appreciated.
If the LabelItem is on top of the LayerItem, itemAt will most likely return the LabelItem because it is the topmost item under the mouse. Unless the LabelItem is set to not accept any mouse button with l->setAcceptedMouseButtons(0).
Try to use qgraphicsitem_cast to test the type of the item. Each derived class must redefine QGraphicsItem::type() to return a distinct value for the cast function to be able to identify the type.
You also could handle the clicks in the items themselves by redefining their QGraphicsItem::mouseReleaseEvent() method, it would remove the need for the evil cast, but you have to remove the function LayerView::mouseReleaseEvent() or at least recall the base class implementation, QGraphicsView::mouseReleaseEvent(), to allow the item(s) to receive the event.
I have seen these odd behaviours: It was mostly binary incompatibility - the c++ side looks correct, and the crash just does not make sense. As you stated: In your code the "selected" variable cannot be the cause. Do you might have changed the declaration and forgot the recompile all linked objects. Just clean and recompile all object files. Worked for me in 99% of the cases.