I put a widget named myWiget in QMainWindow. The myWidget is promoted to a class named PaintImage (PaintImage *myWidget). Here what I am going to do is to draw image in the sub-widget myWidget by PaintImage in which painter method is called.
In the PaintImage.h, I have #include "mainwindow.h" and declare MainWindow *main. I use the pointer main to access some variables of interest defined there, e.g.:
int w = ui->myWidget->geometry().width();
int h = ui->myWidget->geometry().height();
Then in paintimage.cpp:
PaintImage::PaintImage(QWidget *parent) : QWidget(parent)
{
//these lines of codes cause the problem!
int w = main->w;
int h = main->h;
.......
}
void PaintImage::paintEvent(QPaintEvent * /*event*/)
{
//QPainter painter is called inside
}
Compiling the codes shows that:
The program has unexpectedly finished.
The process was ended forcefully.
What causes the problem? Cannot I access the MainWindow members from inside PaintImage? Thanks in advance!
Related
I need to post an Event from an thread to an QtreeView in my Mainwindow. Now to post an event we need the pointer to the Qobject (i.e. our qtreeview inside main window).
For this i have to take the pointer to my mainwindow in constructor MainWindow::MainWindow().
sharedobj.h file contains pointer to mainwindow :----
#include "ui_mainwindow.h"
/*!
Shared object among threads.
*/
class cntrlObj
{
public:
cntrlObj();
~ctrlObj();
/// Thread run control
bool m_bQuit;
/*!
Pointer to mainwindow window
*/
Ui::MainWindow *ui;
}
Mainwindow class contains following object :---
cntrlObj cntrlObj_obj;
Mainwindow constructor :-----
/*!
Take Pointer to Mainwindow session window
*/
cntrlObj_obj->ui_ptr->setupUi(this);
Please suggest is it an right way to take an pointer to Mainwindow ?
Also can i include file "ui_mainwindow.h" inside another sharedobj.h file to access namespace UI of mainwindow to declare an pointer as i have done in "sharedobj.h" file ?
You need to localize the knowledge within the Mainwindow, and post the event to it.
So:
Post the event to the Mainwindow instance.
Reimplement MainWindow::customEvent(...) as follows (if it's a custom QEvent, otherwise you'd reimplement event(...):
void MainWindow::customEvent(QEvent * ev) {
if (ev->type() == MyEventType) {
QCoreApplication::sendEvent(ui->treeView, ev);
}
}
Alas, why on Earth would you need to send an event to a view?
I am newbie to Qt 5.1.0. My problem with Qt is showed directly as follows. Data from serial port is received by readdata(), then call the draw() in mainwindow.cpp to deliver the data to newpaint() in paint.cpp. Two classes are created in this project:class mainwindow is mainly responsible for receiving data from serial port,class paint is for drawing the data (actually the data is coordinates of a mathematical function) on the scroll area widget which is on the mainwindow.
But in paint.cpp, paintevent is not invoked by update().UpdateEnabled() returns true depicting that the problem doesn't exist in the use of update().
Main part is pasted below.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QPainterPath linepath;
linepath.moveTo(0,0);
ui->setupUi(this);
paintwiget=new paint(linepath,ui->scrollArea);
ui->scrollArea->setWidget(paintwiget);
paintwiget->show();
ui->closeserial->setEnabled(false);
ui->sendData->setEnabled(false);
serial=new QSerialPort(this);
connect(serial,SIGNAL(readyRead()),this,SLOT(readData()));
}
void paint::newpaint(qreal *aa1, int len1)
{
if (!aa.isEmpty())
aa.clear();
int i;
for (i=0;i<len1;i++)
aa.append(aa1[i]);
// qDebug()<<aa.size();
//qDebug()<<"aa[0:3]"<<aa[0]<<" "<<aa[1]<<" "<<aa[2]<<" "<<aa[3];
len=len1;
// this->setVisible(true);
qDebug()<<this->isVisible();//now returns true
this->update();
//qDebug()<<"okla";
}
void paint::paintEvent(QPaintEvent *)
{
qDebug()<<"ok~~";
QPointF currentpoi;
QPainter painter(this);
int ii=0;
qDebug()<<len;
for (ii=0;ii<len/2;ii++)
{
currentpoi=path.currentPosition();
qDebug()<<"currentpoi"<<currentpoi;
path.moveTo(currentpoi);
path.lineTo(aa[2*ii],aa[2*ii+1]);
// painter.setRenderHint(QPainter::Antialiasing);
painter.drawPath(path);
}
}
paint.h
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QTabWidget>
//#include <mainwindow.h>
class paint : public QWidget
{
public:
explicit paint(QPainterPath &path,QWidget *parent=0);
void newpaint(qreal *,int);
QVector <qreal>aa;
int len;
QWidget *parent;
private:
QPointF point;
QPainterPath path;
protected:
void paintEvent(QPaintEvent *event);
};
Hard to say for sure that this is the only issues you are facing, but there are at least three issues:
Issue 1
The following code tells me that you have a member of MainWindow called paint * paintwiget:
void MainWindow::draw(qreal *aa,int len)
{
// ...
paintwiget->newpaint(dist,len);
}
Then, this code tells me that you are creating a new temporary variable of the same name:
MainWindow::MainWindow(QWidget *parent)
{
// ...
paint *paintwiget=new paint(linepath,ui->scrollArea->viewport());
}
The compiler should have probably given you a warning for this. Replace this line by:
paintwiget = new paint(linepath,ui->scrollArea->viewport());
(notice the lack of paint *), and tell me if this solves the problem.
Issue 2
You have to change this:
void paint::newpaint(qreal *aa, int len)
{
// ...
aa[i]=aa[i];
len=len;
}
by this:
void paint::newpaint(qreal *aa_new, int len_new)
{
// ...
aa[i]=aa_new[i];
len=len_new;
}
Otherwise, your aa[i]=aa[i] has no effect: it replaces the parameter of the method by itself, instead of replacing your member by the parameter of the method. Using a parameter with the same name than a member "hides" the member: you can't access it anymore, either at the left hand side or the right hand side of an assignment.
Issue 3
I'm not quite sure what you are doing with scrollArea->viewport() in the constructor of paint, but something tells me you are doing it wrong. The constructor of paint should NOT use it, but instead, you should do:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPainterPath linepath;
paintwiget = new paint(linepath); // Do NOT pass viewport in parameter
ui->scrollArea->setWidget(paintwiget);
paintwiget->show();
// ...
}
I am creating an animation with QGraphicsView, QGraphicsScene and QGraphicsItem. Can someone explain me when the paint function is called? Although I does not change variables of the item, the paint function is called every ≈100 ms. Can I stop that, so i can repaint the item when I want?
You are approaching it the wrong way. The item should be repainted only when needed - when you change how it looks or where it's located. That's when you call the QGraphicsItem::update(). The rest will be handled for you. It seems you're overcomplicating things.
Do note that you need to be determining the current time-dependent parameter of the animation within the paint() method, or "close" to it (say, right before update() is called), using actual time! If your animations are derived from QAbstractAnimation, it's already done for you. If they are not, then you'll have to use QElapsedTimer yourself.
The relevant Qt documentation says:
The animation framework calls updateCurrentTime() when current time has changed. By reimplementing this function, you can track the animation progress. Note that neither the interval between calls nor the number of calls to this function are defined; though, it will normally be 60 updates per second.
This means that Qt will do animations on a best-effort basis. The currentTime reported by the animation is the most recent time snapshot at the moment the animation was updated in the event loop. This is pretty much what you want.
The simplest way to deal with all this would be to use QVariantAnimation with QGraphicsObject. An example is below. Instead of rotating the object, you may have your own slot and modify it in some other way. You can also, instead of using signal-slot connection, have a customized QVariantAnimation that takes your custom QGraphicsItem-derived class as a target.
main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsObject>
#include <QPropertyAnimation>
#include <QGraphicsRectItem>
class EmptyGraphicsObject : public QGraphicsObject
{
public:
EmptyGraphicsObject() {}
QRectF boundingRect() const { return QRectF(0, 0, 0, 0); }
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
};
class View : public QGraphicsView
{
public:
View(QGraphicsScene *scene, QWidget *parent = 0) : QGraphicsView(scene, parent) {
setRenderHint(QPainter::Antialiasing);
}
void resizeEvent(QResizeEvent *) {
fitInView(-2, -2, 4, 4, Qt::KeepAspectRatio);
}
};
void setupScene(QGraphicsScene &s)
{
QGraphicsObject * obj = new EmptyGraphicsObject;
QGraphicsRectItem * rect = new QGraphicsRectItem(-1, 0.3, 2, 0.3, obj);
QPropertyAnimation * anim = new QPropertyAnimation(obj, "rotation", &s);
s.addItem(obj);
rect->setPen(QPen(Qt::darkBlue, 0.1));
anim->setDuration(2000);
anim->setStartValue(0);
anim->setEndValue(360);
anim->setEasingCurve(QEasingCurve::InBounce);
anim->setLoopCount(-1);
anim->start();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene s;
setupScene(s);
View v(&s);
v.show();
return a.exec();
}
You can set the viewportUpdateMode of the QGraphicsView to change how it updates. The options are: -
QGraphicsView::FullViewportUpdate
QGraphicsView::MinimalViewportUpdate
QGraphicsView::SmartViewportUpdate
QGraphicsView::BoundingRectViewportUpdate
QGraphicsView::NoViewportUpdate
The Qt docs explains what the different options do, but if you want full control, just set to QGraphicsView::NoViewportUpdate and control it yourself using a QTimer event.
The application I am writting as unique instantiation of some classes which have to be accessible easily. For that i use singletons.
For exemple my Core is defined as :
class Core : public QObject
{
Q_OBJECT
public:
Core();
~Core();
static Core& getCore()
{
static Core mycore;
return mycore;
}
(...)
};
and it works just great. However I tried to do the same with my MainWindow class, which interits from QMainWindow. I need that in order to access methods such as geometry() from other objects
However Core works great, MainWindow makes error when clossing the programe. The main window destructor is called and executed apparently once ( debug using qDebug() ) but i still have a SIGSEGV signal. What's happening? How to solve it?
Here is the code of MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow& getUi()
{
static MainWindow myUi;
return myUi;
}
public slots:
void refreshImage();
private:
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&appCore(), SIGNAL(refreshed()), this, SLOT(refreshImage()));
}
MainWindow::~MainWindow()
{
delete ui;
}
And the main code
QApplication app(argc, argv);
try
{
appCore().setDevice(MDMA::Kinect);
appUi().show();
return app.exec();
} catch(MDMA::exn e) {
(...)
}
where appCore and appUi are macros for Core::getCore and MainWindow::getUi()
This crash probably results from your QApplication being destroyed before the MainWindow.
If you cannot pass your MainWindow via other ways to the code where it is needed (e.g. as argument or via QObjecg::parent()), you could employ a technique similar to what QApplication does with it's instance method (a non-owning global reference):
Construct your MainWindow as an ordinary local variable on the stack, after the QApplication. Then set a global pointer (maybe better a QPointer; e.g. a static member of MainWindow), which you initially initialize to 0, to this in the constructor of MainWindow. You can also check if it was already initialized here to enforce the uniqueness. Via a public accessor method (instance?) for the global pointer, you can access the class from everywhere while ensuring destruction before QApplication.
If you want to make singletone, try to use general technics, for example, as described here:
http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern
Hope, lot of questions will dissappear after reading all of that article.
As for me, there is nice and simple realization of singletone.
Good luck!
I write my own class which subclass from QWidget
And this is my header file
#ifndef GRAPHMATRIX_H
#define GRAPHMATRIX_H
#include "treemodel.h"
#include <QWidget>
#include <Qt/qtableview.h>
class GraphMatrix : public QWidget
{
Q_OBJECT
public:
TreeModel& getModel();
GraphMatrix(QWidget* parent = 0);
void addTop(QString name);
void cutComponent(GraphMatrix* component, QVector<int> columns);
private:
TreeModel model;
QTableView* view;
public slots:
void changeValue(const QModelIndex& index);
};
#endif // GRAPHMATRIX_H
And I am getting this error
error C2248: 'QWidget::QWidget' : cannot access private member declared in class 'QWidget'
Can anyone help me?
Updated to add: I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem
It looks like you are trying to call the default constructor of QWidget which is private. Instead, your constructor needs to call the public constructor of QWidget as follows:
GraphMatrix::GraphMatrix(QWidget* parent) : QWidget(parent) {}
I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem