Dynamically creating controls in MFC (Collection question) - mfc

I have some custom control inside of which i should create radiobuttons or checkboxes. The count of child controls is available only at runtime (it loads some file from which it gets this count). So i need to create variable number of controls. Which collection i should use for this purpose?
Solution 1: simply use std::vector<HWND> (or CArray<HWND>) - not suitable because i want use MFC (CButton). Of course i can Attach() and later Detach() handle to window each time i need this window, but it will give big overhead.
Solution 2: use std::vector<CButton*> or CArray<CButton*> or CList<CButton*> or... In this case i take care about making 'new' and appropriate 'delete' when control is unneeded. I am forgetful :)
MFC handle map contains pointer to CButton and i can't use simple CArray<CButton>, because it will move my objects each time when his size will grow.
... and the question is:
Which collection i should use for containing variable count of MFC control classes?

If you only want to read your file with the Count parameter, create your buttons, work with them and later delete them all then CArray<CButton*> is fine in my opinion. To make sure the buttons get deleted you could wrap the CArray into a helper like:
class CMyButtonArrayWrapper
{
public:
CMyButtonArrayWrapper();
virtual ~CMyButtonArrayWrapper();
void ClearArray();
void Add(CButton* theButton);
private:
CArray<CButton*> m_Array;
}
CMyButtonArrayWrapper::CMyButtonArrayWrapper()
{
}
CMyButtonArrayWrapper::~CMyButtonArrayWrapper()
{
ClearArray();
}
void CMyButtonArrayWrapper::ClearArray()
{
for (int i=0; i<m_Array.GetSize(); i++)
{
CButton* aButton=m_Array.GetAt(i);
if (aButton)
delete aButton;
}
m_Array.RemoveAll();
}
void CMyButtonArrayWrapper::Add(CButton* theButton)
{
m_Array.Add(theButton);
}
Then add an object of this class as a member to your custom control (m_MyButtonArrayWrapper) and add your buttons with:
CButton* aButton=new CButton;
aButton->Create( ... );
m_MyButtonArrayWrapper.Add(aButton);
If you need to add and remove buttons randomly a CList might be better suited for performance reasons. (But you won't probably notice a performance difference using InsertAt/RemoveAt of CArray, except your UI has several thousands of buttons. I guess this would be more an artwork than a user interface :))

Related

How to implement undo-redo functionality in hiding QGraphicsItem using Command-Pattern in Qt?

I am having a QGraphicsView which contains some QGraphicsItem I have a feature (Hide Item) which on mouse right click, hide desired QGraphicsItem(Rectangle) and its connected polylines. I have a Undo-Redo feature also.
Undo - It should cancel the effect of last command executed and show
previous transformation.
Redo - It will undo the previous Undo.
To implement this Undo-Redo feature I have used Command pattern. I have implemented Undo-Redo feature for ZoomIn-ZoomOut.
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?
Below Undo-Redo code is for ZoomIn-ZoomOut feature. (It is just for reference that I want to implement Hide feature something like this. )
myCommand.c
class myCommand: public QUndoCommand
{
public:
myCommand();
myCommand(double scale, QGraphicsScene* scene,QGraphicsView* view);
private:
QGraphicsItem* mItem;
QGraphicsScene* mScene;
QGraphicsView* mView;
double scaleFactor;
void undo();
void redo();
}
myCommand.cpp
myCommand::myCommand(double scale, QGraphicsScene *scene,QGraphicsView* view): mScene(scene),
mView(view),scaleFactor(scale)
{}
void guiCommand::undo()
{
mView->scale(1/scaleFactor,1/scaleFactor);
}
void myCommand::redo()
{
mView->scale(scaleFactor,scaleFactor);
}
myView.cpp
void myView::ZoomIn()
{
double scaleFactor = 1.1;
view->scale(scaleFactor,scaleFactor);
myCommand* command1 = new myCommand(scaleFactor,scene,view);
undoStack->push(command1);
}
myView.h
public:
QUndoStack* undoStack;
New addition :
void myRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
vPtr = this->getPtr();
if(vPtr->isVisible == false)
this->hide();
else
{
this->show();
qDebug()<<"Undo Rect";
}
}
myCommand is :
myCommand* command3 = new myCommand(isRectHiddden,vPtr,GraphName);
undoStack->push(command3);
It should be very simple given the fact that you already successfully implemented zoom-in/zoom-out.
class HideItemCommand: public QUndoCommand
{
public:
explicit HideItemCommand(QGraphicsItem *item);
private:
QGraphicsItem* mItem;
void undo();
void redo();
}
HideItemCommand::HideItemCommand(QGraphicsItem *item): mItem(item)
{}
void HideItemCommand::undo()
{
mItem->show();
}
void myCommand::redo()
{
mItem->hide();
}
void myView::hideItem(QGraphicsItem* item)
{
item->hide();
auto cmd = new HideItemCommand(item);
undoStack->push(cmd);
}
So this is very simple. BUT!!! Now I am going to think one or two steps ahead. You asked only about showing/hiding undo/redo which can be implemented using the code which I suggested. But you are probably developing some drawing app so I guess that sooner or later you will want also add-item or remove-item undoable/redoable commands. And then the code which I wrote will not suffice any more. The reason is that holding item by pointer will not work any more if you remove and then add again the item using undo/redo. After redoing of remove operation, the pointer to the newly re-created object will be different the the pointer to the corresponding object which you had deleted earlier, so the item kept in HideCommand via its pointer will be invalid.
To solve this problem of invalid pointers, you need to invent some other way of recording what items you have in your scene. For example some UUID or just a sequence of integers (which is what I would do), lets call it item ID. And then keep a two-way map of these item IDs and corresponding pointers, so that you are able to translate ID to the item pointer, there and back.
Then when you create an item via some AddItemCommand you create the item and generate its ID and store the relation between the ID and the pointer to the map. You put record of this ID in the undo command. And for all other commands which will need to refer to that item (e.g. that HideCommand) you will use the ID instead of the pointer. This will allow you put all commands to the stack, use stable IDs and not volatile pointers which may change as you undo/redo adding or deleting of objects. Also RemoveItemCommand will record the ID of the removed object and if undone, the new item will be created (i.e. a new, different pointer) but with the old, known ID. So other commands referencing this ID will still be valid.
I hope I managed to explain this well. In fact it is not that difficult. You just need to understand that pointers will change over time if you add or remove items with undo/redo, but IDs can stay the same. Therefor you need to keep IDs in your commands and not pointers. This will of course change the code which I wrote a bit. But I believe you are able to adjust it from using pointers to using IDs by yourself once you implement the ID <-> pointer mapping in your app.

