How to make a floating CMFCToolbar nonmovable - mfc

First I make my CMFCToolbar permanent with
m_wndMyToolBar.SetPermament(TRUE); // it removes the CLOSE Button
Now, how can I achieve that the user can not move the permanent CMFCToolbar?
I have tried to subclass the CMFCToolbar, but the ON_WM_MOUSEMOVE & ON_WM_NCMOUSEMOVE are never called inside this class.

If you want to fix all toolsbars just remove
EnableDocking(CBRS_ALIGN_ANY);
In your CMainFrame class.
To handle a single bar, try to overwrite FloatControlBar and return FALSE.
The final and best to prevent floating fr a special bar is to overwrite OnBeforeFloat and return FALSE. This function is called by FLoatControlBar
The final way to prevent anything is to capture WM_NCHITTEST. Handle it and return HTCLIENT or eventually HTNOWHERE.

Related

Problems saving dialog data in OnOK

Has anyone found a good way to save dialog data to a database in CMyDialog::OnOK?
void CMyDialog::OnOK()
{
// If I save my data here, I don't know if DoDataExchange()
// found validation errors.
CDialog::OnOK();
// If I save my data here, EndDialog() has already been called
}
Looking for ideas on how best to structure this. I know the norm is to have the caller save the data as needed but I don't want the dialog to close if I encounter an error saving the data to the database.
It seems like a good solution would be if CDialog::UpdateData() were virtual, but it is not.
Why not just use UpdateData?
The return value:
Nonzero if the operation is successful; otherwise 0. If bSaveAndValidate is TRUE, then a return value of nonzero means that the data is successfully validated.
So:
void CMyDialog::OnOK()
{
if(!UpdateData(TRUE))
{
// There was some error with the validation procedure so don't end the dialog.
return; // Suppress closing dialog
}
// OK to save data
if(!SaveDataToDatabase())
{
// Some error
return;
}
// Data validated Ok and was saved to DB OK, so close
EndDialog(IDOK);
}
Unless I miss understand your question.
So, it seems clear MFC wasn't designed to work this way.
But the simplest solution I found was to modify DoDataExchange() as follows:
void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
// DDX and DDV calls go here
if (pDX->m_bSaveAndValidate)
{
if (!SaveData())
pDX->Fail();
}
}
The code above relies on SaveData() displaying an error message and returning false if it encounters any errors.
The result is that the regular validation is performed before I attempt to save my data. And, if the code that saves the data fails, I can still prevent the dialog box from closing via the same technique that the MFC validation methods use. (Namely, by calling pDX->Fail()).
In your comment you say this:
// If I save my data here, EndDialog() has already been called
All that means is that the HWND named m_hWnd has been closed and all the child controls with it. The window is dead, but not your instance of your CVehicleDlg. The member variables associated with the data exchange will have the values from the controls transferred to them. You should be good to go for saving.
Another approach would be to catch OnDestroy in your class instead of OnOK. That way, you get the default processing of OnOk to do the data validation. The window wouldn't be destroyed unless the data validation failed. You'll have to special case OnCancel to set some flag to "not save" when your dialog is destroyed.

Any instance access all instances (of a class)

This may seem like a trivial question, or I may have misunderstood previous information/the research I've done so far.
But is it possible to have a object with a function (in C++) that can access all instances of its own type?
In the context of my usage. I wanted to have a Button class, whereby I could simply instantiate multiple Buttons but call to a function could call reference all buttons.
ButtonInstance.isMouseTargetting(cursorCoordinates);
Is this possible? If so is it efficient?
Or should I have the class which owns the Button instances call each instance to check if the mouse coordinates match up?
I'm under the impression you are looking for advice on how to design this.
In the context of my usage. I wanted to have a Button class, whereby I
could simply instantiate multiple Buttons but call to a function could
call reference all buttons.
You want to do this in a button container. A button is not a button container and in a GUI context you already have an established hirerarchy.
Or should I have the class which owns the Button instances call each
instance to check if the mouse coordinates match up?
Yes. You probably already have a window/container class for this.
Your question is more of about Design pattern than C++ itself. Take a look at the Gang of Four book;you will find an appropriate implementation.
You can, for example, make a list of all objects created for a given class,
class Button {
public:
Button() {
_buttonList.push_back( this );
// assign index/handler to this button
}
~Button() {
_buttonList.erase( _handle );
}
static bool isMouseTargeting( float x, float y ) {
for ( auto button : _buttonList ) {
// check if inside
}
return false;
}
private:
static std::list< Button* > _buttonList;
// Handler _handle;
}
This is only a very general example of what you could do. You can use any other container besides a list (entirely up to you), and you have to find a way to index each button (or create a handle) so that you can later erase it in the destructor.
Beware of the default constructors (copy or move). If you don't explicitly create your constructors then some of your buttons will not enter the list, so either make them yourself or delete them.
Button( const Button& button ) = delete;
This is one way to do what you asked, but not necessarily the best solution. It may be simpler to just add the buttons to a non-static container by yourself and search from there.
The short answer is yes. But i will not recommend to put this functionality on the Button class since this will add extra (maybe not expected) responsibility to it. You can achieve the desired behavior by storing your Button objects on some collection and then call a function to check which button is targeted by the mouse.
Another solution would be to store the buttons collection as a member of a higher level class that represents your user-interface. This way you can call a method of this class and check if the mouse cursor is currently on some Button or not. With this design you can add the same support for other GUI elements (if you need to) easily.

