form properties not called during resize - c++

I have a .NET form with a boolean property called _isResized, which is set to true when the SizeChanged event is called and is set to false when the bool isResized() function is called.
ref class net_window : public System::Windows::Forms::Form
{
private:
bool _isResized;
public:
net_window(void)
: _isResized(false){
InitializeComponent();
}
void InitializeComponent(void){
this->SizeChanged += gcnew EventHandler(this, &net_window::eventResized);
}
bool isResized(void){
bool temp = _isResized;
_isResized = false;
return temp;
}
Void eventResized(Object^ sender, EventArgs^ e){
_isResized = true;
}
};
I also have an native C++ class called window which acts as a layer around the .NET form. This class is updated every frame of the main loop and uses the bool isResized() function of the form to see if the size has changed.
class Window
{
private:
void* _net_window_handle;
Window(){
_net_window_handle = new gcroot<net_window^>;
(*(gcroot<net_window^>*)_net_window_handle) = gcnew net_window;
}
~Window(){
delete _net_window_handle;
}
void update(void)//Called every frame.
{
if( (*(gcroot<net_window^>*)_element)->isResized() )
//Do stuff.
}
};
The delegate added to SizeChanged is called whenever the form is being resized, so _isResized is set to true as soon as the form size changes, but for some reason the thread of the main loop freezes whenever the window class uses the bool isResized() function, until the user has released the edge of the form and thus the resizing has finished.
Is it not possible to access .NET form values as long as it is being resized. Is there an alternative?
Thanks
EDIT
I use a main loop which calls System::Windows::Forms::Application::DoEvents() every frame. When the thread of the loop enters this function and the main window is resizing, it freezes. Is there a way to avoid this problem.

DoEvents strikes again. Windows pumps a modal message loop when the user starts dragging a window edge. Which means that your DoEvents loop isn't running anymore. Use a timer instead, SetTimer with a 15 or 31 msec interval is about right. Having your code respond to the Resize event directly of course highly preferred.
Thanks Hans Passant

Related

How to prevent GUI from hanging while allowing 2nd operation to be performed alongwith 1st operation in Qt

Here I am explaining my problem statement in detail and the efforts I have put so far
A) Problem Statement : During printing if 'Stop Printing' pushbutton is pressed, the printing should stop at that moment!
B) My Work :
1. StartPrinitng_Pressed :
void MainWindow :: on_StartPrinitng_Pressed()
{QSqlquery studentList;
studentList("SELECT Name, address FROM class WHERE Roll No = some variable")
while(studentList.next())
{
Name=studentList.value(0).toString();
address=studentList.value(1).toString();
QTimer:: singleShot(1000,this,SLOT(StopNow())); //calling stopNow function
if(StopPrintingNow==0)
{ //** I am printing the fetched data (in a string) by setting GPIO pins HIGH **// }
}
}
2. StopPrinting_Pressed :
void MainWindow::on_StopPrinting_Pressed()
{StopPrintingNow=1;}
3. StopNow Function Declaration :
void MainWindow::StopNow()
{
if(StopPrintingNow==1)
{ //** I have reset all serials ports; Break; **// }
else if(StopPrintingNow==0)
{ QTimer::singleShot(1000,this,SLOT(on_startPrinting_pressed())); }
}
C) Flow of program execution : As and when "StartPrinting" pushbutton is pressed, the query shown in my question executes which fetches data from database and perform simultaneous printing.
D)Problem Faced -
1.GUI is getting hanged while printing, hence StopPrinting button doesn't respond.
Qtimer is not calling "StopNow function " while printing (though I have called it at correct position)enter image description here
Handling of timers and button presses is both covered by the Qt event loop -- which is blocked while you are looping over that SQL query. You have two options:
1) Periodically dispatch events in your while loop.
This is as simple as
qApp->processEvents();
But you have to be careful, however: any events you trigger due to user interaction (or a timer) will block and your while loop will not run until the event is finished. In your case especially, you could end up running a second copy of your on_StartPrinitng_Pressed function.
2) Do the printing on a separate thread.
This involves some more code, but the gist of it is that you create a SqlPrinter object with a startPrinting slot and stopPrinting slot. You then create a QThread and change its owner thread to that thread. Slot invocations will happen across the thread boundary and all will be fine.
class SqlPrinter : public QObject {
Q_OBJECT
public:
SqlPrinter(QObject* parent = nullptr) : QObject(parent) {}
public slots:
void startPrinting();
void stopPrinting();
};
In your main code, then do something like this, assuming that you have the two buttons named MainWindow_StartButton and MainWindow_StopButton:
QThread* printerThread = new QThread(qApp);
SqlPrinter* printer = new SqlPrinter;
printer->moveToThread(printerThread);
printerThread->start();
QObject::connect(MainWindow_StartButton, &QPushButton::clicked, printer, &SqlPrinter::StartPrinting);
QObject::connect(MainWindow_StopButton, &QPushButton::clicked, printer, &SqlPrinter::StopPrinting);
Don't forget to clean up SqlPrinter afterwards!

Typecasting EventHandler in C++/CLI

