Infinite recursion with Qt coupled signal/slot - qt

I think I have some fundamental misunderstanding of how the Qt signal/slot mechanism works.
I have worked through example programs and they make sense but when I've tried to take those and modify them I have been getting results I do not understand. I have attach a code sample below that is a boiled-down version of what I was trying to do that certainly does not do what I want it to. Am I misusing the signal/slot mechanism and or the QString class? Is the way I am using the signal/slot to modify things in a coupled fashion creating an infinite loop? Any help greatly appreciated.
// test.cpp
#include <QApplication>
#include <QDialog>
#include <QLineEdit>
#include <QString>
#include <QVBoxLayout>
class myDialog : public QDialog
{
Q_OBJECT
public:
myDialog() : a_( new QLineEdit ), b_( new QLineEdit )
{
QVBoxLayout* layout( new QVBoxLayout( this ) );
layout->addWidget( a_ );
layout->addWidget( b_ );
connect( a_, SIGNAL( textChanged( const QString& ) ),
this, SLOT( aChanged( const QString& ) ) );
connect( b_, SIGNAL( textChanged( const QString& ) ),
this, SLOT( bChanged( const QString& ) ) );
}
private:
QLineEdit* a_;
QLineEdit* b_;
private slots:
void aChanged( const QString& qs );
void bChanged( const QString& qs );
};
#include "test.moc"
void myDialog::aChanged( const QString& qs )
{
b_->setText( QString::number( 2.0 * qs.toDouble() ) );
}
void myDialog::bChanged( const QString& qs )
{
a_->setText( QString::number( 3.3 * qs.toDouble() ) );
}
int main( int argc, char** argv )
{
QApplication a( argc, argv );
myDialog d;
d.show();
return a.exec();
}

Because In aChanged, you edit the b QLineEdit, it triggers the textChanged() signal for b...causing it to call bChanged, changing a..... etc. etc.
I think that is your problem here.
You might want to use textEdited() in stead.

Not so critical in this case, but please pay attention to delete a_ and b_ in the destructor since they dont have any parent.

Related

Deleting QQuickView on exit cause Qt application to freeze

I founded a deadlock in Qt 5.3. How to fix in correctly? Without ugly fix (not to delete qquickview *)
I have a singleton with a pointer to QQuickView. When I need to close my application I do a call of QGuiApplication::quit() and try to release QQuickView * in destructor of singlenot. Result - application freezes.
Sample:
test.qml
import QtQuick 2.1
Rectangle
{
id: root;
color: "black";
signal quit();
Component.onDestruction: quit();
}
main.cpp
#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
#include <QPointer>
struct Singleton
{
QPointer< QQuickView > w;
static Singleton inst;
int run( int argc, char *argv[] )
{
QGuiApplication a( argc, argv );
w = new QQuickView();
QObject::connect( w, &QQuickView::statusChanged, [=]()
{
QObject::connect( w->rootObject(), SIGNAL( quit() ), qApp, SLOT( quit() ) );
} );
w->setSource( QUrl( "qrc:/test.qml" ) );
w->setResizeMode( QQuickView::SizeRootObjectToView );
w->show();
a.exec();
return 0;
}
~Singleton()
{
delete w; // Comment this to fix bug
}
};
Singleton Singleton::inst;
int main(int argc, char *argv[] )
{
Singleton::inst.run( argc, argv );
return 0;
}
P.S. C++0x is used for simplifying code. Same result on C++03 compilers.
It was a bug in Qt. Fixed since 5.4 version.

Capture QML drawing buffer, without displaying