Qt5 C++: Custom Spinbox accepting two values

I'm not really into qt but i would like to have spinbox accepting two values
i.e:
It should work like this: select value to change with mouse f.e second value click arrow button and change this value.
Is there any possibility to do that, not creating a new own custom widget?
Short answer is: no
Long answer is:
You should subclass QAbstractSpinBox and implement these two virtual methods:
virtual void stepBy(int steps) override;
virtual StepEnabled stepEnabled() const override;
Keep in mind that you will need to provide your own data store and data manipulation!
The first function determines what happens when the step in either direction is requested. The negative number for steps (that tells how many steps to go in either direction) means go down and positive means up (i.e. clicking on the arrows of the SpinBox). QSpinBox adds the value in steps to its value (so when negative it gets subtracted) for example. Here you can also catch what part of the SpiBox's string the user selected and increment that appropriately with use of
lineEdit()->selectionStart();
lineEdit()->selectedText();
and when you are done you set the correct text back with:
lineEdit()->setText(myModifedValueText); //note that your internally stored value does not need to be QString, you just need to create it from your value in this method to set it to the internal QLineEdit so it can be displayed
The second method is called when the SpinBox needs to know if it can go up or down. So basically here you check the boundaries (if there are any) and return the appropriate flags (QAbstractSpinBox::StepUpEnabled or QAbstractSpinBox::StepDownEnabled or both).
Optinally in the constructor of your SpinBox you can apply QValidator to its internal QLineEdit to accept only certain format of values when the user inputs them by hand, e.g.:
QRegExpValidator *validator = new QRegExpValidator(this);
validator->setRegExp(...); //create a RegExp for your value, you may use any Online regexp validator/creator for this to get the right one
lineEdit()->setValidator(validator);
Finally you can fine-tune your SpinBox to show a text when there is an invalid value or you can fix it yourself using QAbstractSpinBox::fixup and validate the input with the namesake QAbstractSpinBox::validate.
For really pimped out SpinBox you could also re-implement its context menu and actions where you first get the standard menu from QLineEdit:
QMenu *menu = lineEdit()->createStandardContextMenu();
in the QWidget::contextMenuEvent and add/modify it as you need before you show it with menu->exec(event->globalPos()) and then delete menu;.
However QAbstractSpinBox does most of the ground job for you so you really should be fine with implementing just the above two virtual methods.

What signal should I capture to grab the text of Gtk::Entry before it is changed?

I am writing an application using gtkmm 3 (running Ubuntu 12.04 LTS) and working right now with the Gtk::Entry control.
I cannot find the correct signal to capture so that I can grab the Gtk::Entry buffer text before it is changed, and persist it to maintain a record of changes. I know that in some other tool-kits, there is a hook provided that facilitates such. (I believe using a "shadow buffer".)
What signal do I have to grab to do this? What is the slot's signature for this signal? Is this functionality supported at all?
Since you are changing the behaviour, it's better to inherit from Gtk::Entry:
class ValidatedEntry : public Gtk::Entry {
Glib::ustring last_valid;
virtual void on_changed()
{
Glib::ustring text = get_text();
if (... validation here ...)
set_text(last_valid); // WARNING: will call this on_changed() again
else
last_valid = text;
Gtk::Entry::on_changed(); // propagate down
}
};
BUT
This goes against usability, that's why it's not a built-in behaviour. Users won't like the text reverting back just because they miss-typed something; they might hit backspace before they realize the entry threw the wrong character away.
You should at least wait until the user presses the Enter key (i.e. signal_activate or override on_activate()), or do something less drastic, like showing a warning icon.
You could give a try to GObject's "notify" signal. It is used in conjunction with the property to spy. Connecting to "notify::text" will call your callback for each modification of the "text" property, but the first change may be the setter that will set the initial value, that you could then store. Worth a try.
Otherwise, you could try to store it on the first triggering of the "insert-text" or "delete-text" signals. Please give use some feedback if that seems to work.
I also agree with DanielKO: on an usability point of view, modifying user input is just annoying and bad practice. Better to tell her which field is wrong, put the focus there, and/or have a button to reset to defaults, but not enforce any change on user input.

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.