Calling an event handler after text has been modified in wxWidgets - c++

I am trying to create a situation in my wxWidgets application where a user can type something into a text box, and if there are one or more characters in the text box, other controls become enabled. As such, I created an event handler that checks TextBox->IsEmpty() on the event wxEVT_COMMAND_TEXT_UPDATED. However, this seems to be called before the changes to the text in the text box take place. Is there any way to get an event to fire after the changes have occurred?
Thank you.
EDIT: Code I am using.
I am using Connect() to set up the event handling, so there is no event table to speak of. This is the code I am using:
cur->mTextBox = new wxTextCtrl(mParentFrame, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize);
mParentFrame->Connect(wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(iguiFrame::correctTextBoxes));
correctTextBoxes is a public method of my wxFrame derived class, which calls a function containing only the following code:
if(cur->mTextBox->IsEmpty())
{
wxMessageBox("Empty!");
}
The message box always pops up "one character" too late.

As #ravenspoint mentioned, this event should have been fired after the change was made, but I also wanted to point out that even in the cases where an event is fired just before a change is made, the change is almost always passed into your event handler with the event parameter.
So for this case, you may want to actually just check the value of event.GetString() in correctTextBoxes() to see the new value being set on the text control.

Related

Qt5: Tell QPlainTextEdit to ignore syntax highlighting changes

I have a QPlainTextEdit widget in my application which has a QSyntaxHighlighter assigned to it. Upon each content change within that text edit area, I need to get a notification (to update the global application save/changed state). However, the signal textChanged() also gets emitted each time the highlighter gets to work, which I need to filter out somehow.
I already had a look at modificationChanged(), but that doesn't seem to work either. It ignores the highlighting changes and successfully notifies me upon the first content change, but not of any subsequent changes. The documentation mentions, that I should be able to reset the internal state with setModified(false) but that method doesn't seem to exist.
Any ideas on how to filter the changes?
Do I have to switch to QTextDocument which seems to have a single contentsChanged() that is said to ignore syntax highlighting changes?
It turns out I already was on the right track...just not all the way:
I indeed need to listen to modificationChanged signals since they are emitted on content changes (which are the relevant events for my application save state handling).
I however originally did not see a way to reset the internal modification state (e.g. when my application saves its state). The reason was that setModified(bool) does not exist for the QPlainTextEdit, but I realized that each of those objects has a QTextDocument internally which does have that method. So I simply call that each time I need to reset the state to non-modified:
m_pPlainTextEdit->document()->setModified(false);
As a result, when the content is changed the next time, modificationChanged will get emitted again so that I can react to it and for example enable the "Save" icon.
BTW: The signal contentsChanged from QTextDocument is also emitted upon formatting changes, so not helpful in my scenario.
I have not tested it, it is just basically an idea.
When the user modifies the text, it is a QKeyEvent.
When the highlighter does, it is some sort of QInputMethodEvent (?)
What you could do is, check if the event is a QKeyEvent, and if it is not, block it.
You can create a filterobject class, or just define the following method in the class that contains the QTextEdit.
bool MyClass::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QKeyEvent) //The user modified the text edit
return false;
else
return true;
}
And you have to install it (for example in the constructor), if you defined it in the class that contains QTextEdit:
myTextEdit->installEventFilter(this);
Instead of hooking into modificationChanged(), and resetting the modified flag everytime, you could just hook into textChanged(). It's triggered anytime you make a change to the document, regardless if had been previously changed or not...

Preventing newlines in Text widget, but still proagate the event upwards?

According to Effbot's Tkinterbook on Events and Bindings, I can prevent newlines from being inserted into a Text widget via this code:
text.bind("<Return>", lambda e: "break")
Which does work, but it prevents the <Return> event from reaching the parent form, which has its own <Return> binding that performs work on the Text widget and others. What I want to do is catch events like <Return>, <KP_Enter>, etc, in the Text widget and prevent the newline from being inserted, but I still want that event to propagate upwards. I can't find a good way of doing this, because Text widgets have no form of validation like Entry widgets (which is where this kind of work would normally be done).
I am thinking that if I override <KeyPress> and check event.keycode for 13, I can skip the internal call to ::tk::TextInsert and instead invoke whatever function internal to Tk is responsible for passing events up to the next elements in the bindtags, based on reading the TCL code in text.tcl in Python.
You mention bindtags, which sounds like you know what they are. Yet you also talk of events which propagate to their "parent form", which events don't normally do. The only time a <return> event will propagate to its parent is if the parent is in the bindtags. This will be true if the parent is the root window, but not for any other unless you explicitly add the parent to the bindtags.
When you do return "break" in a binding, you prevent other bindtags from acting on the event. There is no way to skip the immediately preceeding bindtag but allow additional bindtags to process the event. And, there's no way (short of regenerating the event) to have other widgets that are not part of the bindtags process the event.
If you have a binding on a frame, and one on the text widget, and you want both to fire, just have your text widget binding call the code associated with the other binding. For example:
self.parent.bind("<Return>", self.validate_form)
Self.text.bind("<Return>", self.validate_form)
If self.validate_form returns "break", this should work as you expect.