Why a Widget class uses pointers as data members?

I'm working through "Programming Principles and Practice", and I don't understand why this Widget class uses pointers as data members.
The book's explanations is this:
Note that our Widget keeps track of its FLTK widget and the Window with which it is associated. Note that we need pointers for that because a Widget can be associated with different Windows during its life. A reference or a named object wouldn’t suffice. (Why not?)
So, I still don't understand why the Widget can't have a named object Window win as a data member, which can take a different value when it's associated with a different Window. Could someone explain this a bit?
class Widget {
// Widget is a handle to a Fl_widget — it is *not* a Fl_widget
// we try to keep our interface classes at arm’s length from FLTK
public:
Widget(Point xy, int w, int h, const string& s, Callback cb)
:loc(xy), width(w), height(h), label(s), do_it(cb) { }
virtual ~Widget() { } // destructor
virtual void move(int dx,int dy)
{ hide(); pw–>position(loc.x+=dx, loc.y+=dy); show(); }
virtual void hide() { pw–>hide(); }
virtual void show() { pw–>show(); }
virtual void attach(Window&) = 0; // each Widget defines at least one action for a window
Point loc;
int width;
int height;
string label;
Callback do_it;
protected:
Window* own; // every Widget belongs to a Window
Fl_Widget* pw; // a Widget “knows” its Fl_Widget
};
Window own;
This will copy the whole Window object. If the real window changes, this widget will have an old and useless copy.
Window & own;
A reference. We meet two issues:
A) We can not know if the window has been deleted outside the widget code
B) The window must exists before this widget
Window * own;
A pointer can be NULL, as opposed to a reference. This avoids reference issues.
The book seems a bit old, just because it uses raw-pointers.
EDIT due to comments
It is absolutely true that issue "A)" is the same for references and pointers. But it can be easier handled with a pointer.
What I wanted to point to is that when a window is deleted, the widget must be informed about it, so as to not use the "own" object.
With a pointer, it can be resetted to NULL, so any further attemp to use "own" can be easily catched. But with a reference you need, at least, an extra bool in your code just to store if "own" is valid or not.
First, we need to work out the logical and implementation details. On the logical side, a window contains widgets: just like a mother has children. This is a one to many relationship. Each widget has an implementation entity, in this case an Fl_widget. It could equally be a MS windows Window, a QtWidget or and X-Windows Widget. It is one of those implementation dependent things
___________
|window |
| _______ | _________
| |widget-|-|--->|Fl_widget|
| _______ | _________
| |widget-|-|--->|Fl_widget|
|___________|
Within window itself, there will also be an implementation detail like another Fl_Widget or Fl_window.
The reason why we cannot have Window win instead of Window win* is because the window owns the widget and not the other way round. If we had Window win then whenever any window property changed, you'd have to modify all the widgets containing the same window. Taking, the mother child relationship, if the mother had a haircut, the mother member for all the children of the same mother would have to have a haircut. You'd have to have a method to keep track of and update all the mothers of all the children. This would just be a maintenance nightmare.
If we just hold a pointer to the window then we know that if the window is modified, all sibling widgets will be able to query the change in the parent window and get the same answer without a lot of effort.
The second part of your question about moving widgets between windows - I've never seen anyone do that. In all the implementations I have ever used, this is impossible. The parent window owns the widget for life. To "move it", you'd normally have to reincarnate it i.e. destroy it from the current window and re-create it in the new window.

