Does each QT widget have a 'show' signal? - c++

I wanted to do some action when a dialog shows when it opens or when it maximizes from a minimal status or it moves from out of a screen.
Does QT have such a signal?
I am also not sure where to find if QT has a list of signals defined.

Does each QT widget have a 'show' signal?
If you look at Qt source code then you will find QWidget::show to be a slot:
public Q_SLOTS:
// Widget management functions
virtual void setVisible(bool visible);
void setHidden(bool hidden);
void show();
The slot is mainly for us, programmers to make us able to connect with signals for specific purposes like clicking the button we created does something to certain widget. As for Windows or Mac OS, we have the app serving all the events coming from the system via event loop. And QWidget reacts on all the 'signals' in the form of system events coming and yes, may, execute show() or showMaximized() or showMinimized slots then.
But I can assume you want to overload
virtual void showEvent(QShowEvent *);
virtual void hideEvent(QHideEvent *);
Like:
void MyWidget::showEvent(QShowEvent *e)
{
if (isMaximized())
{
if (e->spontaneous())
{
// the author would like to know
// if the event is issued by the system
}
; // the action for maximized
}
else
{
; // the action for normal show
}
}
void MyWidget::hideEvent(QHideEvent *)
{
if (isMinimized())
{
; // the action for minimized
}
else
{
; // the action for hide
}
}
For recognizing cases when the system operates the widget we can use QEvent::spontaneous().
Please also refer to show and hide event doc pages:
http://doc.qt.io/qt-5/qshowevent-members.html
http://doc.qt.io/qt-5/qhideevent.html

Related

How to wait for window to be hidden in Qt?

I am hiding a Qt toolbox window in one of my functions. I need to do some screen capturing stuffs to be executed in function after hiding my toolbox window.
void ProcessData()
{
Toolbox::getInstance()->hide(); //I am trying to hide toolbox here
//screen capture stuffs. - It should be executed once the toolbox window is hidden.
}
But what happens is, Toolbox is hidden only when the ProcessData() returns. This leads to the problem that my captured screen have the toolbox.
Is there any way to wait for the toolbox to be hidden in Qt ?
Apart from using QApplication::processEvents, I would suggest you a more elegant solution:
Reimplement QWidget::hideEvent of the class returned by Toolbox::getInstance to emit a signal, e.g. widgetHidden
protected:
void hideEvent(QHideEvent *event) {
QWidget::hideEvent(event);
Q_EMIT widgetHidden();
}
signals:
void widgetHidden();
Connect widgetHidden to a slot to capture the screen
connect(Toolbox::getInstance(), &MyWidget::widgetHidden, this, &ClassName::onWidgetHidden);
where MyWidget is the class returned by Toolbox::getInstance and ClassName is the name of the class to which ProcessData belongs.
Add a flag to know if it is the right time to capture, as the widget might be hidden in some other way
bool m_captureAllowed = false;
Implement the onWidgetHidden slot
private slots:
void onWidgetHidden() {
if (m_captureAllowed) {
m_captureAllowed = false;
//screen capture stuffs
}
}
Set the flag in ProcessData
void ProcessData()
{
m_captureAllowed = true;
Toolbox::getInstance()->hide(); //I am trying to hide toolbox here
}

Calling function each time qt windows gain focus

I have a mainwindow which in there is a Qtableview by clicking on insert record I go to other modal windows to add record when I add record and close the second windows I come back to main windows but the qtableview doesn't show the new record that is added. The record is in database.
I already make this somehow work with :
void MainWindow::showEvent( QShowEvent* event ) {
QWidget::showEvent( event );
updTbl();
}
But it only works when windows get minimized.
QMainWindow has also two event handler from QWidget
void QWidget::focusInEvent(QFocusEvent *event)
void QWidget::focusOutEvent(QFocusEvent *event)
If you use QtCreator, go to your mainwindow.h and search the line "class MainWindow : public QMainWindow". Right click on QMainWindow -> Refactoring -> Insert virtual function. That's an easy way to find which virtual functions exist and that can be overloaded, you can select focusInEvent and focusOutEvent from there.
Handling activate/deactivate events as follows will give you the desired behaviour
// overloading event(QEvent*) method of QMainWindow
bool MainWindow::event(QEvent* e)
{
switch (e->type())
{
case QEvent::WindowActivate:
// gained focus
//Update Table
break;
case QEvent::WindowDeactivate:
// lost focus
break;
};
return QMainWindow::event(e);
}
Ref: https://gist.github.com/01walid/2276009

check when a button is clicked event qt