I need to grab each QML (QtQuick 2) drawing frame and sent it over the network.
At the moment I have used method listed below, but this method has two big disadvantage
1) Due to Qt5 documentation grabWindow() function has performance issues
2) It can't work with hidden QML window
Is it possible to get OpenGL render buffer right after QQuickWindow::afterRendering ?
Using FBOs ? Shared opengl context ?
class Grab: public QObject
{
public:
Grab( QQuickWindow * wnd ) : wnd_(wnd) {}
public slots:
void Grabme()
{
QImage image = wnd_->grabWindow();
}
private:
QQuickWindow *wnd_;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/grab1/main.qml"));
viewer.showExpanded();
Grab grab( &viewer );
QObject::connect( &viewer, &QtQuick2ApplicationViewer::frameSwapped,
&grab, &Grab::Grabme, Qt::DirectConnection );
return app.exec();
}
Example bellow can grab any qml content to FBO and then sent it as Image via signal.
Only one problem of this approach is visibility, grab window must be visible for successful grabbing. If anybody knows how to prevent this you can help me and provide more advanced approach.
// main.cpp
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
GrabWindow grab;
grab.setResizeMode( QQuickView::SizeViewToRootObject );
grab.setSource( QUrl::fromLocalFile("qml/main.qml") );
grab.setFlags( Qt::Popup );
grab.show();
return app.exec();
}
// grabwindow.hpp
#pragma once
#include <QOpenGLFramebufferObject>
#include <QScopedPointer>
#include <QQuickView>
#include <QImage>
class GrabWindow: public QQuickView
{
Q_OBJECT
signals:
void changeImage( const QImage &image );
public:
GrabWindow( QWindow * parent = 0 );
private slots:
void afterRendering();
void beforeRendering();
private:
QScopedPointer<QOpenGLFramebufferObject> fbo_;
};
// grabwindow.cpp
#include "grabwindow.hpp"
#include <limits>
GrabWindow::GrabWindow( QWindow * parent ) :
QQuickView( parent )
{
setClearBeforeRendering( false );
setPosition( std::numeric_limits<unsigned short>::max(), std::numeric_limits<unsigned short>::max() );
connect( this, SIGNAL( afterRendering() ), SLOT( afterRendering() ), Qt::DirectConnection );
connect( this, SIGNAL( beforeRendering() ), SLOT( beforeRendering() ), Qt::DirectConnection );
}
void GrabWindow::afterRendering()
{
if( !fbo_.isNull() )
{
emit changeImage( fbo_->toImage() );
}
}
void GrabWindow::beforeRendering()
{
if (!fbo_)
{
fbo_.reset(new QOpenGLFramebufferObject( size(), QOpenGLFramebufferObject::NoAttachment) );
setRenderTarget(fbo_.data());
}
}
I managed to find a trick to make grabWindow() work when the Window is "not visible". The trick is to set the window's visibility: Window.Minimized and the flags: Qt.Tool. The window is not displayed to the user, but to the Qt's internals it appears to be visible and the grabWindow() method call works as expected. Remember to call that method only once the scene has been initialised.
The only problem with this solution (that I have come across) is that if the window's color property is set to transparent, the captured content has black background.
With later versions of Qt 5.X you can also use the software render backend.
The following renders any scene in the background without any visible window or OpenGL tricks:
// main.cpp
#include <QGuiApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQuickItem>
#include <QQuickWindow>
#include <QQuickRenderControl>
int main(int argc, char *argv[])
{
const char *source = "qrc:/main.qml";
if (argc > 1) source = argv[1];
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
QGuiApplication app{argc, argv};
QQuickRenderControl renderControl;
QQuickWindow window{&renderControl};
QQmlEngine engine;
QQmlComponent component{
&engine,
QUrl{QString::fromUtf8(source)}
};
QQuickItem *rootItem = qobject_cast<QQuickItem *>(component.create());
window.contentItem()->setSize(rootItem->size());
rootItem->setParentItem(window.contentItem());
window.resize(rootItem->size().width(), rootItem->size().height());
QImage image = renderControl.grab();
image.save("output.png");
return 0;
}

Customizing scrollbar over QListWidget

