Getting notified when a list box has an item removed? - c++

I use CListBox::SetItemData to store a pointer to some data in my ownerdrawn CListBox-derived class, and I'd like the listbox itself to keep track of it and free the memory when its no longer needed.
For that I'd need to be notified each time an item is deleted (including LB_RESETCONTENT and every possible other case where an item is deleted). Is there an event or events that I can handle to achieve that?

As its owner drawn with one of the LBS_OWNERDRAW* styles you can look out for WM_DELETEITEM;
Sent to the owner of a list box or combo box when the list box or
combo box is destroyed or when items are removed by the
LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT
message. The system sends a WM_DELETEITEM message for each deleted
item

No. A ListBox only generates notifications for things that the user does. The user cannot remove or add or empty a list box, that can only be done by your own code. So the philosophy here is that the control doesn't have to tell you about something you already know. You can arbitrarily generate your own message in the code that modifies the content. But of course inheriting your own class from CListBox and adding your own virtual methods would be better.

Since you're subclassing the listbox already anyway, the 'proper' design would (IMO) be to add data management functionality to the listbox, which would then know when items are removed and can delete the data as required. What I mean is, let's say your list keeps track of people, you'd add AddPerson(Person p) and RemovePerson(Person p) methods to your class. The implementation of RemovePerson would remove the respective entry from the list, and delete all data related to it. So don't use CListBox::DeleteString to remove things, use the higher-level API that you implement yourself.

It's easy - just subclass the list box and add message handlers for LB_DELETESTRING and LB_RESETCONTENT
See here for details:
http://www.codeguru.com/cpp/controls/listbox/article.php/c4759/CListBox-with-the-Horizontal-Scroll-Bar-that-Works.htm

Related

Reset / Clear every item within TabWidget Page

Is it possible to reset / clear every QTabWidgets Pages Items?
I have created the UI using the Designer.
I would hate to statically code a clear mask function since we all now UIs can get quite complex and it would take quite the maintenance work for every item that gets added later on.
If this is not possible I would also be okay with looping over each child item and invoking the clear( ) function if someone could give me a hint as to how I can get the pointer / address of them.
All pages of a QTabWidget are of the type QWidget which is a QObject. The latter has the function
const QObjectList & QObject::children() const
so you can get all children, iterate over them and invoking the clear(). You should probably check isWidgetType() to make sure you only have widgets and probably also design this function recursively if you plan on having widgets with children of their own (i.e QGroupBox).

Updating CMFCRibbonBar elements from document

I would like to update the ribbon from the CDocument derived class because the information relevant for ribbon's status is stored there. The was created by the Wizard and edited in resource manager
Some elements (Buttons, checkboxes) can be updated with ON_UPDATE_COMMAND_UI macro.
But I have a headache with update other things like CMFCRibbonComboBox or CMFCRibbonProgressBar because CCmdUI doesn't provide suitable functions to deal with them (ie AddItem)
Other option using GetDlgItem doesn't work, because neither CDocument nor RibbonBar elements are derived from CWnd.
So what is the way to update CMFCRibbonComboBox and others?
I faced a similar problem with combo boxes on a toolbar. The combo box was used to display the current mouse coordinates of a point in "world coordinate" space while the mouse was moved. I derived my own class for the combo and exposed some methods that would update its contents. I then picked the most appropriate point in the code to make the appropriate calls to those methods. That may be during the paint cycle (eg. OnDraw), or, during idle time. A similar approach of deriving and exposing methods should work for you. The only caveat is to pick the correct location to inject your calls to perform the update.
I first tried RogerRowland's solution, but it soon became annoying to add a function to MainFrame for every trifle , then to call AfxGetMainWnd() from document and apply static_cast on it.
Instead I now store pointers to the ProgressBar and the combobox inside the document. I added the methods to CMainFrame to get them and removed the rest.
The only dificulty with it is the fact that the document is constructed before the main window. So I have to delay the initialisation of the mentioned pointers. I solved it by adding setRibbonBarPointers() to the document and calling it from OnInitialUpdate() of the view

How to structure signals/slots?