Is it possible to get information on the control on which an event was issued in Qt?

I am trying to create one event handler for button clicks and connect that to multiple buttons (creating a simple calculator where pressing each number adds its text to the lineEdit).
In C# we would use the sender object which was passed as a parameter and then cast it back to Button and get its Text or other needed property and go on.
I am new to Qt, Do we have such a thing or a similar approach in Qt? Since I couldn't get it out of the signal/slot method of Qt.
On the QObject / QWidget that receives the signal, call this->sender() (QObject::sender()), and cast it with dynamic_cast<MyWidgetType*>(...)
You can find some good examples here for linking back to the issuer of an event.
http://doc.qt.digia.com/qq/qq10-signalmapper.html
They give you different examples for
The sender() Approach (like Jamin Grey's approach below)
The Subclass Approach
The Signal Mapper Approach

Getting results from a non thread blocking message box?

Generally, message boxes work like this:
if(ShowMessageBox("Title","Text",MB_YES_NO) == MB_YES)
{
//the user responded yes
}
However, I'm working on a game where I have made the gui system, and when a messagebox is shown, there is still animation happening in the background so I cannot simply block the thread, the animation would stop.
Right now, the way it works is to show the message box, an IMessageHandler* must be provided and it is called with the dialog result.
I'm wondering if I'm overlooking something. Is there a better way to do this that might resemble more how it is usually done. How might other games approach it?
Thanks
There are multiple options, e.g...
Create a View-Model class that the message box reads from (title, message, button text) and writes to (result prior to closing), pass the VM to your message box before displaying it, then read result from VM after close.
(A better technique would to use a command pattern or place an event on the message box instead of passing VM to message box, then within command/event handler update VM).
Use a command pattern or an event to pass result from message box (prior to close) directly to caller (or to view model).
Use a show dialog style call to message box (blocking), however, do that on a separate thread, then write results to a place where main thread can read from.

Callback for button in Qt Designer?

I just started using QtCreator tonight, and it seems it puts all of the interface stuff inside of the ui file. I followed a tutorial to create a resource for my icons, then I added them to a menu bar at the top.
I need to make a connection when one of them is clicked though, and cannot figure out how to make a callback for it.
Am I going to have to completely create them through code or is there some way to add a callback for them (rather than just making them interact with other objects).
Menu bar items are action objects. To do something when they are clicked, you need to catch the triggered() signal from the action. Read more about signals and slots here.
To do this, you need to declare a new slot in your MainWindow class. Qt also supports doing this automatically, without the need to connect anything, but I prefer doing it myself. If you're not interested, just skip this part.
First, we declare a new slot in your window class:
private slots:
void clickMenuButton();
Then, in your constructor, you need to connect the triggered signal to your new slot:
connect(ui.actionObject, SIGNAL(triggered()), this, SLOT(clickMenuButton()));
The first argument is the object that holds the signal we'll listen to (your menu button). The second is the name of the signal. The third is the object that holds the receiving slot (in this case, our window). The fourth is the slot.
And just like that, clickMenuButton() will be called whenever the action is clicked.
As I said before, Qt can also automatically connect signals to slots. The disadvantage here seems to be that you can't change the slot's name, but you don't need to connect it either.
Qt Creator supports creation of slots for widgets: in the case of your menu action, you should go to the form designer, and you should see a list of actions in your form (if you don't, find the Action Editor). Right click the action you want, and push Go to slot.... There, double click triggered().
Qt Creator will then open the new slot in your code editor, and you can do whatever you want to here!
To do that you'll need to add a QAction, add it to the menu, associate an icon with it and then create a callback for it. I'm using the VS Integration so I don't know the details of how to do it in Creator but it should be possible without creating stuff in code.
There should be somewhere an actions editor. from there you add an action, then right-click it or something to add an icon to it, then drag it do the menu and then possibly double click it to create a slot for it. This is how it works in the VS Integration atleast.