Add two numbers using MFC

Since I am a total beginner in MFC I need a help to understand some basics. At the moment it is not clear to me how can I grab some value (by ID or something else) and use it, or change it...
Lets say I have something like this:
The ID of edit boxes are: IDC_EDIT1, IDC_EDIT2, IDC_EDIT3 (respectively).
The ID of Calculate button is IDC_BUTTON1.
How can I grab the value of IDC_EDIT1, and add it to IDC_EDIT2 and then show it IDC_EDIT3 on Calculate click?
After creating this Dialog, I get the following code:
void CMFCApplication1Dlg::OnBnClickedButton1()
{
}
void CMFCApplication1Dlg::OnEnChangeEdit1()
{
}
void CMFCApplication1Dlg::OnEnChangeEdit2()
{
}
void CMFCApplication1Dlg::OnEnChangeEdit3()
{
}
For starter, try this:
void CMFCApplication1Dlg::OnBnClickedButton1()
{
int a = GetDlgItemInt(IDC_EDIT1);
int b = GetDlgItemInt(IDC_EDIT2);
SetDlgItemInt(IDC_EDIT3, a+b);
}
An MFC CDialog is a CWnd (inheritance). So you can access its childs with GetDlgItem. If you only want to process integers, you can even use the helper method GetDlgItemInt which will give you the text of the CEdit as an integer. Once this is done, you just add the two numbers and use the result to set the value of the last CEdit (that should be either inactive of read-only) with SetDlgItemInt.
If you want to accept floating point, you should read the values with SetDlgItemText and write them with SetDlgItemText and process the conversions to/from double by hand.
What I mean is that you will not have to use the OnEnChangeEditx notifications but do all the stuff in the OnBnClickedButton1 one.
As you have not shown your current code, I cannot say more here...

MFC RibbonBar -- programmatically minimize?

The MFC ribbon bar has a menu item labelled 'Minimize the ribbon'. When you select it, only the headers of each category are shown, and the ribbon pops up when the headers are clicked. I'd like to programmatically force a ribbon into this state. Unfortunately, the only method I can find is ToggleMimimizeState() [sic], which will either put it into this state or take it out depending on its current state.
Looking at the MFC source code, the way the menu command works is through this code:
case idMinimize:
if (m_pActiveCategory != NULL)
{
ASSERT_VALID(m_pActiveCategory);
m_pActiveCategory->ShowElements(FALSE);
RedrawWindow();
}
m_pActiveCategory can be obtained from outside of the CMFCRibbonBar class through the GetActiveCategory() method, but unfortunately the category's ShowElements() method is protected and I cannot see a way of achieving the same effect with the public methods.
Neither does there seem to be an obvious way of determining whether the ribbon is currently minimized.
Is there something I'm missing, or do I just have to guess at the current state?
Derive two new classes from CMFCRibbonBar and CMFCRibbonCategory
class MyCMFCRibbonCategory: public CMFCRibbonCategory
{
public:
void force_ShowElements(BOOL todo)
{
ShowElements(todo);
}
};
class MyRibbonBar: public CMFCRibbonBar
{
public:
BOOL is_minimized()
{
return m_dwHideFlags == AFX_RIBBONBAR_HIDE_ELEMENTS;
}
void minimize_me(BOOL show_minimized)
{
MyCMFCRibbonCategory* cc = (MyCMFCRibbonCategory*)GetActiveCategory();
if (cc != NULL)
{
cc->force_ShowElements(!show_minimized);
RedrawWindow();
}
}
};
then change in your CMainframe from
CMFCRibbonBar m_wndRibbonBar;
to
MyRibbonBar m_wndRibbonBar;
Now in your code you can use the new two members:
BOOL MyRibbonBar::is_minimized()
void MyRibbonBar::minimize_me(BOOL show_minimized)
Basic example:
void CMainFrame::OnButton2()
{
if( m_wndRibbonBar.is_minimized() )
m_wndRibbonBar.minimize_me(FALSE);
else
m_wndRibbonBar.minimize_me(TRUE);
}
Hope it can help.
A combination of the above worked for me. That is, I wanted to use the Ribbon as a tabbed set of extra functions on a main menu. However, I didn't want the ribbon to have the ability to stay maximized. I only wanted the user to click, see a few actions and after that, disappear.
In short, prevent the ribbon from docking, or staying maximized. Whatever you want to call it. Click a tab, then and icon on the ribbon and disappear.
Instructions:
I derived my own CMyRibbon class by inheriting from CMFCRibbonBar. (Done using Class wizard and making an MFC class)
Create an event handler for WM_SIZE in our new CMyRibbon class (ClassWizard)
void CMyRibbon::OnSize(UINT nType, int cx, int cy)
{
CMFCRibbonBar::OnSize(nType, cx, cy);
if (!(GetHideFlags() & AFX_RIBBONBAR_HIDE_ELEMENTS))
ToggleMimimizeState();
}
In CMainFrm.h add this change:
CMyRibbon m_wndRibbonBar;
Use m_wndRibbonBar.ToggleMimimizeState();
Simply check (m_wndRibbonBar.GetHideFlags() & AFX_RIBBONBAR_HIDE_ELEMENTS) value.