I'd like to implement my own semi-transparent scrollbar, that draws on top of the QListWidget instead of taking up permanent space in its viewport. I do not wish to use QML as my QListWidget and its dynamic content is already fully developed over 6 months now.
How can I achieve that. Stylesheets are useless for that purpose as they will not determine the positioning of the scrollbar. I'd like it to be on top of the QListWidget, not on its side, taking up its space.
I'm talking about something in the neighborhood of this:
Any hints as to how to do that will be appreciated.
What you are trying to do is a perfect example of one thing that persistently annoys me about qt - if there is some graphical effect that Qt's designers haven't thought of, creating it on your own is a pain, constant fight against Qt, and usually ends with giving up anyway.
I suspect that you do it with small screens on your mind (cell phones? tablets?), so i guess there is no other way to solve this problem.
What I am trying here is hacky, but otherwise you would probably have to rewrite entire scrollbar yourself just to add those few missing details. My proposition is:
#ifndef MYSCROLLBAR_H
#define MYSCROLLBAR_H
#include <QScrollBar>
class MyScrollBar : public QScrollBar
{
Q_OBJECT
public:
explicit MyScrollBar(QWidget *parent = 0);
protected:
void showEvent ( QShowEvent * event );
signals:
public slots:
void updateMask();
};
#endif // MYSCROLLBAR_H
And in myscrollbar.cpp
#include "myscrollbar.h"
#include <QPaintEvent>
#include <QRegion>
#include <QStyleOptionSlider>
MyScrollBar::MyScrollBar(QWidget *parent) :
QScrollBar(parent)
{
connect(this, SIGNAL(valueChanged(int)), this, SLOT(updateMask()));
}
void MyScrollBar::updateMask(){
QStyleOptionSlider opt;
initStyleOption(&opt);
QRegion r(style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, this));
r+= style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarAddLine, this);
r+= style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSubLine, this);
setMask(r);
}
void MyScrollBar::showEvent ( QShowEvent * event ){
QScrollBar::showEvent(event);
updateMask();
}
Such scroller will be transparent (both visually and event-wise) in any of it's non-vital parts. It still creates some artifacts on widgets laying below it - I guess setMask() was never supposed to be used like this. To mitigate it you can connect valueChanged() signal to update() slot of the viewport of your list widget. This worked nice on my toy-example, but if you embed custom widgets in your list it might become unbearable to cope with. It might also run you into performance problems in case of more complex applications - especially if you write for mobile platforms.
Alternatively you can just "fork" entire QScrollBar class and simply modify it's paintEvent to use less subControls than SC_All - with additional setAttribute(Qt::WA_OpaquePaintEvent, false); in constructor it should provide visual transparency. Then you should also forward mouse events (if not hitting anything important) to your viewport of list widget (again, trouble with custom widgets in view).
Now what remains is writing your own layout class (or just manually positioning it) that will put both listview and scrollbar on one another in correct positions - QStackedLayout sounds nice, but it allows only one layer to be visible at any given time - clearly not what we are looking for.
Last step is switching off default scrollbars on view, and connecting signals/slots of the default (invisible) scrollbar to slots/signals of your scrollbar, to achieve effect of actual scrolling.
Shortly this will require a LOT of coding to get done. Are you sure that such a simple effect is worth it?
** EDIT: **
I create a layout class for stacking widgets on top of one another - this question gave me motivation to do it finally ;)
#ifndef STACKLAYOUT_H
#define STACKLAYOUT_H
#include <QLayout>
class StackLayout : public QLayout
{
Q_OBJECT
public:
StackLayout();
explicit StackLayout(QWidget *parent);
~StackLayout();
void addItem ( QLayoutItem * item );
int count () const;
Qt::Orientations expandingDirections () const;
bool hasHeightForWidth () const;
int heightForWidth ( int w ) const;
QLayoutItem * itemAt ( int index ) const;
bool isEmpty () const;
QSize maximumSize () const;
int minimumHeightForWidth ( int w ) const;
QSize minimumSize () const;
void setGeometry ( const QRect & r );
QSize sizeHint () const;
QLayoutItem * takeAt ( int index );
private:
QList<QLayoutItem *> itemList;
};
#endif // STACKLAYOUT_H
And the stacklayout.cpp file:
StackLayout::StackLayout()
:QLayout()
{}
StackLayout::StackLayout(QWidget *parent) :
QLayout(parent)
{
}
StackLayout::~StackLayout(){
QLayoutItem *item;
foreach (item, itemList){
delete item;
}
}
void StackLayout::addItem ( QLayoutItem * item ){
itemList.append(item);
}
int StackLayout::count () const{
return itemList.count();
}
Qt::Orientations StackLayout::expandingDirections () const{
Qt::Orientations result = 0;
QLayoutItem *item;
foreach (item, itemList){
result = result | item->expandingDirections();
}
return result;
}
bool StackLayout::hasHeightForWidth () const{
QLayoutItem *item;
foreach (item, itemList){
if (item->hasHeightForWidth())
return true;
}
return false;
}
int StackLayout::heightForWidth ( int w ) const{
int result = 0;
QLayoutItem *item;
foreach (item, itemList){
if (item->hasHeightForWidth())
result = qMax(result, item->heightForWidth(w));
}
return result;
}
QLayoutItem * StackLayout::itemAt ( int index ) const{
if (index<itemList.count())
return itemList[index];
return 0;
}
bool StackLayout::isEmpty () const{
QLayoutItem *item;
foreach (item, itemList){
if (!item->isEmpty())
return false;
}
return true;
}
QSize StackLayout::maximumSize () const{
QSize result=QLayout::maximumSize();
QLayoutItem *item;
foreach (item, itemList){
result = result.boundedTo(item->maximumSize());
}
return result;
}
int StackLayout::minimumHeightForWidth ( int w ) const{
int result = 0;
QLayoutItem *item;
foreach (item, itemList){
if (item->hasHeightForWidth())
result = qMax(result, item->minimumHeightForWidth(w));
}
return result;
}
QSize StackLayout::minimumSize () const{
QSize result=QLayout::minimumSize();
QLayoutItem *item;
foreach (item, itemList){
result = result.expandedTo(item->minimumSize());
}
return result;
}
void StackLayout::setGeometry ( const QRect & r ){
QLayoutItem *item;
foreach (item, itemList){
item->setGeometry(r);
}
}
QSize StackLayout::sizeHint () const{
QSize result=QSize(0,0);
QLayoutItem *item;
foreach (item, itemList){
result = result.expandedTo(item->sizeHint());
}
return result;
}
QLayoutItem * StackLayout::takeAt ( int index ){
if (index < itemList.count())
return itemList.takeAt(index);
return 0;
}
Assuming you already have some nice transparent scrollbar, to insert it you would do:
QWidget* w = new QWidget();
StackLayout* sl = new StackLayout(w);
QListView* lv = new QListView(w);
sl->addWidget(lv);
QHBoxLayout* hbl = new QHBoxLayout();
sl->addItem(hbl);
TransparentScrollBar* tsc = new TransparentScrollBar(w);
hbl->addWidget(tsc,0);
hbl->insertStretch(0,1);
Here is sample code for your questoin.
Not done:
Mouse dragging of scroller
Done:
Support of any mouse hover/leave events
Support of scrolling
Scroll bar is transparent for mouse events
It is good start point for any customization depending on you task. Usage:
GUI::MegaScrollBar *bar = new GUI::MegaScrollBar( ui->listWidget );
bar->resize( 40, 30 ); // First arg - width of scroller
MegaScrollBar.h
#ifndef MEGASCROLLBAR_H
#define MEGASCROLLBAR_H
#include <QWidget>
#include <QPointer>
class QAbstractItemView;
class QResizeEvent;
namespace GUI
{
class MegaScrollBar
: public QWidget
{
Q_OBJECT
public:
MegaScrollBar( QAbstractItemView *parentView );
~MegaScrollBar();
private slots:
void updatePos();
private:
bool eventFilter( QObject *obj, QEvent *event );
void onResize( QResizeEvent *e );
void paintEvent( QPaintEvent * event );
void resizeEvent( QResizeEvent * event );
QPointer< QAbstractItemView > m_view;
QPointer< QWidget > m_scrollBtn;
};
}
#endif // MEGASCROLLBAR_H
MegaScrollBar.cpp
#include "MegaScrollBar.h"
#include <QAbstractItemView>
#include <QEvent>
#include <QResizeEvent>
#include <QScrollBar>
#include <QDebug>
#include <QPainter>
#include "ScrollButton.h"
namespace GUI
{
MegaScrollBar::MegaScrollBar( QAbstractItemView *parentView )
: QWidget( parentView, Qt::FramelessWindowHint )
, m_view( parentView )
{
Q_ASSERT( parentView );
setAttribute( Qt::WA_TranslucentBackground );
setAttribute( Qt::WA_TransparentForMouseEvents );
m_scrollBtn = new ScrollButton( parentView );
m_scrollBtn->setFixedSize( 20, 40 );
m_view->installEventFilter( this );
QScrollBar *sb = m_view->verticalScrollBar();
connect( sb, SIGNAL( valueChanged( int ) ), this, SLOT( updatePos() ) );
}
MegaScrollBar::~MegaScrollBar()
{
removeEventFilter( m_view );
}
bool MegaScrollBar::eventFilter( QObject *obj, QEvent *event )
{
switch ( event->type() )
{
case QEvent::Enter:
m_scrollBtn->show();
break;
case QEvent::Leave:
m_scrollBtn->hide();
break;
case QEvent::Resize:
onResize( static_cast< QResizeEvent * >( event ) );
break;
}
return QWidget::eventFilter( obj, event );
}
void MegaScrollBar::onResize( QResizeEvent *e )
{
const int x = e->size().width() - width();
const int y = 0;
const int w = width();
const int h = e->size().height();
move( x, y );
resize( w, h );
updatePos();
}
void MegaScrollBar::updatePos()
{
QScrollBar *sb = m_view->verticalScrollBar();
const int min = sb->minimum();
const int val = sb->value();
const int max = sb->maximum();
const int x = pos().x() + ( width() - m_scrollBtn->width() ) / 2;
if ( max == 0 )
{
m_scrollBtn->move( x, pos().y() );
return ;
}
const int maxY = height() - m_scrollBtn->height();
const int y = ( maxY * val ) / max;
m_scrollBtn->move( x, y );
}
void MegaScrollBar::paintEvent( QPaintEvent * event )
{
Q_UNUSED( event );
QPainter p( this );
QRect rc( 0, 0, rect().width() - 1, rect().height() - 1 );
// Draw any scroll background
p.fillRect( rc, QColor( 255, 255, 200, 100 ) );
}
void MegaScrollBar::resizeEvent( QResizeEvent * event )
{
Q_UNUSED( event );
updatePos();
}
}
Preview:
It is possible to set up any widget for scroll button: Here is custom one:
ScrollButton.h
#ifndef SCROLLBUTTON_H
#define SCROLLBUTTON_H
#include <QWidget>
namespace GUI
{
class ScrollButton
: public QWidget
{
Q_OBJECT
public:
ScrollButton( QWidget *parent );
~ScrollButton();
private:
void paintEvent( QPaintEvent * event );
};
}
#endif // SCROLLBUTTON_H
ScrollButton.cpp
#include "ScrollButton.h"
#include <QPainter>
#include <QGraphicsOpacityEffect>
#include <QColor>
namespace GUI
{
ScrollButton::ScrollButton( QWidget *parent )
: QWidget( parent )
{
QGraphicsOpacityEffect *op = new QGraphicsOpacityEffect( this );
op->setOpacity( 0.5 );
setGraphicsEffect( op );
}
ScrollButton::~ScrollButton()
{
}
void ScrollButton::paintEvent( QPaintEvent * event )
{
Q_UNUSED( event );
// Draw any scroll button
QPainter p( this );
QRect rc( 5, 5, rect().width() - 6, rect().height() - 6 );
p.fillRect( rc, QColor( 0, 0, 0, 255 ) );
}
}
Please comment, if you can't handle mouse interaction.

