Handling exit without saving in Qt - c++

Im a student programmer using Qt to build and application for work and I am having some difficulty figuring out how to handle when a user has exited a Dialog without saving changes. The dialog is primarily purposed for data entry so being able to identify if changes have been made and then offering the user the option to save before quitting would be extremely usefull. I looked through Qt's Documentation on QDialog and didn't find anything in regards to the mode that is returned if the exit button is pressed. Having a means to just identify when the exit button is clicked is first priority. Also, being a student programmer I am also open to any ideas for best practices in regards to how I should compare before and after data. The data is entered into a table so I am guessing that I would have to make something like this
connect(some kinda exit handler, SIGNAL(clicked), this, SLOT(comparePreAndPostTable)
QVector<QString> prechanges = everything from the table
QVector<QString> postchanges = everything from table when exit is clicked
if(prechanges != postchanges)
{
Give oppertunity to save
}
Any assistance is appreciated! It would really be nice if Qt already had something for this!

You need to override the closeEvent() method of QWidget to handle the exit button of your dialog. The documentation even give an example that strangely looks like what you are looking for:
void MainWindow::closeEvent(QCloseEvent *event)
{
if (maybeSave()) {
writeSettings();
event->accept();
} else {
event->ignore();
}
}
where maybeSave() would compare to see if anything has changed.

Related

Call button click function from grandchild

I'm creating my first C++ wxWidgets application. I'm trying to create some kind of split button where the options are displayed in a grid. I have a custom button class which, when right-clicked on, opens a custom wxPopupTransientWindow that contains other buttons.
When I click on the buttons in the popup, I want to simulate a left click on the main button. I'm trying to achieve this through events, but I'm kinda confused.
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxWindow* mBtn = this->GetGrandParent();
mBtn->SetLabel(this->GetLabel());
mBtn->Refresh();
wxCommandEvent event(wxEVT_BUTTON);
event.SetId(GetId());
event.SetEventObject(mBtn);
mBtn-> //make it process the event somehow?
wxPopupTransientWindow* popup = wxDynamicCast(this->GetParent(), wxPopupTransientWindow);
popup->Dismiss();
}
}
What is the best way to do this?
You should do mBtn->ProcessWindowEvent() which is a shorter synonym for mBtn->GetEventHandler()->ProcessEvent() already mentioned in the comments.
Note that, generally speaking, you're not supposed to create wxEVT_BUTTON events from your own code. In this particular case and with current (and all past) version(s) of wxWidgets it will work, but a cleaner, and guaranteed to also work with the future versions, solution would be define your own custom event and generate it instead.

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

WT widget not updating in boost thread