I have a form (which I'll call MainForm) embedded with a TabControl. Every time the user creates a new tab it is filled with an instance of a pre-built Panel (which I'll call MyPanel) which contains many controls.
My MyPanel class has a private variable bool save_state which is set to false every time one of the (editable) controls is edited and set to true when the user "saves" the state of the panel.
I want a visual flag to keep track of tabs that have unsaved changes (e.g. the tab "Tab1" will instead display the text "Tab1 *" if it has unsaved changes). So I want to set up the event handler in my MainForm which can call a method in MyPanel to add the handler to each control.
Since not all my controls use the same EventHandler type (for example, I also need to track DataGridViewRowsAddedEvent, among others), I currently have several methods adding the appropriate handler to the corresponding controls (one for each type of Event Handler), each of which is running the same code (i.e. set the save_state bit to false and append " *" to the tab text.
For example, in MainForm.cpp I have:
#include "MyPanel.h"
void markUnsaved(void) {
// set panel bit to false
// append " *" to tab text if we haven't already
}
void MainForm::handler1(Object ^sender, EventArgs ^e) {
markUnsaved();
}
void MainForm::handler2(Object ^sender, DataGridViewRowsAddedEventArgs ^e) {
markUnsaved();
}
void Main::FormaddNewPanelToTab(int tab_index) {
// check index is valid ...
// make the new panel
MyPanel ^new_panel = gcnew MyPanel();
new_panel->addEventHandlerToControls(gcnew EventHandler(this, &MainForm::handler1));
new_panel->addDgvEventHandlerToControls(gcnew DataGridViewRowsAddedEventHandler(this, &MainForm::handler2));
// rest of code...
}
Though this currently works as intended, this (along with the several other Event Handler types I have to manage) makes my code look really silly.
I am hoping to be able to have have a single event handler in MainForm and a single method in MyPanel which type-casts the Event Handler passed and adds it to all the controls with the appropriate types.
I have tried doing simple casts such as:
void MyPanel::addHandlerToControls(EventHandler ^handler) {
control_NUD->ValueChanged += handler; // this works because ValueChanged is of type EventHandler
control_DGV->RowsAdded += (DataGridViewRowsAddedEventHandler ^)handler; // this compiles but throws an exception
// rest of the code...
}
to no avail.
Any help would be greatly appreciated!
I know this is maybe a bit late for answer but I'd want to show how would I solve this.
Firs of all I suggest to get rid from idea of casting event handlers. Kind of such approach may work in C# (with some adjustments) but as far as I know it's not possible in C++ /CLI.
I'd go for adding new event to a MyPanel class that will be invoked every time when the data on a panel is changed. But to avoid adding a lot of different handlers to a control events in a MyPanel class it's better to create one generic method that will handle all the neccessary control's events and fire new event. Maybe this sounds messy, let me show the code:
public ref class MyPanel
{
// Add a new event
public:
event EventHandler^ DataChanged;
// Add a method that will fire new event
// this methid will be invoked on every control's event that you'll subscribe
private:
generic <typename T>
void DataChangedHandler(System::Object^ sender, T e)
{
// Fire the event
DataChanged(this, EventArgs::Empty);
}
// Once the controls are initialized you may add the event handlers
// I put it in a constructor only for example
MyPanel()
{
control_NUD->ValueChanged += gcnew EventHandler(this, &MyPanel::DataChangedHandler<EventArgs^>);
control_DGV->RowsAdded += gcnew DataGridViewRowsAddedEventHandler(this, &MyPanel::DataChangedHandler<DataGridViewRowsAddedEventArgs^>);
// and so on...
}
}
/// And now in a main form we only need to subscribe to a DataChanged event
public ref class MainForm
{
//...
// the handler
void MyHandler(Object^ sender, EventArgs^ e)
{
markUnsaved();
}
void FormaddNewPanelToTab(int tab_index)
{
// make the new panel
MyPanel ^new_panel = gcnew MyPanel();
new_panel->DataChanged += gcnew EventHandler(this, &MainForm::MyHandler);
}
//...
}
Hope this helps.

No double / Only one QMessageBox at same time

In my application, I have the following situation:
In a verify-method for inputs of a QTabWidget, I'm coming to determine an error for a sub-widget's input.
In cause of that I set this sub-widget as the active widget
In showEvent of this widget I'm firing an QTimer::singleShot to a method onShowEventFinished() in which I'm going to show a QMessageBox
After activating the the new sub-widget, I want to show at first the error message from my verify (step 1).
So then the message from verify shows up, but then in cause of my singleShot in step 3 the other one show up over it. I want to show the second one at the earliest, when the first one is closed.
(It's important that the first message shows up at the earliest when the regarding sub widget ist showing.)
Example code:
class MySubwidget : public QWidget
{
// omitted (ctor, etc.)
protected:
void showEvent( QShowEvent* e )
{
QShowEvent( e );
QTimer::singleShot( 200, this, SLOT(onShowEventFinished()) );
};
private slots:
void onShowEventFinished()
{
bool showEntryHint = false;
// omitted (some stuff to determine to show an entry hint or not)
if( showEntryHint )
{
QMessageBox t_MessageBox( this );
// omitted (set up the message box
t_MessageBox.exec();
}
};
};
I've tried different ways to solve this with QMutex, QWaitCondition or QSemaphore in a derived class from QMessageBox but this doesn't work because the execution of the message box is in the same thread.
This means, when the first message box is started with QMessageBox::exec() than QApplication::processEvents (called by QMessageBox) caused the invokement of my slot and called QMessageBox::exec() twice (for the second hint, while the first exec() is alive until the first message box is closed).
My currently workaround is now to have a subclass where I'm calling QApplication::processEvents() as long as another instance of MyMessageBox is shown:
class MyMessageBox : public QMessageBox
{
public:
// omitted (ctor, etc.)
int exec()
{
while( MessageBoxShowingCount > 0 )
QApplication::processEvents();
return QMessageBox::exec();
};
protected:
void showEvent( QShowEvent* e )
{
MessageBoxShowingCount++;
QMessageBox::showEvent(e);
};
void hideEvent( QHideEvent* e )
{
QMessageBox::hideEvent(e);
MessageBoxShowingCount--;
};
static int MessageBoxShowingCount = 0;
};
(For this solution I have replaced all my QMessageBox-instances by an MyMessageBox-instance.)
What you seem to need is an application-wide message manager. The QMessageBox then becomes that class's implementation detail and is not used directly anymore. When you want to show a message, you'd then use your MessageManager class.

Why CListCtrl Update() not necessary in the example below?

In the code below the ListCtrl will not update the item if i do not use "Update()" after the first "If" conditon but will update even if there is no "Update()" method called after the Second "If" conditon. Why is this? I'm just curious to know when Update() is necessary and when it is not!
class MyDialog()
{
public:
void MyFunction();
private:
CListCtrl myListControl;
}
void MyDialog::Myfunction()
{
bool bCondition;
for (auto i = 0, i < myListControl.GetItemCount(); ++i)
{
auto n = myListControl.SetItemText(i, 1, "Start");
if (n)
myListControl.Update(i);
/*Update() is required here */
EvaluateCondition( bConditon);
if(bConditon)
myListControl.SetItemText(i, 1, "End");
/* Why is Update() ***Not*** required here? */
}
}
Update causes the change to be put on the screen immediately. If you don't call it, Windows automatically puts the change on the screen when your message loop next runs (after your MyFunction exits). This is why you need to call it to see "Start", before you change it to "End". Windows automatically updates it to "End" when your function exits.
How can you answer question Why X is true? if X is false???
When you set some item's text - the list control invalidates the corresponding area; eventually, when it comes to painting - it will redraw the new text.
According to MSDN (CListCtrl::Update):
Forces the list view control to repaint the item specified by nItem.
So you can see the result immediately.

Implementing a "window" system and "no deletion of self" rule

I've been trying to program in C++ a sort of simple "window" system for use in a game, which draws windows that can have buttons, etc. in them in the game area (internal to the game's own graphics, i.e. not the OS's GUI windows). The window objects (call it "class Window" for here) have some methods for events like key press, and the ability to hook on a handler to be called upon receipt of that event.
Windows are (or will be) collected in a "window manager", and the window object will have "close()" member that would call the parent window manager's window-deletion routine to delete itself. An event handler hooked to, say, a button on the window might invoke this routine to close the window (think an "OK" box).
The trouble is this sounds like a "delete *this;" statement, which I've heard is a no-no. True, it doesn't do that directly, but the effect is the same: an object has a member function that brings about its own destruction (e.g. the "close()" function, or the event function that triggers the handler leading to the "close()" function being called.). If this is bad, then what is a better way to design this?
There is nothing wrong with an object deleting itself. You must simply tell the window manager to remove the window from it's collection and then delete. If you have the window manager delete the window object, that's even better.
If you really want to avoid this behavior, you can add a bool dead; to each window that initializes to false. When the window is to be closed, set this->dead = true;. Every frame, have the window manager iterate through it's windows and delete the ones that are dead.
Note that this solution still does not fix errors that arise from external systems that have a reference to the deleted window, but it does have the advantage of centralizing the deletion of windows.
I have designed many games' window systems, and in my experience, allowing windows to delete themselves is a very elegant solution, even if it is more error-prone.
A minimal example:
class Window
{
public:
void keyPressCallback(int c)
{
if (c == KEY_ESC)
{
manager.destroy(this);
return;
}
}
WindowManager& manager;
};
class WindowManager
{
public:
void destroy(Window* target)
{
delete target;
windows.erase(std::find(windows.begin(), windows.end(), target));
}
std::vector<Window*> windows;
};
As long as there are no remaining pointers to that window, this method is perfectly safe and semantically sane. When the window receives a signal to close, it closes itself.
The same example with the dead flag:
class Window
{
public:
Window() : dead(false) {}
void keyPressCallback(int c)
{
if (c == KEY_ESC)
{
dead = true;
return;
}
}
bool dead;
};
class WindowManager
{
public:
void cleanup()
{
for (auto iter = windows.begin(); iter != windows.end(); ++iter)
{
if (iter->dead) windows.erase(iter);
}
}
std::vector<Window*> windows;
};