(Qt) Unusable window after one button click

I have a window with many buttons. Each one triggers a sub-program (written using the Opencv API). Each sub-program displays images and stuff on windows.
The problem is, when I close these windows (via the little red cross), all the buttons become unclickable. So if I want to launch another program, I'll have to exit the main window and run it again.
In other words, I want to be able to run all the sub-programs without having to start over every time.
Here's the GUI's code :
.cpp
#include "fenprincipale.h"
#include "ui_fenprincipale.h"
#include<highgui.h>
#include<cv.h>
#include <moyenetmedian.h>
#include<morpho.h>
#include<tracking.h>
#include<contour.h>
#include<QApplication>
FenPrincipale::FenPrincipale(QWidget *parent) :
QWidget(parent),
ui(new Ui::FenPrincipale)
{
ui->setupUi(this);
MoyenEtMedian *moyenEtMedian = new MoyenEtMedian;
morpho * mor = new morpho;
tracking * tra= new tracking;
contour * cont= new contour;
QObject::connect(ui->bMoyMed, SIGNAL( clicked() ), moyenEtMedian, SLOT( exec() ), Qt::AutoConnection );
QObject::connect(ui->bMorph, SIGNAL( clicked() ), mor, SLOT( exec() ), Qt::AutoConnection );
QObject::connect(ui->bTrack, SIGNAL( clicked() ), tra, SLOT( exec() ), Qt::AutoConnection );
QObject::connect(ui->bCont, SIGNAL( clicked() ), cont, SLOT( exec() ), Qt::AutoConnection );
}
FenPrincipale::~FenPrincipale()
{
delete ui;
}
.h :
#ifndef FENPRINCIPALE_H
#define FENPRINCIPALE_H
#include <QWidget>
#include <QApplication>
namespace Ui {
class FenPrincipale;
}
class FenPrincipale : public QWidget
{
Q_OBJECT
public:
explicit FenPrincipale(QWidget *parent = 0);
void switch_callback(int);
void execMoyMed (void);
~FenPrincipale();
private:
Ui::FenPrincipale *ui;
};
#endif // FENPRINCIPALE_H
the main class :
#include <QCoreApplication>
#include <QApplication>
#include <QtGui>
#include <QWidget>
#include "fenprincipale.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FenPrincipale fenetre;
fenetre.show();
return a.exec();
}
Slot implementation for "moyenetmedian" :
void MoyenEtMedian::exec(void)
{
const char* name = "Filtres";
IplImage* img = cvLoadImage( "C:/Users/XELTINFO/ProjetVision/image.png" );
IplImage* out = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 3 );
cvNamedWindow( name, 1 );
cvShowImage(name, out);
// Create trackbar
cvCreateTrackbar2( "Filtre", name, &g_switch_value, 1, &MoyenEtMedian::switch_callback, this );
while( 1 ) {
switch( filterInt ){
case 0:
cvSmooth( img, out, CV_BLUR, 7, 7 );
break;
case 1:
cvSmooth( img, out, CV_MEDIAN, 7, 7 );
break;
}
if(filterInt != lastfilterInt){
cvShowImage(name, out);
lastfilterInt = filterInt;
}
if( cvWaitKey( 15 ) == 27 )
break;
}
cvReleaseImage( &img );
cvReleaseImage( &out );
cvDestroyWindow( name );
}
The class declaration :
#ifndef MOYENETMEDIAN_H
#define MOYENETMEDIAN_H
#include "ui_fenprincipale.h"
#include<QObject>
class MoyenEtMedian : public QObject
{
Q_OBJECT
public:
MoyenEtMedian();
static void switch_callback(int position, void*);
public slots :
void exec(void);
};
#endif // MOYENETMEDIAN_H
The class delcarations and slots implementations are very similar for all classes. I'll add the rest if this isn't enough.
You are blocking the event loop in your exec() slot, since it doesn't return immediately. You should instead subclass QWidget and override keyPressEvent() to get keyboard input from Qt's event loop instead of doing the busy-loop you currently have.
So when using Qt with OpenCV, I would setup the polling using Qt's timers instead of a while loop.
There is a pretty good tutorial of using QTimers to interact with OpenCV objects here:
http://www.youtube.com/watch?v=0ONxIy8itRA
Jump to 35 or 38 minutes into it to see how he writes his classes.
Basically, you let Qt do the waiting and timing, instead of having a while loop with a wait call doing the timing.
And if possible, let Qt create the windows, and nest the OpenCV windows into Qt's windows so that Qt can manage the events on the windows.
Hope that helps.