I am a beginner in Qt and I would like to know, how can I create an event which checks when a button in the windows gets clicked? The window has a single push button.
I could not find a simple and correct example for my question, that's why I am asking here. I did google first.
Thank you
class MyClass : public QWidget
{
public:
MyClass ()
{
QPushButton *pButton = new QPushButton(this);
QObject::connect(pButton, &QPushButton::clicked, this, &MyClass::onButtonClicked);
}
public slots:
void onButtonClicked () {qDebug () << "Button clicked";};
};
onButtonClicked will be called if the button pressed.
Please see signals & slots and QPushButton signals for more information.
Qt employs the signals and slots paradigm. You don't check if a button is clicked. When a button is clicked, it emits a signal. You can connect your own functions to that signal. So whenever that button is clicked, the signal is emitted, and triggers all the functions it is connected to.
Be sure to check out signals and slots, which is a core concept of Qt, along with properties and meta data.
Note that as a QWidget derived, a button comes with the following methods, which are triggered by mouse events and you can override them if you wish, although in the case of something as a button that is hardly necessary:
virtual void mouseDoubleClickEvent(QMouseEvent * event)
virtual void mouseMoveEvent(QMouseEvent * event)
virtual void mousePressEvent(QMouseEvent * event)
virtual void mouseReleaseEvent(QMouseEvent * event)

QML OpenGL plugin not redrawing at 60Hz