I am creating a UI with Qt and there are two elements which may or may not be present. Additionally, their parents are different elements as well. However, one affects the other.
How should I structure the signals/slots (or should I not even use that pattern) in the best way?
The methods that come to mind all seem like hacks:
create a signal/slot in all parents and pass up and then back down the signal
create a signal/slot in the closest common parent of both then have the children connect their signals/slots to the parents'
on creation of one navigate the structure of the other to get the element and then connect signals/slots directly. Any guidance here is greatly appreciated.
Edit: "present" means that there is a button that the user may press that creates an element and adds it to the layout. So depending on the combination of button presses, an element may be present or not.
"affect" means it changes its state. for example, there is a list of items and a button elsewhere which adds an element to the list.
For an example, imagine a tabbed pane which contains a todo list. There is a button not in the tabbed pane which adds an item to the list. The tabbed pane does NOT create all the elements of the pane. It creates only the elements of the visible pane and deletes them when the pane is switched away. Therefore, the list may or may not exist.
The UI elements are QWidgets. All QWidgets are QObjects. Any QObject's signals can be connect()ed to any other object's slots. The hierarchy of parent/child relationships is entirely immaterial.
You seem to be confusing signal-slot connections with events, which can be in fact passed up the object hierarchy if they remain ignored by given object.
It's also worth noting that signal-slot connections are safe in spite of QObjects being destroyed. When an object with connected signals or slots gets destroyed, the connections are safely torn down. The only thing you can't do is deleting the sender nor receiver object within a slot - use object->deleteLater() instead.

How to set height for owner draw variable CListBox (MFC)

I have a variable-height owner draw ListBox control. When I call AddString, a MeasureItem message is sent asking me to tell Windows the size of the item. The problem is, the code hasn't had a chance to call SetItemData yet, so the code can't determine the size yet.
I've tried calling SetRedraw(FALSE) hoping that would postpone the measure request, but no luck.
So how can I add an item to a CListBox and get the Item Data passed in at the same time? I've tried with and without LBS_HASSTRINGS. Not sure what else to try.
If your list box control does not have the LBS_HASSTRINGS style, the pointer argument to AddString() is not considered as a string but as item data (see the remarks section in the documentation for LB_ADDSTRING).
Therefore, if your list items consist in both a string and some item data, you can wrap these two pieces of information in a structure or a class and pass a pointer to that wrapper to AddString().
The upside is that both the string and the item data will be available by the time MeasureItem() is called. The downside is that you will have to implement CompareItem() if your list is sorted, and to free the wrappers both when items are deleted and before the list box control is destroyed.

How do I setup a callback mechanism for RichEdit in win32

In win32, how do I setup a callback mechanism for RichEdit I have not created myself?
PART 1
I'm reading from a textedit field in another application's GUI. This works just fine now, except after the first read I'd like to fetch only new or modified lines. In GTK+ or Qt I'd just install a callback on some signal the field edits when its changed, but how does it work on Win32?
My MSDN searches result with nothing useful, probably because I don't know the exact term to search for. The class of the textedit is RichText20W, and it has some messages that are probably used somehow, though that article just discusses using them for the parent of the class.
PART 2
Also, if there is no such "text changed, here is the newly inserted text" callback which returns the new content immediately, I need some way to easily detect what is new. From top-of-my-head:
Have a marker at the end of the text block we've read, and only read between that and the end.
Store what we've read previously, and after a second read, remove the duplicate part from the latter to have the newly inserted stuff.
Option 2 might not be viable, since the textedit can contain any amount of text. The marker part sounds doable, but yet again, my feeble Win32 skills and horrible Win32 function names prevent me from finding the right way to do it.
Note that all these must be doable for a textedit I do not own and have not created, they belong to a third party process.
Code samples in C++ highly appreciated.
Disclaimer
Obviously, if there is some better way of doing it, let me know. I only assumed callback would be the way to go based on my previous experience with GTK+/Qt. Feel free to show me the path :)
Win32 controls don't work on message-specific callbacks that you can subscribe to. They just send messages to their parent window when something happens, in this case EN_UPDATE, EN_CHANGE and all that. Even these events don't tell you what text changed. They only tell you that it did change.
You could subclass the parent, but the documentation for SetWindowLongPtr explicitly says you "should not subclass a window class created by another process." Something like this is probably possible with hooks, but I haven't used them enough to say for certain how you'd actually do it.
I realize it's an old post, but this article seems to be doing something similar.
Based on Joel's answer, I quit looking for callbacks and just made a small class that hooks itself (not by a real API hook though) to the richedit and polls it once a second for content length, and if it has changed since the last poll, it asks for the content, compares that to previous known content and emits a signal with the changed content.
This seems to work OK for this purpose, but if someone knows a better way still (some real and tested way of doing it via API hooks or something), please post.