clicked() signal in a button

I've got some problem with signal for a button in Qt 4.8.0. I am using vs 2010 with Qt Designer. I have created a button in Designer with playButton name. But after that I tried to connect clicked() signal (in vs) with my function from CRenderArea (to start a timer), but it seems that it doesn't work (the function start() works when I put it in the constructor, so it's not the problem of the code itself). The code is compiling, the program is executing, but after clicking a button - nothing happens (it should move a line).
I would be really thankful for some help, just started a fun with Qt.
The codes are here (I hope the number of files won't scare you, these are the simplest codes ever :) ):
main.cpp
#include "ts_simulator.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TS_simulator w;
w.show();
return a.exec();
}
ts_simulator.cpp:
TS_simulator::TS_simulator(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
p_map = new CRenderArea();
ui.setupUi( this );
p_map->setParent( ui.renderArea );
// this doesn't work, why?
connect( ui.playButton, SIGNAL( clicked() ), this, SLOT( p_map->start() ) );
}
CRenderArea.h
#pragma once
#include <QtGui>
class CRenderArea : public QWidget {
Q_OBJECT // I think it's necessary?
int x;
QBasicTimer* timer;
public:
CRenderArea();
public slots: // this is necessary too, right?
void start();
private:
void timerEvent( QTimerEvent* );
void paintEvent( QPaintEvent* );
};
and CRenderArea.cpp:
#include "CRenderArea.h"
CRenderArea::CRenderArea() : x( 0 ) {
setBackgroundRole( QPalette::Base );
setMinimumSize( 591, 561 );
setAutoFillBackground( true );
timer = new QBasicTimer();
}
void CRenderArea::timerEvent( QTimerEvent* e ) {
++x;
update();
}
void CRenderArea::paintEvent( QPaintEvent* p ) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGray);
painter.drawLine(2+x/10, 8, 60, 300);
}
void CRenderArea::start() {
timer->start( 0, this );
}
Greets.
The problem is here:
connect( ui.playButton, SIGNAL( clicked() ), this, SLOT( p_map->start() ) );
if p_map is the receiver of the signal, and it has Q_OBJECT, it should be written as:
connect( ui.playButton, SIGNAL( clicked() ), p_map, SLOT(start()) );

Resources