How C++/Qt - Memory allocation works?

I recently started investigating Qt for myself and have the following question:
Suppose I have some QTreeWidget* widget. At some moment I want to add some items to it and this is done via the following call:
QList<QTreeWidgetItem*> items;
// Prepare the items
QTreeWidgetItem* item1 = new QTreeWidgetItem(...);
QTreeWidgetItem* item2 = new QTreeWidgetItem(...);
items.append(item1);
items.append(item2);
widget->addTopLevelItems(items);
So far it looks ok, but I don't actually understand who should control the objects' lifetime. I should explain this with an example:
Let's say, another function calls widget->clear();. I don't know what happens beneath this call but I do think that memory allocated for item1 and item2 doesn't get disposed here, because their ownage wasn't actually transfered. And, bang, we have a memory leak.
The question is the following - does Qt have something to offer for this kind of situation? I could use boost::shared_ptr or any other smart pointer and write something like
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
but I don't know if the Qt itself would try to make explicit delete calls on my pointers (which would be disastrous since I state them as shared_ptr-managed).
How would you solve this problem? Maybe everything is evident and I miss something really simple?
A quick peek into qtreewidget.cpp shows this:
void QTreeWidget::clear()
{
Q_D(QTreeWidget);
selectionModel()->clear();
d->treeModel()->clear();
}
void QTreeModel::clear()
{
SkipSorting skipSorting(this);
for (int i = 0; i < rootItem->childCount(); ++i) {
QTreeWidgetItem *item = rootItem->children.at(i);
item->par = 0;
item->view = 0;
delete item; // <<----- Aha!
}
rootItem->children.clear();
sortPendingTimer.stop();
reset();
}
So it would appear that your call to widget->addTopLevelItems() does indeed cause the QTreeWidget to take ownership of the QTreeWidgetItems. So you shouldn't delete them yourself, or hold them in a shared_ptr, or you'll end up with a double-delete problem.
Qt has its own smart pointers, take a look at http://doc.qt.io/archives/4.6/qsharedpointer.html . Normally, it is though advisable to use the standard ownership hierarchy of Qt whenever possible. That concept is described here:
http://doc.qt.io/archives/4.6/objecttrees.html
For your concrete example, this means that you should pass a pointer to the container (i.e. the QTreeWidget) to the constructor of the child objects. Every QWidget subclass constructor takes a pointer to a QWidget for that purpose. When you pass your child pointer to the container, the container takes over the responsibility to clean up the children. This is how you need to modify your example:
QTreeWidgetItem* item1 = new QTreeWidgetItem(..., widget);
QTreeWidgetItem* item2 = new QTreeWidgetItem(..., widget);
(I don't know what the ... are in your example, but the important thing for Qt memory management is the last argument).
Your example of using a smart pointer
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
is not a good idea, because you break the golden rule of smart pointers: Never use the raw pointer of a smart pointer managed object directly.
Many Qt class instances can be constructed with a parent QObject*. This parent controls the life time of the constructed child. See if QTreeWidgetItem can be linked to a parent widget, which seems so, reading Qt docs:
Items are usually constructed with a
parent that is either a QTreeWidget
(for top-level items) or a
QTreeWidgetItem (for items on lower
levels of the tree).