I have run into an interesting problem with WT, I have solved it, but I do not understand WHY my solution solved the problem. I've dug through WT documentation for the widgets and have come up empty handed so far, so maybe someone who knows more about WT can help me out here.
Anyway, the problem is with a WComboBox widget in a boost thread not updating it's data when clicked on and having it's selection changed.
I created a boost thread in a class
class MyConsole: public WApplication
{
private:
boost::shared_ptr<boost::thread> _thread;
WComboBox* _combo_box;
bool running;
//Thread function
void my_thread(Wt::WApplication *app);
}
Then I fill the combo box with data, lets use "foo" and "goya" as the 2 entries. I made a function for the thread, and put a loop into it.
void MyConsole::my_thread(Wt::WApplication *app)
{
while(running)
{
std::string test;
Wt::WApplication::UpdateLock lock(app);
if(lock)
{
test = _combo_box->valueText().narrow();
}
if (strcmp("foo", test.c_str()) == 0)
{
cout << "we got foo" << endl;
}
else if (strcmp("goya", test.c_str()) == 0)
{
cout << "we got goya" << endl;
}
}
}
Without changing the initial selection of the combo box, the above code always enters the foo if statement, which is expected. However, when I change the selection of the _combo_box to "goya" the above code still enters the "foo" if statement, which is very unexpected. Investigating the matter further such as printing out the current index of the combo box before the if statement showed me that it is always 0 and never gets incremented when the selection changes.
The way I fixed it was by connecting the combo box changed() signal to a do nothing function that I added to the class.
class MyConsole: public WApplication
{
private:
...
void WWidgetForceUpdate(void)
{
}
...
}
...
_combo_box->changed().connect(this, &MyConsole::WWidgetForceUpdate);
With the addition of that function call when the selection changes, the "foo" and "goya" if statements worked properly, and printing out the current index of the combo box before the if statement confirmed that the index was now changing.
Why did connecting the changed() signal to a do nothing function remedy the situation? I am sure there is a bigger problem that I am not seeing here :(
Any help would be much appreciated.
Wt sends changes from the browser to the server when events happen. If your program is not interested in an event, this synchronisation will not take place (otherwise synchronisation would take place on every character of text you enter in an input box, on every mose movement, .... even if your application is not doing anything with it). Nothing connected to changed() means that nothing is interested in that specific event, and the browser will not notify the server when it happens.
Any event that is being listened upon will send all changes of all widgets to the server, so that the full widget tree is synchronised. So if you have a button with clicked() listener, and a combobox without a changed() listener, the state of the combobox will still be updated in the widget tree when you click the button.
There is however a bug in your code: you cannot just access the widget tree from a random thread without grabbing the update lock (WApplication::UpdateLock).

Taking data from a Dialog in Qt and using it in a Ui

So I'm making a text editor using Qt and right now I have a button that opens a dialog called "Format text". I want it to work kind of like the dialog in notepad called "font" where you select a few text attributes from some drop down lists and it shows you what your text will look like. Right now I have it working where you can select the font style, font color, and font size and hit preview and it shows you in a box in the dialog what your text will look like. However, I have a button called "okay" which is supposed to change the highlighted text or the text you are about to type, but I can't figure out how to display those changes on the main window. The .ui files are private and a lot of the already made functions and pointers are the same in every ui file so if I change the ui file to pubic I have to change a whole bunch of things. Can anyway give me a simple answer? I'm trying to do this with as little confusion as possible. More coding and less confusion is better than less coding and more confusion for someone of my skill level. Sorry that this is all one giant paragraph and that I didn't provide any code, but I didn't think the code was necessary, however if you do need some of the code i'd be happy to share it.
Thank you for your help and your time. I hope you all have a nice evening.
QDialog have a signal called finished(), you can connect this signal with your slot. To accomplish your work, pass a QSettings or for simplicity QStringList to dialog settings (responsible for changing font, color ...), the QStringList will save user defined settings, after closing the dialog, iterate through QStringList member to alert Main window.
A pseudo code will look like this
Class Editor:
Editor::Editor()
{
TextSettings textSettings;
textSettings.setSettings(settings); // settings is a member
connect(textSettings, &finished(int)), this, SLOT(alertEditor(int)))
}
Editor::alertEditor(int s)
{
if(s == 0)
{
for (int i = 0; i < settings.size(); ++i)
settings.at(i).toLocal8Bit().constData(); // extract various user settings
}
}
Class TextSettings:
TextSettings::TextSettings(QStringList settings)
{
settings << ui->combobox->currentItem(); // font name as example
}

where is the exit function of a MFC application?

i can't seem to find any exit function in my mfc application codes.
i want my application to actually save some settings when i click on the red cross on the top right of the application. anyone knows where is this exit function located at? thanks
Depends on what type of application it is. Check CWinApp::ExitInstance which will be called always. You may also look into CDialog::OnCancel, CWnd::OnClose, CWnd::OnDestroy, CFrameWnd::OnNcDestroy
If it is a dialog based application, I prefer the following code
void CMFC_dialogDlg::OnOK()
{
}
void CMFC_dialogDlg::OnCancel()
{
}
void CMFC_dialogDlg::OnClose()
{
//Call Save Function
CDialog::OnOK();
}
After adding the following code i will remove the Ok and Cancel button from the dialog so that i will prevent the application from closing while pressing Esc/Enter key.