The Situation
My company has a QML-based application which displays some content using a custom OpenGL-based render plugin (MyGame). This plugin has a few critical needs:
To be able to effect changes in the renderer in response to QML-based signals.
(e.g. change the position of an object rendered by the game)
To only process these changes at a specific spot in MyGame's redraw loop.
(This is very important; MyGame is very sensitive about when changes are allowed.)
To have the plugin redraw at 60Hz (at least).
The Problem
The code we have right now honors (1) and (2), but fails (3); the plugin does not get visually updated consistently. (The updates are erratic, at an estimated 5-10Hz.) I believe that the plugin we have created—based on QQuickFramebufferObject—is not taking proper advantage of how Qt/QML intended the scene graph to be updated.
How can I re-structure my plugin so that I get all three of the above?
The Code
Overview:
The plugin creates a QQuickFramebufferObject (MyPlugin) and a QQuickFramebufferObject::Renderer (MyRenderer).
When MyRenderer::render() is called it calls MyGame::Redraw() itself, and then calls update().
MyGame::Redraw() does what it needs to, and at the right spot where changes can be accepted, emits a timeToMakeChanges QML signal on MyPlugin.
QML listens for the onTimeToMakeChanges signal and invokes methods on the plugin that affect MyGame.
To workaround the problem of low-frequency visual updates, I've found that if I overlay a QML Canvas over my plugin and redraw the canvas frequently using a Timer, my plugin starts to get visually updated at what appears to be around 60Hz. Clearly this is a gross hack.
Following is a summary of the code setup. Please forgive missing/incorrect code; I'm trying to distill thousands of lines of glue code down to the essentials for this question.
MyPlugin.h
#include <QOpenGLFramebufferObject>
#include <QQuickFramebufferObject>
class MyPlugin : public QQuickFramebufferObject {
Q_OBJECT
public:
MyPlugin();
virtual ~MyPlugin();
virtual QQuickFramebufferObject::Renderer* createRenderer() const;
signals:
void timeToMakeChanges();
public slots:
void makeChanges(QVariant inValue);
void HandleWindowChanged(QQuickWindow *inWindow);
private:
MyGame* GetGame() { ... }
};
MyPlugin.cpp
#include "MyPlugin.h"
#include <MyGame.h>
// ******************************************************************
class MyRenderer:
public QObject,
public QQuickFramebufferObject::Renderer,
protected QOpenGLFunctions
{
Q_OBJECT
public:
virtual void render();
private:
static void RequestGameChanges();
};
void MyRenderer::render() {
if ( !m_Initialized ) {
QOpenGLFramebufferObject *theFbo = this->framebufferObject();
InitializeGl( theFbo ); // Not shown
m_MyGame = &MyGame::Create();
m_MyGame->RegisterCallback(
reinterpret_cast<qml_Function>(MyRenderer::RequestGameChanges)
);
m_Initialized = true;
}
m_MyGame->RestoreState();
m_MyGame->Redraw();
m_MyGame->SaveState();
m_PluginItem->window()->resetOpenGLState();
// Tell QML that we want to render again as soon as possible
update();
}
// This gets invoked in the middle of m_MyGame->Redraw()
void MyRenderer::RequestGameChanges() {
emit m_PluginItem->timeToMakeChanges();
}
// ******************************************************************
MyPlugin::MyPlugin() {
setMirrorVertically(true);
connect(
this, SIGNAL(windowChanged(QQuickWindow*)),
this, SLOT(HandleWindowChanged(QQuickWindow*))
);
}
void MyPlugin::HandleWindowChanged(QQuickWindow *inWindow) {
inWindow->setClearBeforeRendering(false);
}
void MyPlugin::makeChanges(QVariant inValue) {
MyGame *theGame = GetGame();
// Send the requested changes to theGame
}
QQuickFramebufferObject::Renderer* MyPlugin::createRenderer() const {
m_Renderer = new MyRenderer( *this );
}
MyApp.qml
import MyPlugin 1.0
Window {
MyPlugin {
property var queuedUpChanges: ([])
onSomeOtherSignal: queueUpChangesToMake();
onTimeToMakeChanges: makeChanges( queuedUpChanges );
}
Canvas { id:hack }
Timer {
interval:10; running:true; repeat:true
onTriggered: hack.changeWhatYouShow();
}
}
Bonus Points
The main question is "How do I modify my code so that I get 60Hz updates?" However, as seen in the QML, the setup above requires me to queue up all changes in QML so that they are able to be applied during the right spot in the MyGame::Render().
Ideally, I'd prefer to write QML without timeToMakeChanges, like:
MyPlugin {
onSomeOtherSignal: makeChanges( ... );
}
If there's a way to accomplish this (other than queuing up the changes in C++ instead)—perhaps something related to synchronize() I'd love to know about it.
I'd make a timer in QML that calls the makeChanges regularly. But store all the state in MyPlugin. Then, in Renderer::synchronize(), copy from MyPlugin to MyRenderer, so it can be used by the MyGame.
(although, I wouldn't do any gamelogic-related calculations in QML ever in the first place)

QDialog exec() and getting result value

I have subclassed QDialog to implement functionality similar to QMessageBox ( I needed this to allow for customization). It has a text message and OK, Cancel buttons. I am showing the dialog using exec() to make it blocking. Now, how do I return values of true/false when the user clicks on OK/Cancel?
I tried connecting the buttons to setResult() and then, return the result value when clicked, but
Clicking the buttons does not close the dialog box
the return value is incorrect.
Following is the code I have written. I think I am wrong in the exec/result part - but I am not sure how to fix it.
class MyMessageBox : public QDialog {
Q_OBJECT
private slots:
void onOKButtonClicked() { this->setResult(QDialog::Accepted); }
void onCancelButtonClicked() { this->setResult(QDialog::Rejected); }
public:
MyMessageBox(QMessageBox::Icon icon, const QString& title,
const QString& text, bool showCancelButton = true,
QWidget* parent = 0);
virtual void resizeEvent(QResizeEvent* e);
QDialog::DialogCode showYourself()
{
this->setWindowModality(Qt::ApplicationModal);
this->exec();
return static_cast<QDialog::DialogCode>(this->result());
}
};
The user will instantiate the class and call showYourself() which is expected to return the value and also close(and delete) the dialog.
I have posted partial code. Let me know if you need more and I will post the complete version.
Some points :
Rather than using setResult() yourself, use QDialog::accept() and QDialog::reject().
It seems you are not taking full advantage of the signals and slots. You need the object which create the dialog (or another one) to listen to the signals of the dialog.
In your code you are not connecting signals to slots either.
With my fix onOKButtonClicked and onCancelButtonClicked are unnecessary.
With my fix you don't need showYourself(). Just call exec and with the events
information will flow.
You need to add this code before showing the dialog (this assume it is in a dialog method):
QObject::connect(acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
QObject::connect(rejectButton, SIGNAL(clicked()), this, SLOT(reject()));
In the caller object you have
void someInitFunctionOrConstructor(){
QObject::connect(mydialog, SIGNAL(finished (int)), this, SLOT(dialogIsFinished(int)));
}
void dialogIsFinished(int){ //this is a slot
if(result == QDialog::Accepted){
//do something
return
}
//do another thing
}
Another solution:
// set signal and slot for "Buttons"
connect(YesButton, SIGNAL(clicked()), dlg, SLOT(accept()));
connect(NoButton, SIGNAL(clicked()), dlg, SLOT(reject()));
// show modal window event loop and wait for button clicks
int dialogCode = dlg->exec();
// act on dialog return code
if(dialogCode == QDialog::Accepted) { // YesButton clicked }
if(dialogCode == QDialog::Rejected) { // NoButton clicked }
Case 1 Clicking the buttons does not close the dialog box.
For this you have to close the dialog on respective SLOTS, so Use
void onOKButtonClicked(){ this->setResult(QDialog::Accepted); this->close();}
void onCancelButtonClicked(){ this->setResult(QDialog::Rejected);this->close();}
Note: Only after you have clicked the Ok button or Cancel button in a standard QMessageBox, setResult() function is triggered and the status is changed. It's not the same effect when done vice versa.
Case 2 The return value is incorrect.
I think only after your dialog gets closed, you will have the result available in result() function. So I guess it will be solved, after you have made the changes specified in Case 1.
If it still persists, use your own private member function to resolve it.